aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/2014_12_01_00_world.sql842
-rw-r--r--sql/updates/world/2014_12_01_01_world.sql277
-rw-r--r--sql/updates/world/2014_12_04_00_world.sql64
-rw-r--r--src/server/game/DataStores/DBCStores.cpp15
-rw-r--r--src/server/game/DataStores/DBCStores.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp551
-rw-r--r--src/server/game/Entities/Player/Player.h93
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp81
-rw-r--r--src/server/game/Globals/ObjectMgr.h2
-rw-r--r--src/server/game/Handlers/SkillHandler.cpp57
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp23
-rw-r--r--src/server/game/Server/Packets/SpellPackets.cpp11
-rw-r--r--src/server/game/Server/Packets/SpellPackets.h10
-rw-r--r--src/server/game/Server/Packets/TalentPackets.cpp14
-rw-r--r--src/server/game/Server/Packets/TalentPackets.h13
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp4
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h4
-rw-r--r--src/server/game/Server/WorldSession.h3
-rw-r--r--src/server/scripts/Commands/cs_learn.cpp4
20 files changed, 1017 insertions, 1055 deletions
diff --git a/sql/updates/world/2014_12_01_00_world.sql b/sql/updates/world/2014_12_01_00_world.sql
index fed2dbf6ade..6e96a1bfe9a 100644
--- a/sql/updates/world/2014_12_01_00_world.sql
+++ b/sql/updates/world/2014_12_01_00_world.sql
@@ -1,423 +1,423 @@
DELETE FROM `playercreateinfo_action`;
INSERT INTO `playercreateinfo_action` (`race`, `class`, `button`, `action`, `type`) VALUES
-('10', '10', '0', '100780', '0'),
-('10', '10', '9', '129597', '0'),
-('10', '10', '72', '100780', '0'),
-('10', '10', '81', '129597', '0'),
-('10', '8', '0', '44614', '0'),
-('10', '8', '9', '28730', '0'),
-('10', '9', '0', '686', '0'),
-('10', '9', '9', '28730', '0'),
-('10', '9', '10', '10', '48'),
-('10', '2', '0', '35395', '0'),
-('10', '2', '9', '155145', '0'),
-('10', '3', '0', '3044', '0'),
-('10', '3', '9', '80483', '0'),
-('10', '3', '10', '9', '48'),
-('10', '3', '11', '982', '0'),
-('10', '1', '0', '88163', '0'),
-('10', '1', '1', '78', '0'),
-('10', '1', '9', '69179', '0'),
-('10', '1', '72', '88163', '0'),
-('10', '1', '73', '78', '0'),
-('10', '1', '81', '69179', '0'),
-('10', '4', '0', '1752', '0'),
-('10', '4', '9', '25046', '0'),
-('10', '5', '0', '585', '0'),
-('10', '5', '9', '28730', '0'),
-('4', '6', '0', '6603', '0'),
-('4', '6', '1', '49576', '0'),
-('4', '6', '2', '45477', '0'),
-('4', '6', '3', '45462', '0'),
-('4', '6', '4', '50842', '0'),
-('4', '6', '5', '47541', '0'),
-('4', '6', '10', '58984', '0'),
-('4', '6', '83', '58984', '0'),
-('7', '6', '0', '6603', '0'),
-('7', '6', '1', '49576', '0'),
-('7', '6', '2', '45477', '0'),
-('7', '6', '3', '45462', '0'),
-('7', '6', '4', '50842', '0'),
-('7', '6', '5', '47541', '0'),
-('7', '6', '10', '20589', '0'),
-('7', '6', '72', '6603', '0'),
-('7', '6', '83', '117', '128'),
-('7', '6', '84', '6603', '0'),
-('7', '6', '96', '6603', '0'),
-('7', '6', '108', '6603', '0'),
-('3', '6', '0', '6603', '0'),
-('3', '6', '1', '49576', '0'),
-('3', '6', '2', '45477', '0'),
-('3', '6', '3', '45462', '0'),
-('3', '6', '4', '50842', '0'),
-('3', '6', '5', '47541', '0'),
-('1', '6', '0', '6603', '0'),
-('1', '6', '1', '49576', '0'),
-('1', '6', '2', '45477', '0'),
-('1', '6', '3', '45462', '0'),
-('1', '6', '4', '50842', '0'),
-('1', '6', '5', '47541', '0'),
-('1', '6', '11', '59752', '0'),
-('6', '6', '0', '6603', '0'),
-('6', '6', '1', '49576', '0'),
-('6', '6', '2', '45477', '0'),
-('6', '6', '3', '45462', '0'),
-('6', '6', '4', '50842', '0'),
-('6', '6', '5', '47541', '0'),
-('6', '6', '10', '20549', '0'),
-('6', '6', '75', '20549', '0'),
-('2', '6', '0', '6603', '0'),
-('2', '6', '1', '49576', '0'),
-('2', '6', '2', '45477', '0'),
-('2', '6', '3', '45462', '0'),
-('2', '6', '4', '50842', '0'),
-('2', '6', '5', '47541', '0'),
-('2', '6', '10', '20572', '0'),
-('22', '6', '0', '6603', '0'),
-('22', '6', '1', '49576', '0'),
-('22', '6', '2', '45477', '0'),
-('22', '6', '3', '45462', '0'),
-('22', '6', '4', '50842', '0'),
-('22', '6', '5', '47541', '0'),
-('22', '6', '9', '68992', '0'),
-('22', '6', '10', '68996', '0'),
-('22', '6', '11', '87840', '0'),
-('5', '6', '0', '6603', '0'),
-('5', '6', '1', '49576', '0'),
-('5', '6', '2', '45477', '0'),
-('5', '6', '3', '45462', '0'),
-('5', '6', '4', '50842', '0'),
-('5', '6', '5', '47541', '0'),
-('5', '6', '10', '20577', '0'),
-('10', '6', '0', '6603', '0'),
-('10', '6', '1', '49576', '0'),
-('10', '6', '2', '45477', '0'),
-('10', '6', '3', '45462', '0'),
-('10', '6', '4', '50842', '0'),
-('10', '6', '5', '47541', '0'),
-('10', '6', '6', '50613', '0'),
-('8', '6', '0', '6603', '0'),
-('8', '6', '1', '49576', '0'),
-('8', '6', '2', '45477', '0'),
-('8', '6', '3', '45462', '0'),
-('8', '6', '4', '50842', '0'),
-('8', '6', '5', '47541', '0'),
-('8', '6', '10', '26297', '0'),
-('9', '6', '0', '6603', '0'),
-('9', '6', '1', '49576', '0'),
-('9', '6', '2', '45477', '0'),
-('9', '6', '3', '45462', '0'),
-('9', '6', '4', '50842', '0'),
-('9', '6', '5', '47541', '0'),
-('9', '6', '9', '69070', '0'),
-('9', '6', '10', '69041', '0'),
-('9', '6', '11', '69046', '0'),
-('11', '6', '0', '6603', '0'),
-('11', '6', '1', '49576', '0'),
-('11', '6', '2', '45477', '0'),
-('11', '6', '3', '45462', '0'),
-('11', '6', '4', '50842', '0'),
-('11', '6', '5', '47541', '0'),
-('11', '6', '10', '59545', '0'),
-('11', '3', '0', '3044', '0'),
-('11', '3', '9', '59543', '0'),
-('11', '3', '10', '9', '48'),
-('11', '3', '11', '982', '0'),
-('11', '3', '72', '6603', '0'),
-('11', '3', '74', '75', '0'),
-('11', '3', '82', '159', '128'),
-('11', '3', '83', '4540', '128'),
-('11', '2', '0', '35395', '0'),
-('11', '2', '9', '59542', '0'),
-('11', '2', '83', '4540', '128'),
-('11', '1', '0', '88163', '0'),
-('11', '1', '1', '78', '0'),
-('11', '1', '9', '28880', '0'),
-('11', '1', '72', '88163', '0'),
-('11', '1', '73', '78', '0'),
-('11', '1', '81', '28880', '0'),
-('11', '5', '0', '585', '0'),
-('11', '5', '9', '59544', '0'),
-('11', '5', '83', '4540', '128'),
-('11', '7', '0', '403', '0'),
-('11', '7', '9', '59547', '0'),
-('11', '10', '0', '100780', '0'),
-('11', '10', '72', '100780', '0'),
-('11', '10', '81', '121093', '0'),
-('11', '8', '0', '44614', '0'),
-('11', '8', '9', '59548', '0'),
-('11', '8', '83', '4540', '128'),
-('3', '3', '0', '3044', '0'),
-('3', '3', '9', '20594', '0'),
-('3', '3', '10', '9', '48'),
-('3', '3', '11', '982', '0'),
-('3', '3', '75', '20594', '0'),
-('3', '2', '0', '35395', '0'),
-('3', '2', '9', '20594', '0'),
-('3', '1', '0', '88163', '0'),
-('3', '1', '1', '78', '0'),
-('3', '1', '9', '20594', '0'),
-('3', '1', '72', '88163', '0'),
-('3', '1', '73', '78', '0'),
-('3', '1', '81', '20594', '0'),
-('3', '7', '0', '403', '0'),
-('3', '7', '9', '20594', '0'),
-('3', '7', '72', '403', '0'),
-('3', '5', '0', '585', '0'),
-('3', '5', '9', '20594', '0'),
-('3', '4', '0', '1752', '0'),
-('3', '4', '9', '20594', '0'),
-('3', '10', '0', '100780', '0'),
-('3', '10', '72', '100780', '0'),
-('3', '10', '81', '20594', '0'),
-('3', '9', '0', '686', '0'),
-('3', '9', '9', '20594', '0'),
-('3', '9', '10', '10', '48'),
-('3', '8', '0', '44614', '0'),
-('3', '8', '9', '20594', '0'),
-('7', '5', '0', '585', '0'),
-('7', '4', '0', '1752', '0'),
-('7', '1', '0', '88163', '0'),
-('7', '1', '1', '78', '0'),
-('7', '1', '72', '88163', '0'),
-('7', '1', '73', '78', '0'),
-('7', '1', '81', '20589', '0'),
-('7', '10', '0', '100780', '0'),
-('7', '10', '72', '100780', '0'),
-('7', '10', '81', '20589', '0'),
-('7', '9', '0', '686', '0'),
-('7', '9', '10', '10', '48'),
-('7', '8', '0', '44614', '0'),
-('9', '9', '0', '686', '0'),
-('9', '9', '9', '69070', '0'),
-('9', '9', '10', '69041', '0'),
-('9', '9', '11', '10', '48'),
-('9', '8', '0', '44614', '0'),
-('9', '8', '9', '69070', '0'),
-('9', '8', '10', '69041', '0'),
-('9', '1', '0', '88163', '0'),
-('9', '1', '1', '78', '0'),
-('9', '1', '9', '69070', '0'),
-('9', '1', '10', '69041', '0'),
-('9', '1', '72', '88163', '0'),
-('9', '1', '73', '78', '0'),
-('9', '1', '81', '69070', '0'),
-('9', '1', '82', '69041', '0'),
-('9', '3', '0', '3044', '0'),
-('9', '3', '8', '982', '0'),
-('9', '3', '9', '69070', '0'),
-('9', '3', '10', '69041', '0'),
-('9', '3', '11', '9', '48'),
-('9', '5', '0', '585', '0'),
-('9', '5', '9', '69070', '0'),
-('9', '5', '10', '69041', '0'),
-('9', '4', '0', '1752', '0'),
-('9', '4', '9', '69070', '0'),
-('9', '4', '10', '69041', '0'),
-('9', '7', '0', '403', '0'),
-('9', '7', '9', '69070', '0'),
-('9', '7', '10', '69041', '0'),
-('9', '7', '72', '403', '0'),
-('1', '1', '0', '88163', '0'),
-('1', '1', '1', '78', '0'),
-('1', '1', '9', '59752', '0'),
-('1', '1', '72', '88163', '0'),
-('1', '1', '73', '78', '0'),
-('1', '1', '81', '59752', '0'),
-('1', '3', '0', '3044', '0'),
-('1', '3', '9', '59752', '0'),
-('1', '3', '10', '9', '48'),
-('1', '3', '11', '982', '0'),
-('1', '2', '0', '35395', '0'),
-('1', '2', '9', '59752', '0'),
-('1', '5', '0', '585', '0'),
-('1', '5', '9', '59752', '0'),
-('1', '4', '0', '1752', '0'),
-('1', '4', '9', '59752', '0'),
-('1', '9', '0', '686', '0'),
-('1', '9', '9', '59752', '0'),
-('1', '9', '10', '10', '48'),
-('1', '8', '0', '44614', '0'),
-('1', '8', '9', '59752', '0'),
-('1', '10', '0', '100780', '0'),
-('1', '10', '72', '100780', '0'),
-('1', '10', '81', '59752', '0'),
-('4', '4', '0', '1752', '0'),
-('4', '4', '4', '58984', '0'),
-('4', '4', '81', '58984', '0'),
-('4', '5', '0', '585', '0'),
-('4', '5', '9', '58984', '0'),
-('4', '5', '81', '58984', '0'),
-('4', '1', '0', '88163', '0'),
-('4', '1', '1', '78', '0'),
-('4', '1', '9', '58984', '0'),
-('4', '1', '72', '88163', '0'),
-('4', '1', '73', '78', '0'),
-('4', '1', '81', '58984', '0'),
-('4', '3', '0', '3044', '0'),
-('4', '3', '9', '58984', '0'),
-('4', '3', '10', '9', '48'),
-('4', '3', '11', '982', '0'),
-('4', '3', '81', '58984', '0'),
-('4', '8', '0', '44614', '0'),
-('4', '8', '9', '58984', '0'),
-('4', '10', '0', '100780', '0'),
-('4', '10', '72', '100780', '0'),
-('4', '10', '81', '58984', '0'),
-('4', '11', '0', '5176', '0'),
-('4', '11', '9', '58984', '0'),
-('4', '11', '72', '6603', '0'),
-('4', '11', '74', '58984', '0'),
-('4', '11', '84', '6603', '0'),
-('4', '11', '96', '6603', '0'),
-('4', '11', '108', '6603', '0'),
-('2', '3', '0', '3044', '0'),
-('2', '3', '9', '20572', '0'),
-('2', '3', '10', '9', '48'),
-('2', '3', '11', '982', '0'),
-('2', '1', '0', '88163', '0'),
-('2', '1', '1', '78', '0'),
-('2', '1', '9', '20572', '0'),
-('2', '1', '72', '88163', '0'),
-('2', '1', '73', '78', '0'),
-('2', '1', '81', '20572', '0'),
-('2', '7', '0', '403', '0'),
-('2', '7', '9', '33697', '0'),
-('2', '7', '72', '403', '0'),
-('2', '4', '0', '1752', '0'),
-('2', '4', '9', '20572', '0'),
-('2', '10', '0', '100780', '0'),
-('2', '10', '72', '100780', '0'),
-('2', '10', '81', '33697', '0'),
-('2', '8', '0', '44614', '0'),
-('2', '8', '9', '33702', '0'),
-('2', '9', '0', '686', '0'),
-('2', '9', '9', '33702', '0'),
-('2', '9', '10', '10', '48'),
-('24', '8', '0', '44614', '0'),
-('24', '8', '9', '107079', '0'),
-('24', '8', '11', '77264', '128'),
-('24', '10', '0', '100780', '0'),
-('24', '10', '72', '100780', '0'),
-('24', '10', '81', '107079', '0'),
-('24', '10', '83', '77272', '128'),
-('24', '1', '0', '88163', '0'),
-('24', '1', '1', '78', '0'),
-('24', '1', '9', '107079', '0'),
-('24', '1', '11', '77273', '128'),
-('24', '1', '72', '88163', '0'),
-('24', '1', '73', '78', '0'),
-('24', '1', '81', '107079', '0'),
-('24', '1', '83', '77273', '128'),
-('24', '3', '0', '3044', '0'),
-('24', '3', '7', '77272', '128'),
-('24', '3', '9', '107079', '0'),
-('24', '3', '10', '9', '48'),
-('24', '3', '11', '982', '0'),
-('24', '4', '0', '1752', '0'),
-('24', '4', '9', '107079', '0'),
-('24', '4', '11', '77272', '128'),
-('24', '5', '0', '585', '0'),
-('24', '5', '9', '107079', '0'),
-('24', '5', '11', '77264', '128'),
-('24', '7', '0', '403', '0'),
-('24', '7', '9', '107079', '0'),
-('24', '7', '11', '77272', '128'),
-('24', '7', '72', '403', '0'),
-('6', '7', '0', '403', '0'),
-('6', '7', '9', '20549', '0'),
-('6', '7', '75', '20549', '0'),
-('6', '5', '0', '585', '0'),
-('6', '5', '9', '20549', '0'),
-('6', '2', '0', '35395', '0'),
-('6', '2', '9', '20549', '0'),
-('6', '3', '0', '3044', '0'),
-('6', '3', '9', '20549', '0'),
-('6', '3', '10', '9', '48'),
-('6', '3', '11', '982', '0'),
-('6', '3', '75', '20549', '0'),
-('6', '1', '0', '88163', '0'),
-('6', '1', '1', '78', '0'),
-('6', '1', '9', '20549', '0'),
-('6', '1', '72', '88163', '0'),
-('6', '1', '73', '78', '0'),
-('6', '1', '81', '20549', '0'),
-('6', '10', '0', '100780', '0'),
-('6', '10', '72', '100780', '0'),
-('6', '10', '81', '20549', '0'),
-('6', '11', '0', '5176', '0'),
-('6', '11', '9', '20549', '0'),
-('6', '11', '72', '6603', '0'),
-('6', '11', '75', '20549', '0'),
-('6', '11', '84', '6603', '0'),
-('6', '11', '96', '6603', '0'),
-('6', '11', '108', '6603', '0'),
-('8', '8', '0', '44614', '0'),
-('8', '8', '9', '26297', '0'),
-('8', '9', '0', '686', '0'),
-('8', '9', '9', '26297', '0'),
-('8', '9', '10', '10', '48'),
-('8', '10', '0', '100780', '0'),
-('8', '10', '72', '100780', '0'),
-('8', '10', '81', '26297', '0'),
-('8', '11', '0', '5176', '0'),
-('8', '11', '9', '26297', '0'),
-('8', '11', '72', '6603', '0'),
-('8', '11', '84', '6603', '0'),
-('8', '11', '96', '6603', '0'),
-('8', '1', '0', '88163', '0'),
-('8', '1', '1', '78', '0'),
-('8', '1', '9', '26297', '0'),
-('8', '1', '72', '88163', '0'),
-('8', '1', '73', '78', '0'),
-('8', '1', '81', '26297', '0'),
-('8', '3', '0', '3044', '0'),
-('8', '3', '9', '26297', '0'),
-('8', '3', '10', '9', '48'),
-('8', '3', '11', '982', '0'),
-('8', '4', '0', '1752', '0'),
-('8', '4', '9', '26297', '0'),
-('8', '4', '76', '26297', '0'),
-('8', '5', '0', '585', '0'),
-('8', '5', '9', '26297', '0'),
-('8', '7', '0', '403', '0'),
-('8', '7', '9', '26297', '0'),
-('8', '7', '72', '403', '0'),
-('5', '5', '0', '585', '0'),
-('5', '5', '9', '20577', '0'),
-('5', '4', '0', '1752', '0'),
-('5', '4', '9', '20577', '0'),
-('5', '1', '0', '88163', '0'),
-('5', '1', '1', '78', '0'),
-('5', '1', '9', '20577', '0'),
-('5', '1', '72', '88163', '0'),
-('5', '1', '73', '78', '0'),
-('5', '1', '81', '20577', '0'),
-('5', '3', '0', '3044', '0'),
-('5', '3', '9', '20577', '0'),
-('5', '3', '10', '9', '48'),
-('5', '3', '11', '982', '0'),
-('5', '9', '0', '686', '0'),
-('5', '9', '9', '20577', '0'),
-('5', '9', '10', '10', '48'),
-('5', '8', '0', '44614', '0'),
-('5', '8', '9', '20577', '0'),
-('5', '10', '0', '100780', '0'),
-('5', '10', '72', '100780', '0'),
-('5', '10', '81', '20577', '0'),
-('22', '4', '0', '1752', '0'),
-('22', '5', '0', '585', '0'),
-('22', '3', '0', '3044', '0'),
-('22', '3', '10', '9', '48'),
-('22', '3', '11', '982', '0'),
-('22', '1', '0', '88163', '0'),
-('22', '1', '1', '78', '0'),
-('22', '1', '72', '88163', '0'),
-('22', '1', '73', '78', '0'),
-('22', '11', '0', '5176', '0'),
-('22', '11', '72', '6603', '0'),
-('22', '11', '84', '6603', '0'),
-('22', '11', '96', '6603', '0'),
-('22', '8', '0', '44614', '0'),
-('22', '9', '0', '686', '0'),
-('22', '9', '10', '10', '48');
+(10, 10, 0, 100780, 0),
+(10, 10, 9, 129597, 0),
+(10, 10, 72, 100780, 0),
+(10, 10, 81, 129597, 0),
+(10, 8, 0, 44614, 0),
+(10, 8, 9, 28730, 0),
+(10, 9, 0, 686, 0),
+(10, 9, 9, 28730, 0),
+(10, 9, 10, 10, 48),
+(10, 2, 0, 35395, 0),
+(10, 2, 9, 155145, 0),
+(10, 3, 0, 3044, 0),
+(10, 3, 9, 80483, 0),
+(10, 3, 10, 9, 48),
+(10, 3, 11, 982, 0),
+(10, 1, 0, 88163, 0),
+(10, 1, 1, 78, 0),
+(10, 1, 9, 69179, 0),
+(10, 1, 72, 88163, 0),
+(10, 1, 73, 78, 0),
+(10, 1, 81, 69179, 0),
+(10, 4, 0, 1752, 0),
+(10, 4, 9, 25046, 0),
+(10, 5, 0, 585, 0),
+(10, 5, 9, 28730, 0),
+(4, 6, 0, 6603, 0),
+(4, 6, 1, 49576, 0),
+(4, 6, 2, 45477, 0),
+(4, 6, 3, 45462, 0),
+(4, 6, 4, 50842, 0),
+(4, 6, 5, 47541, 0),
+(4, 6, 10, 58984, 0),
+(4, 6, 83, 58984, 0),
+(7, 6, 0, 6603, 0),
+(7, 6, 1, 49576, 0),
+(7, 6, 2, 45477, 0),
+(7, 6, 3, 45462, 0),
+(7, 6, 4, 50842, 0),
+(7, 6, 5, 47541, 0),
+(7, 6, 10, 20589, 0),
+(7, 6, 72, 6603, 0),
+(7, 6, 83, 117, 128),
+(7, 6, 84, 6603, 0),
+(7, 6, 96, 6603, 0),
+(7, 6, 108, 6603, 0),
+(3, 6, 0, 6603, 0),
+(3, 6, 1, 49576, 0),
+(3, 6, 2, 45477, 0),
+(3, 6, 3, 45462, 0),
+(3, 6, 4, 50842, 0),
+(3, 6, 5, 47541, 0),
+(1, 6, 0, 6603, 0),
+(1, 6, 1, 49576, 0),
+(1, 6, 2, 45477, 0),
+(1, 6, 3, 45462, 0),
+(1, 6, 4, 50842, 0),
+(1, 6, 5, 47541, 0),
+(1, 6, 11, 59752, 0),
+(6, 6, 0, 6603, 0),
+(6, 6, 1, 49576, 0),
+(6, 6, 2, 45477, 0),
+(6, 6, 3, 45462, 0),
+(6, 6, 4, 50842, 0),
+(6, 6, 5, 47541, 0),
+(6, 6, 10, 20549, 0),
+(6, 6, 75, 20549, 0),
+(2, 6, 0, 6603, 0),
+(2, 6, 1, 49576, 0),
+(2, 6, 2, 45477, 0),
+(2, 6, 3, 45462, 0),
+(2, 6, 4, 50842, 0),
+(2, 6, 5, 47541, 0),
+(2, 6, 10, 20572, 0),
+(22, 6, 0, 6603, 0),
+(22, 6, 1, 49576, 0),
+(22, 6, 2, 45477, 0),
+(22, 6, 3, 45462, 0),
+(22, 6, 4, 50842, 0),
+(22, 6, 5, 47541, 0),
+(22, 6, 9, 68992, 0),
+(22, 6, 10, 68996, 0),
+(22, 6, 11, 87840, 0),
+(5, 6, 0, 6603, 0),
+(5, 6, 1, 49576, 0),
+(5, 6, 2, 45477, 0),
+(5, 6, 3, 45462, 0),
+(5, 6, 4, 50842, 0),
+(5, 6, 5, 47541, 0),
+(5, 6, 10, 20577, 0),
+(10, 6, 0, 6603, 0),
+(10, 6, 1, 49576, 0),
+(10, 6, 2, 45477, 0),
+(10, 6, 3, 45462, 0),
+(10, 6, 4, 50842, 0),
+(10, 6, 5, 47541, 0),
+(10, 6, 6, 50613, 0),
+(8, 6, 0, 6603, 0),
+(8, 6, 1, 49576, 0),
+(8, 6, 2, 45477, 0),
+(8, 6, 3, 45462, 0),
+(8, 6, 4, 50842, 0),
+(8, 6, 5, 47541, 0),
+(8, 6, 10, 26297, 0),
+(9, 6, 0, 6603, 0),
+(9, 6, 1, 49576, 0),
+(9, 6, 2, 45477, 0),
+(9, 6, 3, 45462, 0),
+(9, 6, 4, 50842, 0),
+(9, 6, 5, 47541, 0),
+(9, 6, 9, 69070, 0),
+(9, 6, 10, 69041, 0),
+(9, 6, 11, 69046, 0),
+(11, 6, 0, 6603, 0),
+(11, 6, 1, 49576, 0),
+(11, 6, 2, 45477, 0),
+(11, 6, 3, 45462, 0),
+(11, 6, 4, 50842, 0),
+(11, 6, 5, 47541, 0),
+(11, 6, 10, 59545, 0),
+(11, 3, 0, 3044, 0),
+(11, 3, 9, 59543, 0),
+(11, 3, 10, 9, 48),
+(11, 3, 11, 982, 0),
+(11, 3, 72, 6603, 0),
+(11, 3, 74, 75, 0),
+(11, 3, 82, 159, 128),
+(11, 3, 83, 4540, 128),
+(11, 2, 0, 35395, 0),
+(11, 2, 9, 59542, 0),
+(11, 2, 83, 4540, 128),
+(11, 1, 0, 88163, 0),
+(11, 1, 1, 78, 0),
+(11, 1, 9, 28880, 0),
+(11, 1, 72, 88163, 0),
+(11, 1, 73, 78, 0),
+(11, 1, 81, 28880, 0),
+(11, 5, 0, 585, 0),
+(11, 5, 9, 59544, 0),
+(11, 5, 83, 4540, 128),
+(11, 7, 0, 403, 0),
+(11, 7, 9, 59547, 0),
+(11, 10, 0, 100780, 0),
+(11, 10, 72, 100780, 0),
+(11, 10, 81, 121093, 0),
+(11, 8, 0, 44614, 0),
+(11, 8, 9, 59548, 0),
+(11, 8, 83, 4540, 128),
+(3, 3, 0, 3044, 0),
+(3, 3, 9, 20594, 0),
+(3, 3, 10, 9, 48),
+(3, 3, 11, 982, 0),
+(3, 3, 75, 20594, 0),
+(3, 2, 0, 35395, 0),
+(3, 2, 9, 20594, 0),
+(3, 1, 0, 88163, 0),
+(3, 1, 1, 78, 0),
+(3, 1, 9, 20594, 0),
+(3, 1, 72, 88163, 0),
+(3, 1, 73, 78, 0),
+(3, 1, 81, 20594, 0),
+(3, 7, 0, 403, 0),
+(3, 7, 9, 20594, 0),
+(3, 7, 72, 403, 0),
+(3, 5, 0, 585, 0),
+(3, 5, 9, 20594, 0),
+(3, 4, 0, 1752, 0),
+(3, 4, 9, 20594, 0),
+(3, 10, 0, 100780, 0),
+(3, 10, 72, 100780, 0),
+(3, 10, 81, 20594, 0),
+(3, 9, 0, 686, 0),
+(3, 9, 9, 20594, 0),
+(3, 9, 10, 10, 48),
+(3, 8, 0, 44614, 0),
+(3, 8, 9, 20594, 0),
+(7, 5, 0, 585, 0),
+(7, 4, 0, 1752, 0),
+(7, 1, 0, 88163, 0),
+(7, 1, 1, 78, 0),
+(7, 1, 72, 88163, 0),
+(7, 1, 73, 78, 0),
+(7, 1, 81, 20589, 0),
+(7, 10, 0, 100780, 0),
+(7, 10, 72, 100780, 0),
+(7, 10, 81, 20589, 0),
+(7, 9, 0, 686, 0),
+(7, 9, 10, 10, 48),
+(7, 8, 0, 44614, 0),
+(9, 9, 0, 686, 0),
+(9, 9, 9, 69070, 0),
+(9, 9, 10, 69041, 0),
+(9, 9, 11, 10, 48),
+(9, 8, 0, 44614, 0),
+(9, 8, 9, 69070, 0),
+(9, 8, 10, 69041, 0),
+(9, 1, 0, 88163, 0),
+(9, 1, 1, 78, 0),
+(9, 1, 9, 69070, 0),
+(9, 1, 10, 69041, 0),
+(9, 1, 72, 88163, 0),
+(9, 1, 73, 78, 0),
+(9, 1, 81, 69070, 0),
+(9, 1, 82, 69041, 0),
+(9, 3, 0, 3044, 0),
+(9, 3, 8, 982, 0),
+(9, 3, 9, 69070, 0),
+(9, 3, 10, 69041, 0),
+(9, 3, 11, 9, 48),
+(9, 5, 0, 585, 0),
+(9, 5, 9, 69070, 0),
+(9, 5, 10, 69041, 0),
+(9, 4, 0, 1752, 0),
+(9, 4, 9, 69070, 0),
+(9, 4, 10, 69041, 0),
+(9, 7, 0, 403, 0),
+(9, 7, 9, 69070, 0),
+(9, 7, 10, 69041, 0),
+(9, 7, 72, 403, 0),
+(1, 1, 0, 88163, 0),
+(1, 1, 1, 78, 0),
+(1, 1, 9, 59752, 0),
+(1, 1, 72, 88163, 0),
+(1, 1, 73, 78, 0),
+(1, 1, 81, 59752, 0),
+(1, 3, 0, 3044, 0),
+(1, 3, 9, 59752, 0),
+(1, 3, 10, 9, 48),
+(1, 3, 11, 982, 0),
+(1, 2, 0, 35395, 0),
+(1, 2, 9, 59752, 0),
+(1, 5, 0, 585, 0),
+(1, 5, 9, 59752, 0),
+(1, 4, 0, 1752, 0),
+(1, 4, 9, 59752, 0),
+(1, 9, 0, 686, 0),
+(1, 9, 9, 59752, 0),
+(1, 9, 10, 10, 48),
+(1, 8, 0, 44614, 0),
+(1, 8, 9, 59752, 0),
+(1, 10, 0, 100780, 0),
+(1, 10, 72, 100780, 0),
+(1, 10, 81, 59752, 0),
+(4, 4, 0, 1752, 0),
+(4, 4, 4, 58984, 0),
+(4, 4, 81, 58984, 0),
+(4, 5, 0, 585, 0),
+(4, 5, 9, 58984, 0),
+(4, 5, 81, 58984, 0),
+(4, 1, 0, 88163, 0),
+(4, 1, 1, 78, 0),
+(4, 1, 9, 58984, 0),
+(4, 1, 72, 88163, 0),
+(4, 1, 73, 78, 0),
+(4, 1, 81, 58984, 0),
+(4, 3, 0, 3044, 0),
+(4, 3, 9, 58984, 0),
+(4, 3, 10, 9, 48),
+(4, 3, 11, 982, 0),
+(4, 3, 81, 58984, 0),
+(4, 8, 0, 44614, 0),
+(4, 8, 9, 58984, 0),
+(4, 10, 0, 100780, 0),
+(4, 10, 72, 100780, 0),
+(4, 10, 81, 58984, 0),
+(4, 11, 0, 5176, 0),
+(4, 11, 9, 58984, 0),
+(4, 11, 72, 6603, 0),
+(4, 11, 74, 58984, 0),
+(4, 11, 84, 6603, 0),
+(4, 11, 96, 6603, 0),
+(4, 11, 108, 6603, 0),
+(2, 3, 0, 3044, 0),
+(2, 3, 9, 20572, 0),
+(2, 3, 10, 9, 48),
+(2, 3, 11, 982, 0),
+(2, 1, 0, 88163, 0),
+(2, 1, 1, 78, 0),
+(2, 1, 9, 20572, 0),
+(2, 1, 72, 88163, 0),
+(2, 1, 73, 78, 0),
+(2, 1, 81, 20572, 0),
+(2, 7, 0, 403, 0),
+(2, 7, 9, 33697, 0),
+(2, 7, 72, 403, 0),
+(2, 4, 0, 1752, 0),
+(2, 4, 9, 20572, 0),
+(2, 10, 0, 100780, 0),
+(2, 10, 72, 100780, 0),
+(2, 10, 81, 33697, 0),
+(2, 8, 0, 44614, 0),
+(2, 8, 9, 33702, 0),
+(2, 9, 0, 686, 0),
+(2, 9, 9, 33702, 0),
+(2, 9, 10, 10, 48),
+(24, 8, 0, 44614, 0),
+(24, 8, 9, 107079, 0),
+(24, 8, 11, 77264, 128),
+(24, 10, 0, 100780, 0),
+(24, 10, 72, 100780, 0),
+(24, 10, 81, 107079, 0),
+(24, 10, 83, 77272, 128),
+(24, 1, 0, 88163, 0),
+(24, 1, 1, 78, 0),
+(24, 1, 9, 107079, 0),
+(24, 1, 11, 77273, 128),
+(24, 1, 72, 88163, 0),
+(24, 1, 73, 78, 0),
+(24, 1, 81, 107079, 0),
+(24, 1, 83, 77273, 128),
+(24, 3, 0, 3044, 0),
+(24, 3, 7, 77272, 128),
+(24, 3, 9, 107079, 0),
+(24, 3, 10, 9, 48),
+(24, 3, 11, 982, 0),
+(24, 4, 0, 1752, 0),
+(24, 4, 9, 107079, 0),
+(24, 4, 11, 77272, 128),
+(24, 5, 0, 585, 0),
+(24, 5, 9, 107079, 0),
+(24, 5, 11, 77264, 128),
+(24, 7, 0, 403, 0),
+(24, 7, 9, 107079, 0),
+(24, 7, 11, 77272, 128),
+(24, 7, 72, 403, 0),
+(6, 7, 0, 403, 0),
+(6, 7, 9, 20549, 0),
+(6, 7, 75, 20549, 0),
+(6, 5, 0, 585, 0),
+(6, 5, 9, 20549, 0),
+(6, 2, 0, 35395, 0),
+(6, 2, 9, 20549, 0),
+(6, 3, 0, 3044, 0),
+(6, 3, 9, 20549, 0),
+(6, 3, 10, 9, 48),
+(6, 3, 11, 982, 0),
+(6, 3, 75, 20549, 0),
+(6, 1, 0, 88163, 0),
+(6, 1, 1, 78, 0),
+(6, 1, 9, 20549, 0),
+(6, 1, 72, 88163, 0),
+(6, 1, 73, 78, 0),
+(6, 1, 81, 20549, 0),
+(6, 10, 0, 100780, 0),
+(6, 10, 72, 100780, 0),
+(6, 10, 81, 20549, 0),
+(6, 11, 0, 5176, 0),
+(6, 11, 9, 20549, 0),
+(6, 11, 72, 6603, 0),
+(6, 11, 75, 20549, 0),
+(6, 11, 84, 6603, 0),
+(6, 11, 96, 6603, 0),
+(6, 11, 108, 6603, 0),
+(8, 8, 0, 44614, 0),
+(8, 8, 9, 26297, 0),
+(8, 9, 0, 686, 0),
+(8, 9, 9, 26297, 0),
+(8, 9, 10, 10, 48),
+(8, 10, 0, 100780, 0),
+(8, 10, 72, 100780, 0),
+(8, 10, 81, 26297, 0),
+(8, 11, 0, 5176, 0),
+(8, 11, 9, 26297, 0),
+(8, 11, 72, 6603, 0),
+(8, 11, 84, 6603, 0),
+(8, 11, 96, 6603, 0),
+(8, 1, 0, 88163, 0),
+(8, 1, 1, 78, 0),
+(8, 1, 9, 26297, 0),
+(8, 1, 72, 88163, 0),
+(8, 1, 73, 78, 0),
+(8, 1, 81, 26297, 0),
+(8, 3, 0, 3044, 0),
+(8, 3, 9, 26297, 0),
+(8, 3, 10, 9, 48),
+(8, 3, 11, 982, 0),
+(8, 4, 0, 1752, 0),
+(8, 4, 9, 26297, 0),
+(8, 4, 76, 26297, 0),
+(8, 5, 0, 585, 0),
+(8, 5, 9, 26297, 0),
+(8, 7, 0, 403, 0),
+(8, 7, 9, 26297, 0),
+(8, 7, 72, 403, 0),
+(5, 5, 0, 585, 0),
+(5, 5, 9, 20577, 0),
+(5, 4, 0, 1752, 0),
+(5, 4, 9, 20577, 0),
+(5, 1, 0, 88163, 0),
+(5, 1, 1, 78, 0),
+(5, 1, 9, 20577, 0),
+(5, 1, 72, 88163, 0),
+(5, 1, 73, 78, 0),
+(5, 1, 81, 20577, 0),
+(5, 3, 0, 3044, 0),
+(5, 3, 9, 20577, 0),
+(5, 3, 10, 9, 48),
+(5, 3, 11, 982, 0),
+(5, 9, 0, 686, 0),
+(5, 9, 9, 20577, 0),
+(5, 9, 10, 10, 48),
+(5, 8, 0, 44614, 0),
+(5, 8, 9, 20577, 0),
+(5, 10, 0, 100780, 0),
+(5, 10, 72, 100780, 0),
+(5, 10, 81, 20577, 0),
+(22, 4, 0, 1752, 0),
+(22, 5, 0, 585, 0),
+(22, 3, 0, 3044, 0),
+(22, 3, 10, 9, 48),
+(22, 3, 11, 982, 0),
+(22, 1, 0, 88163, 0),
+(22, 1, 1, 78, 0),
+(22, 1, 72, 88163, 0),
+(22, 1, 73, 78, 0),
+(22, 11, 0, 5176, 0),
+(22, 11, 72, 6603, 0),
+(22, 11, 84, 6603, 0),
+(22, 11, 96, 6603, 0),
+(22, 8, 0, 44614, 0),
+(22, 9, 0, 686, 0),
+(22, 9, 10, 10, 48);
diff --git a/sql/updates/world/2014_12_01_01_world.sql b/sql/updates/world/2014_12_01_01_world.sql
deleted file mode 100644
index d9532d5881b..00000000000
--- a/sql/updates/world/2014_12_01_01_world.sql
+++ /dev/null
@@ -1,277 +0,0 @@
-DROP TABLE IF EXISTS `playercreateinfo_skills`;
-DROP TABLE IF EXISTS `playercreateinfo_spell`;
-
-CREATE TABLE `playercreateinfo_spell` (
- `racemask` int(10) unsigned NOT NULL DEFAULT '0',
- `classmask` int(10) unsigned NOT NULL DEFAULT '0',
- `Spell` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `Note` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`racemask`,`classmask`,`Spell`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-INSERT INTO `playercreateinfo_spell` (`racemask`, `classmask`, `Spell`, `Note`) VALUES
-('10487807', '943', '201', 'One-Handed Swords'),
-('10487807', '623', '196', 'One-Handed Axes'),
-('10487807', '1659', '198', 'One-Handed Maces'),
-('10487807', '2047', '522', 'SPELLDEFENSE (DND)'),
-('10487807', '2047', '204', 'Defense'),
-('10487807', '2047', '81', 'Dodge'),
-('946', '2047', '669', 'Language Orcish'),
-('10487807', '2005', '227', 'Staves'),
-('512', '959', '813', 'Language Thalassian'),
-('10487807', '2047', '203', 'Unarmed'),
-('10487807', '2047', '6478', 'Opening'),
-('10487807', '2047', '6603', 'Auto Attack'),
-('10487807', '2047', '45927', 'Summon Friend'),
-('10487807', '2047', '22027', 'Remove Insignia'),
-('10487807', '2047', '114585', 'Mastery'),
-('10487807', '2047', '2382', 'Generic'),
-('10487807', '2047', '21652', 'Closing'),
-('10487807', '2047', '8386', 'Attacking'),
-('10487807', '2047', '7266', 'Duel'),
-('10487807', '2047', '7267', 'Grovel'),
-('10487807', '2047', '7355', 'Stuck'),
-('10487807', '2047', '6233', 'Closing'),
-('10487807', '2047', '6247', 'Opening'),
-('10487807', '2047', '6477', 'Opening'),
-('10487807', '2047', '115043', 'Player Damage Reduction'),
-('10487807', '2047', '3050', 'Detect'),
-('10487807', '2047', '9125', 'Generic'),
-('10487807', '2047', '61437', 'Opening'),
-('10487807', '2047', '68398', 'Opening'),
-('10487807', '2047', '96220', 'Opening'),
-('8390399', '512', '106902', 'Weapon Skills'),
-('8390399', '512', '106904', 'Armor Skills'),
-('10487807', '2047', '3365', 'Opening'),
-('10487807', '2047', '21651', 'Opening'),
-('10487807', '2047', '6246', 'Closing'),
-('10487807', '2047', '132334', ''),
-('10487807', '2047', '22810', 'Opening - No Text'),
-('10487807', '2047', '134732', 'Battle Fatigue'),
-('10487807', '2047', '161691', 'Garrison Ability'),
-('10487807', '1575', '200', 'Polearms'),
-('10487807', '1647', '9077', 'Leather'),
-('10487807', '2047', '9078', 'Cloth'),
-('10487807', '1613', '15590', 'Fist Weapons'),
-('512', '959', '822', 'Arcane Resistance'),
-('512', '959', '28877', 'Arcane Affinity'),
-('512', '959', '79748', 'Languages'),
-('512', '512', '129597', 'Arcane Torrent'),
-('512', '959', '154742', 'Arcane Acuity'),
-('8390399', '512', '125670', 'Targeted Expulsion'),
-('8390399', '512', '116812', 'Parry'),
-('8390399', '512', '128678', 'Jab'),
-('8390399', '512', '107500', '<DND> Monk Energy Driver'),
-('8390399', '512', '108562', 'Monk Weapon Override Driver'),
-('8390399', '512', '108977', 'Way of the Monk'),
-('8390399', '512', '120275', 'Way of the Monk'),
-('8390399', '512', '115074', 'Fighting Style'),
-('8390399', '512', '100780', 'Jab'),
-('8390399', '512', '115612', 'Expel Harm Driver'),
-('8390399', '512', '119650', 'Energy Usage'),
-('8390399', '512', '120277', 'Way of the Monk'),
-('8390399', '512', '137022', 'Hotfix Passive'),
-('8390399', '512', '103985', 'Stance of the Fierce Tiger'),
-('10487807', '1501', '1180', 'Daggers'),
-('10487775', '128', '76276', 'Armor Skills'),
-('10487775', '128', '76298', 'Weapon Skills'),
-('10487807', '400', '5009', 'Wands'),
-('10487807', '400', '5019', 'Shoot'),
-('512', '400', '28730', 'Arcane Torrent'),
-('10487775', '128', '121039', 'Mana Attunement'),
-('10487775', '128', '44614', 'Frostfire Bolt'),
-('10487775', '128', '137018', 'Hotfix Passive'),
-('10487775', '384', '162699', 'Stat Negation Aura - Intellect DPS'),
-('2098135', '256', '76299', 'Weapon Skills'),
-('2098135', '256', '76277', 'Armor Skills'),
-('2098135', '256', '121688', ''),
-('2098135', '256', '688', 'Summon Imp'),
-('2098135', '256', '686', 'Shadow Bolt'),
-('2098135', '256', '114190', ''),
-('2098135', '256', '137042', 'Hotfix Passive'),
-('2098135', '256', '157903', 'Warlock'),
-('10487807', '39', '202', 'Two-Handed Swords'),
-('10487807', '67', '107', 'Block'),
-('10487807', '1123', '199', 'Two-Handed Maces'),
-('10487807', '103', '197', 'Two-Handed Axes'),
-('1573', '2', '76271', 'Armor Skills'),
-('1573', '2', '76294', 'Weapon Skills'),
-('10487807', '35', '119811', 'Mail'),
-('10487807', '67', '9116', 'Shield'),
-('512', '2', '155145', 'Arcane Torrent'),
-('1573', '2', '82242', 'Parry'),
-('1573', '2', '123830', 'Block'),
-('1573', '2', '35395', 'Crusader Strike'),
-('1573', '2', '137026', 'Hotfix Passive'),
-('10487807', '13', '264', 'Bows'),
-('10487807', '13', '266', 'Guns'),
-('10487807', '12', '674', 'Dual Wield'),
-('10487743', '4', '34082', 'Hunter Passive Auras (DND)'),
-('10487743', '4', '76249', 'Weapon Skills'),
-('10487743', '4', '76250', 'Armor Skills'),
-('10487743', '4', '75', 'Auto Shot'),
-('10487807', '13', '5011', 'Crossbows'),
-('512', '4', '80483', 'Arcane Torrent'),
-('10487743', '4', '77442', 'Focus'),
-('10487743', '4', '883', 'Call Pet 1'),
-('10487743', '4', '982', 'Revive Pet'),
-('10487743', '4', '137014', 'Hotfix Passive'),
-('10487743', '4', '157443', 'Critical Strikes'),
-('10487807', '12', '162697', 'Stat Negation Aura - Agility DPS'),
-('10487743', '4', '3044', 'Arcane Shot'),
-('10487807', '1', '5301', 'Revenge Trigger'),
-('10487807', '1', '32215', 'Victorious State'),
-('10487807', '1', '76268', 'Armor Skills'),
-('10487807', '1', '76290', 'Weapon Skills'),
-('512', '1', '69179', 'Arcane Torrent'),
-('10487807', '1', '3127', 'Parry'),
-('10487807', '1', '88163', 'Attack'),
-('10487807', '1', '2457', 'Battle Stance'),
-('10487807', '1', '123829', 'Block'),
-('10487807', '1', '128217', 'Pummel (shield visual override) (DND)'),
-('10487807', '1', '137047', 'Hotfix Passive'),
-('10487807', '1', '78', 'Heroic Strike'),
-('10486751', '8', '76297', 'Weapon Skills'),
-('10486751', '8', '76273', 'Armor Skills'),
-('512', '8', '25046', 'Arcane Torrent'),
-('10486751', '8', '1752', 'Sinister Strike'),
-('10486751', '8', '121733', 'Throw'),
-('10486751', '8', '82245', 'Parry'),
-('10486751', '8', '137034', 'Hotfix Passive'),
-('10486751', '8', '157442', 'Critical Strikes'),
-('10487805', '16', '76279', 'Armor Skills'),
-('10487805', '16', '76301', 'Weapon Skills'),
-('10487805', '16', '585', 'Smite'),
-('10487805', '16', '137030', 'Hotfix Passive'),
-('2098253', '2047', '668', 'Language Common'),
-('8', '1725', '671', 'Language Darnassian'),
-('8', '1725', '76252', 'Languages'),
-('8', '1725', '20582', 'Quickness'),
-('8', '1725', '20585', 'Wisp Spirit'),
-('8', '1725', '21009', 'Elusiveness'),
-('8', '1725', '58984', 'Shadowmeld'),
-('8', '1725', '20583', 'Nature Resistance'),
-('8', '1725', '154748', 'Touch of Elune'),
-('2099199', '32', '10846', 'First Aid'),
-('2099199', '32', '7928', 'Silk Bandage'),
-('2099199', '32', '7929', 'Heavy Silk Bandage'),
-('2099199', '32', '7934', 'Anti-Venom'),
-('2099199', '32', '3275', 'Linen Bandage'),
-('2099199', '32', '3276', 'Heavy Linen Bandage'),
-('2099199', '32', '3278', 'Heavy Wool Bandage'),
-('2099199', '32', '18629', 'Runecloth Bandage'),
-('2099199', '32', '10840', 'Mageweave Bandage'),
-('2099199', '32', '10841', 'Heavy Mageweave Bandage'),
-('2099199', '32', '18630', 'Heavy Runecloth Bandage'),
-('2099199', '32', '3277', 'Wool Bandage'),
-('2099199', '32', '76292', 'Weapon Skills'),
-('2099199', '32', '76282', 'Armor Skills'),
-('2099199', '32', '750', 'Plate Mail'),
-('2099199', '32', '33391', 'Journeyman Riding'),
-('2099199', '32', '86524', 'Plate Specialization'),
-('2099199', '32', '82246', 'Parry'),
-('2099199', '32', '47541', 'Death Coil'),
-('2099199', '32', '49576', 'Death Grip'),
-('2099199', '32', '48266', 'Frost Presence'),
-('2099199', '32', '45477', 'Icy Touch'),
-('2099199', '32', '50842', 'Blood Boil'),
-('2099199', '32', '45462', 'Plague Strike'),
-('2099199', '32', '137005', 'Hotfix Passive'),
-('2099199', '32', '89964', 'Vanishing Powder'),
-('2099199', '32', '58715', 'Shifting Presences'),
-('2099199', '32', '63644', 'Activating Secondary Spec'),
-('2099199', '32', '63645', 'Activating Primary Spec'),
-('2099199', '32', '127650', 'Remove Talent'),
-('64', '953', '7340', 'Language Gnomish'),
-('64', '953', '20589', 'Escape Artist'),
-('64', '953', '20593', 'Engineering Specialization'),
-('64', '953', '20592', 'Arcane Resistance'),
-('64', '953', '92680', 'Nimble Fingers'),
-('64', '953', '79740', 'Languages'),
-('64', '32', '154747', 'Expansive Mind'),
-('4', '1023', '20596', 'Frost Resistance'),
-('4', '1023', '20594', 'Stoneform'),
-('4', '1023', '59224', 'Might of the Mountain'),
-('4', '1023', '92682', 'Explorer'),
-('4', '1023', '79739', 'Languages'),
-('4', '1023', '672', 'Language Dwarven'),
-('1', '959', '20599', 'Diplomacy'),
-('1', '959', '20598', 'The Human Spirit'),
-('1', '959', '59752', 'Every Man for Himself'),
-('1', '959', '79738', 'Languages'),
-('32', '1655', '670', 'Language Taurahe'),
-('32', '1655', '20549', 'War Stomp'),
-('32', '1655', '20550', 'Endurance'),
-('32', '1655', '20551', 'Nature Resistance'),
-('32', '1655', '20552', 'Cultivation'),
-('32', '1655', '79746', 'Languages'),
-('32', '1655', '154743', 'Brawn'),
-('2', '1005', '21563', 'Command'),
-('2', '45', '20572', 'Blood Fury'),
-('2', '1005', '20573', 'Hardiness'),
-('2', '1005', '79743', 'Languages'),
-('2097152', '32', '94293', 'Altered Form'),
-('2097152', '32', '87840', 'Running Wild'),
-('2097152', '1469', '79742', 'Languages'),
-('2097152', '32', '68975', 'Viciousness'),
-('2097152', '32', '68978', 'Flayer'),
-('2097152', '32', '68992', 'Darkflight'),
-('2097152', '32', '68976', 'Aberration'),
-('2097152', '32', '68996', 'Two Forms'),
-('16', '957', '5227', 'Touch of the Grave'),
-('16', '957', '7744', 'Will of the Forsaken'),
-('16', '957', '20577', 'Cannibalize'),
-('16', '957', '20579', 'Shadow Resistance'),
-('16', '957', '79747', 'Languages'),
-('16', '957', '17737', 'Language Gutterspeak'),
-('512', '32', '50613', 'Arcane Torrent'),
-('128', '2045', '7341', 'Language Troll'),
-('128', '2045', '26297', 'Berserking'),
-('128', '2045', '58943', 'Da Voodoo Shuffle'),
-('128', '2045', '20555', 'Regeneration'),
-('128', '2045', '20557', 'Beast Slaying'),
-('128', '2045', '79744', 'Languages'),
-('256', '32', '69046', 'Pack Hobgoblin'),
-('256', '509', '79749', 'Languages'),
-('256', '509', '69070', 'Rocket Jump'),
-('256', '509', '69044', 'Best Deals Anywhere'),
-('256', '509', '69045', 'Better Living Through Chemistry'),
-('256', '509', '69041', 'Rocket Barrage'),
-('256', '509', '69042', 'Time is Money'),
-('256', '509', '69269', 'Language Goblin'),
-('1024', '759', '29932', 'Language Draenei'),
-('1024', '759', '6562', 'Heroic Presence'),
-('1024', '759', '28875', 'Gemcutting'),
-('1024', '759', '59221', 'Shadow Resistance'),
-('1024', '32', '59545', 'Gift of the Naaru'),
-('1024', '759', '79741', 'Languages'),
-('1024', '4', '59543', 'Gift of the Naaru'),
-('1024', '2', '59542', 'Gift of the Naaru'),
-('1024', '1', '28880', 'Gift of the Naaru'),
-('1024', '16', '59544', 'Gift of the Naaru'),
-('8390054', '64', '76296', 'Weapon Skills'),
-('8390054', '64', '76272', 'Armor Skills'),
-('1024', '64', '59547', 'Gift of the Naaru'),
-('8390054', '64', '403', 'Lightning Bolt'),
-('8390054', '64', '123831', 'Block'),
-('8390054', '64', '137038', 'Hotfix Passive'),
-('1024', '512', '121093', 'Gift of the Naaru'),
-('1024', '128', '59548', 'Gift of the Naaru'),
-('64', '912', '20591', 'Expansive Mind'),
-('64', '520', '154744', 'Expansive Mind'),
-('64', '1', '154746', 'Expansive Mind'),
-('2097320', '1024', '76275', 'Armor Skills'),
-('2097320', '1024', '76300', 'Weapon Skills'),
-('2097320', '1024', '5176', 'Wrath'),
-('2097320', '1024', '137009', 'Hotfix Passive'),
-('2097320', '1024', '159822', 'Shapemender'),
-('2', '576', '33697', 'Blood Fury'),
-('2', '384', '33702', 'Blood Fury'),
-('8388608', '733', '131701', 'Languages'),
-('8388608', '733', '107076', 'Bouncy'),
-('8388608', '733', '107074', 'Inner Peace'),
-('8388608', '733', '107073', 'Gourmand'),
-('8388608', '733', '107072', 'Epicurean'),
-('8388608', '733', '107079', 'Quaking Palm'),
-('8388608', '733', '108127', 'Language Pandaren Neutral'),
-('2097152', '1437', '69001', '');
diff --git a/sql/updates/world/2014_12_04_00_world.sql b/sql/updates/world/2014_12_04_00_world.sql
new file mode 100644
index 00000000000..5308b0f51d7
--- /dev/null
+++ b/sql/updates/world/2014_12_04_00_world.sql
@@ -0,0 +1,64 @@
+DROP TABLE IF EXISTS `playercreateinfo_spell`;
+DROP TABLE IF EXISTS `playercreateinfo_skills`;
+CREATE TABLE `playercreateinfo_skills` (
+ `raceMask` int(10) unsigned NOT NULL,
+ `classMask` int(10) unsigned NOT NULL,
+ `skill` smallint(5) unsigned NOT NULL,
+ `rank` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `comment` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`raceMask`,`classMask`,`skill`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+INSERT INTO `playercreateinfo_skills` (`raceMask`, `classMask`, `skill`, `rank`, `comment`) VALUES
+(0, 0, 95, 0, 'Defense'),
+(0, 0, 162, 0, 'Unarmed'),
+(0, 0, 183, 0, 'GENERIC (DND)'),
+(0, 0, 415, 0, 'Cloth'),
+(0, 0, 777, 0, 'Mounts'),
+(0, 0, 778, 0, 'Companion Pets'),
+(0, 0, 934, 0, 'All - Specializations'),
+(0, 3, 160, 0, 'Two-Handed Maces'),
+(0, 4, 45, 0, 'Bows'),
+(0, 4, 46, 0, 'Guns'),
+(0, 4, 226, 0, 'Crossbows'),
+(0, 8, 176, 0, 'Thrown'),
+(0, 32, 129, 4, 'Death Knight - First Aid'),
+(0, 32, 229, 0, 'Polearms'),
+(0, 32, 293, 0, 'Plate'),
+(0, 32, 762, 0, 'Death Knight - Riding'),
+(0, 35, 55, 0, 'Two-Handed Swords'),
+(0, 35, 413, 0, 'Mail'),
+(0, 37, 44, 0, 'Axes'),
+(0, 37, 172, 0, 'Two-Handed Axes'),
+(0, 39, 43, 0, 'Swords'),
+(0, 40, 118, 0, 'Dual Wield'),
+(0, 67, 433, 0, 'Shield'),
+(0, 400, 228, 0, 'Wands'),
+(0, 1107, 54, 0, 'Maces'),
+(0, 1135, 414, 0, 'Leather'),
+(0, 1293, 173, 0, 'Daggers'),
+(0, 1488, 136, 0, 'Staves'),
+(1, 0, 754, 0, 'Human - Racial'),
+(2, 0, 125, 0, 'Orc - Racial'),
+(4, 0, 101, 0, 'Dwarf - Racial'),
+(4, 0, 111, 0, 'Language: Dwarven'),
+(8, 0, 113, 0, 'Language: Darnassian'),
+(8, 0, 126, 0, 'Night Elf - Racial'),
+(16, 0, 220, 0, 'Undead - Racial'),
+(16, 0, 673, 0, 'Language: Forsaken'),
+(32, 0, 115, 0, 'Language: Taurahe'),
+(32, 0, 124, 0, 'Tauren - Racial'),
+(64, 0, 313, 0, 'Language: Gnomish'),
+(64, 0, 753, 0, 'Gnome - Racial'),
+(128, 0, 315, 0, 'Language: Troll'),
+(128, 0, 733, 0, 'Troll - Racial'),
+(256, 0, 790, 0, 'Racial - Goblin'),
+(256, 0, 792, 0, 'Language: Goblin'),
+(512, 0, 137, 0, 'Language: Thalassian'),
+(512, 0, 756, 0, 'Blood Elf - Racial'),
+(946, 0, 109, 0, 'Language: Orcish'),
+(1024, 0, 759, 0, 'Language: Draenei'),
+(1024, 0, 760, 0, 'Draenei - Racial'),
+(2097152, 0, 789, 0, 'Racial - Worgen'),
+(2097152, 0, 791, 0, 'Language: Worgen'),
+(2098253, 0, 98, 0, 'Language: Common');
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index cc85b56615b..f23dd49102b 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -518,7 +518,10 @@ void LoadDBCStores(const std::string& dataPath)
SpecializationSpellsEntry const* specSpells = sSpecializationSpellsStore.LookupEntry(i);
if (!specSpells)
continue;
- sSpecializationSpellsBySpecStore[specSpells->SpecID].insert(specSpells);
+ sSpecializationSpellsBySpecStore[specSpells->SpecID].push_back(specSpells);
+
+ if (specSpells->OverridesSpellID)
+ sSpecializationOverrideSpellMap[specSpells->SpecID][specSpells->OverridesSpellID] = specSpells->SpellID;
}
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc"/*, &CustomSpellEntryfmt, &CustomSpellEntryIndex*/);
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoriesStore, dbcPath, "SpellCategories.dbc");//15595
@@ -1256,16 +1259,16 @@ std::list<uint32> GetSpellsForLevels(uint32 classId, uint32 raceMask, uint32 spe
if (!specializationId)
return spellList;
- SpecializationSpellsMap::const_iterator specIter = sSpecializationSpellsMap.find(specializationId);
- if (specIter != sSpecializationSpellsMap.end())
+ SpecializationSpellsBySpecStore::const_iterator specIter = sSpecializationSpellsBySpecStore.find(specializationId);
+ if (specIter != sSpecializationSpellsBySpecStore.end())
{
- const std::vector<uint32>& learnSpellList = specIter->second;
+ SpecializationSpellsBySpecEntry learnSpellList = specIter->second;
for (int i = 0; i < learnSpellList.size(); i++)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learnSpellList[i]);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learnSpellList[i]->SpellID);
if (!spellInfo)
{
- TC_LOG_ERROR("spells", "GetSpellsForLevels: spell %u not found in spellstore", learnSpellList[i]);
+ TC_LOG_ERROR("spells", "GetSpellsForLevels: spell %u not found in spellstore", learnSpellList[i]->SpellID);
continue;
}
if (spellInfo->SpellLevel <= minLevel || spellInfo->SpellLevel > maxLevel)
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index a6ecadfaf45..633376d85aa 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -93,7 +93,7 @@ typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRac
typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds;
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
-typedef std::set<SpecializationSpellsEntry const*> SpecializationSpellsBySpecEntry;
+typedef std::vector<SpecializationSpellsEntry const*> SpecializationSpellsBySpecEntry;
typedef std::unordered_map<uint32, SpecializationSpellsBySpecEntry> SpecializationSpellsBySpecStore;
typedef ChrSpecializationEntry const* ChrSpecializationByIndexArray[MAX_CLASSES][MAX_SPECIALIZATIONS];
typedef std::unordered_map<uint32, TalentEntry const*> TalentBySpellIDMap;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index d18f8542f16..740c96753ab 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1122,7 +1122,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
}
// original spells
- LearnDefaultSpells();
+ LearnDefaultSkills();
LearnCustomSpells();
// original action bar
@@ -2985,11 +2985,39 @@ void Player::GiveLevel(uint8 level)
SetByteFlag(PLAYER_FIELD_BYTES, 1, 0x01);
}
+ std::list<uint32> learnList = GetSpellsForLevels(getClass(), getRaceMask(), GetTalentSpec(GetActiveTalentGroup()), oldLevel, level);
+ for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++)
+ {
+ if (!HasSpell(*iter))
+ LearnSpell(*iter, true);
+ }
+
sScriptMgr->OnPlayerLevelChanged(this, oldLevel);
}
void Player::InitTalentForLevel()
{
+ uint8 level = getLevel();
+ // talents base at level diff (talents = level - 9 but some can be used already)
+ if (level < 15)
+ {
+ // Remove all talent points
+ if (GetUsedTalentCount() > 0) // Free any used talents
+ {
+ ResetTalents(true);
+ }
+ }
+ else
+ {
+ if (level < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL) || GetTalentGroupsCount() == 0)
+ {
+ SetTalentGroupsCount(1);
+ SetActiveTalentGroup(0);
+ }
+ }
+
+ SetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS, CalculateTalentsPoints());
+
if (!GetSession()->PlayerLoading())
SendTalentsInfoData(); // update at client
}
@@ -3267,7 +3295,7 @@ void DeleteSpellFromAllPlayers(uint32 spellId)
}
}
-bool Player::AddTalent(uint32 talentId, uint8 spec)
+bool Player::AddTalent(uint32 talentId, uint8 spec, bool learning)
{
TalentEntry const* talentEntry = sTalentStore.LookupEntry(talentId);
@@ -3309,15 +3337,28 @@ bool Player::AddTalent(uint32 talentId, uint8 spec)
return false;
}
- TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(spec);
+ PlayerTalentMap::iterator itr = GetTalentMap(spec)->find(talentId);
+ if (itr == GetTalentMap(spec)->end())
+ {
+ //if (GetTalentBySpellID(talentEntry->SpellID))
+ {
+ PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
+ PlayerTalent* newtalent = new PlayerTalent();
- // Check if player already has this talent
- if (talentGroupInfo->HasTalent(talentId))
- return false;
+ newtalent->state = state;
+ newtalent->spec = spec;
- talentGroupInfo->Talents[talentEntry->TierID] = talentId;
+ (*GetTalentMap(spec))[talentId] = newtalent;
- return true;
+ return true;
+ }
+ //else
+ // TC_LOG_ERROR("spells", "Player::addTalent: Talent %u not found in talent store.", talentId);
+ }
+ else
+ itr->second->state = PLAYERSPELL_UNCHANGED;
+
+ return false;
}
bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, bool fromSkill /*= false*/)
@@ -3421,9 +3462,9 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
SendSupercededSpell(spellId, next_active_spell_id);
else
{
- WorldPacket data(SMSG_REMOVED_SPELL, 4);
- data << uint32(spellId);
- GetSession()->SendPacket(&data);
+ WorldPackets::Spells::SendRemovedSpell removedSpells;
+ removedSpells.Spells.push_back(spellId);
+ GetSession()->SendPacket(removedSpells.Write());
}
}
@@ -3594,11 +3635,15 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
if (HasSkill(pSkill->ID))
continue;
+ SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pSkill->ID, getRace(), getClass());
+ if (!rcEntry)
+ continue;
+
if (_spell_idx->second->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN ||
// lockpicking/runeforging special case, not have SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN
((pSkill->ID == SKILL_LOCKPICKING || pSkill->ID == SKILL_RUNEFORGING) && (_spell_idx->second->TrivialSkillLineRankHigh == 0 || _spell_idx->second->TrivialSkillLineRankHigh == 1)))
{
- switch (GetSkillRangeType(pSkill, _spell_idx->second->RaceMask!= 0))
+ switch (GetSkillRangeType(rcEntry))
{
case SKILL_RANGE_LANGUAGE:
SetSkill(pSkill->ID, GetSkillStep(pSkill->ID), 300, 300);
@@ -3690,6 +3735,7 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const
{
+
if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
return spellInfo->Id == chrSpec->MasterySpellID[0] || spellInfo->Id == chrSpec->MasterySpellID[1];
@@ -3893,9 +3939,9 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
// remove from spell book if not replaced by lesser rank
if (!prev_activate)
{
- WorldPacket data(SMSG_REMOVED_SPELL, 4);
- data << uint32(spell_id);
- GetSession()->SendPacket(&data);
+ WorldPackets::Spells::SendRemovedSpell removedSpells;
+ removedSpells.Spells.push_back(spell_id);
+ GetSession()->SendPacket(removedSpells.Write());
}
}
@@ -4080,17 +4126,20 @@ uint32 Player::GetNextResetTalentsCost() const
}
}
-bool Player::ResetTalents(bool no_cost)
+bool Player::ResetTalents(bool noCost, bool resetTalents, bool resetSpecialization)
{
- sScriptMgr->OnPlayerTalentsReset(this, no_cost);
+ if (!resetTalents && !resetSpecialization)
+ return false;
+ sScriptMgr->OnPlayerTalentsReset(this, noCost);
+
// not need after this call
if (HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
RemoveAtLoginFlag(AT_LOGIN_RESET_TALENTS, true);
uint32 cost = 0;
- if (!no_cost && !sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST))
+ if (!noCost && !sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST))
{
cost = GetNextResetTalentsCost();
@@ -4103,66 +4152,54 @@ bool Player::ResetTalents(bool no_cost)
RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
- uint8 group = GetActiveTalentGroup();
- uint32 specID = GetActiveTalentSpec();
-
- for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
+ if (resetTalents)
{
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
+ for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
+ {
+ TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
- if (!talentInfo)
- continue;
+ if (!talentInfo)
+ continue;
- // unlearn only talents for character class
- // some spell learned by one class as normal spells or know at creation but another class learn it as talent,
- // to prevent unexpected lost normal learned spell skip another class talents
- if (getClass() != talentInfo->ClassID)
- continue;
+ // unlearn only talents for character class
+ // some spell learned by one class as normal spells or know at creation but another class learn it as talent,
+ // to prevent unexpected lost normal learned spell skip another class talents
+ if (talentInfo->ClassID != getClass())
+ continue;
- const SpellInfo* _spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
+ SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
+ if (!spellEntry)
+ continue;
- if (!_spellEntry)
- continue;
+ RemoveSpell(spellEntry->Id, false);
- RemoveSpell(talentInfo->SpellID, true);
+ // search for spells that the talent teaches and unlearn them, 6.x remove?
+ for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
+ RemoveSpell(effect->TriggerSpell, true);
- // search for spells that the talent teaches and unlearn them
- for (SpellEffectInfo const* effect : _spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE))
- if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
- RemoveSpell(effect->TriggerSpell, true);
+ GetTalentMap(GetActiveTalentGroup())->erase(talentId);
+ }
}
- // Remove all specialization specific spells and give default ones which were overriden
- auto specSpells = sSpecializationSpellsBySpecStore.find(specID);
- if (specSpells != sSpecializationSpellsBySpecStore.end())
+ if (resetSpecialization)
{
- for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it)
+ std::list<uint32> learnList = GetSpellsForLevels(0, getRaceMask(), GetTalentSpec(GetActiveTalentGroup()), 0, getLevel());
+ for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++)
{
- SpecializationSpellsEntry const* specSpell = *it;
- if (HasSpell(specSpell->SpellID)) {
- RemoveSpell(specSpell->SpellID, true);
- if (specSpell->OverridesSpellID)
- LearnSpell(specSpell->OverridesSpellID, false);
- }
+ if (HasSpell(*iter))
+ RemoveSpell(*iter, true);
}
+ SetTalentSpec(GetActiveTalentGroup(), 0);
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0);
}
- // Unlearn masteries
- if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(specID))
- for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
- if (uint32 mastery = chrSpec->MasterySpellID[i])
- RemoveAurasDueToSpell(mastery);
-
- // Reset talents store
- GetTalentGroupInfo(group)->Reset();
- SetTalentSpec(group, 0);
-
SQLTransaction trans = CharacterDatabase.BeginTransaction();
_SaveTalents(trans);
_SaveSpells(trans);
CharacterDatabase.CommitTransaction(trans);
- if (!no_cost)
+ if (!noCost)
{
ModifyMoney(-(int64)cost);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS, cost);
@@ -4183,6 +4220,35 @@ bool Player::ResetTalents(bool no_cost)
return true;
}
+bool Player::RemoveTalent(uint32 talentId)
+{
+ TalentEntry const* talent = sTalentStore.LookupEntry(talentId);
+ if (!talent)
+ return false;
+
+ uint32 spellId = talent->SpellID;
+
+ SpellInfo const* unlearnSpellProto = sSpellMgr->GetSpellInfo(spellId);
+
+ RemoveSpell(spellId, false);
+
+ // 6.x remove?
+ for (SpellEffectInfo const* effect : unlearnSpellProto->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
+ RemoveSpell(effect->TriggerSpell, false);
+
+ GetTalentMap(GetActiveTalentSpec())->erase(talentId);
+
+ // Needs to be executed orthewise the talents will be screwedsx
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+ _SaveTalents(trans);
+ _SaveSpells(trans);
+ CharacterDatabase.CommitTransaction(trans);
+
+ SendTalentsInfoData();
+ return true;
+}
+
Mail* Player::GetMail(uint32 id)
{
for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
@@ -4249,7 +4315,8 @@ bool Player::HasSpell(uint32 spell) const
bool Player::HasTalent(uint32 talentId, uint8 group)
{
- return GetTalentGroupInfo(group)->HasTalent(talentId);
+ PlayerTalentMap::const_iterator itr = GetTalentMap(group)->find(talentId);
+ return (itr != GetTalentMap(group)->end());
}
bool Player::HasActiveSpell(uint32 spell) const
@@ -5892,14 +5959,14 @@ void Player::UpdateSkillsForLevel()
continue;
uint32 pskill = itr->first;
- SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(pskill);
- if (!pSkill)
+ SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pskill, getRace(), getClass());
+ if (!rcEntry)
continue;
- if (GetSkillRangeType(pSkill, false) != SKILL_RANGE_LEVEL)
+ if (GetSkillRangeType(rcEntry) != SKILL_RANGE_LEVEL)
continue;
- if (IsWeaponSkill(pSkill->ID))
+ if (IsWeaponSkill(rcEntry->SkillID))
continue;
uint16 field = itr->second.pos / 2;
@@ -17415,11 +17482,16 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
break;
uint32 talentSpec = atoul(talentSpecs[i]);
- if (sChrSpecializationStore.LookupEntry(talentSpec))
- SetTalentSpec(i, talentSpec);
- else
- SetAtLoginFlag(AT_LOGIN_RESET_TALENTS);
+ if (talentSpec)
+ {
+ if (sChrSpecializationStore.LookupEntry(talentSpec))
+ SetTalentSpec(i, talentSpec);
+ else
+ SetAtLoginFlag(AT_LOGIN_RESET_TALENTS);
+ }
}
+
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, GetActiveTalentSpec());
_LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS));
_LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS));
@@ -17442,7 +17514,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
// after spell and quest load
InitTalentForLevel();
- LearnDefaultSpells();
+ LearnDefaultSkills();
LearnCustomSpells();
// must be before inventory (some items required reputation check)
@@ -18486,6 +18558,13 @@ void Player::_LoadSpells(PreparedQueryResult result)
AddSpell((*result)[0].GetUInt32(), (*result)[1].GetBool(), false, false, (*result)[2].GetBool(), true);
while (result->NextRow());
}
+
+ std::list<uint32> learnList = GetSpellsForLevels(getClass(), getRaceMask(), GetActiveTalentSpec(), 0, getLevel());
+ for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++)
+ {
+ if (!HasSpell(*iter))
+ LearnSpell(*iter, true);
+ }
}
void Player::_LoadGroup(PreparedQueryResult result)
@@ -23243,8 +23322,8 @@ void Player::ResetSpells(bool myClassOnly)
else
for (PlayerSpellMap::const_iterator iter = smap.begin(); iter != smap.end(); ++iter)
RemoveSpell(iter->first, false, false); // only iter->first can be accessed, object by iter->second can be deleted already
-
- LearnDefaultSpells();
+
+ LearnDefaultSkills();
LearnCustomSpells();
LearnQuestRewardedSpells();
}
@@ -23267,21 +23346,72 @@ void Player::LearnCustomSpells()
}
}
-void Player::LearnDefaultSpells()
+void Player::LearnDefaultSkills()
{
- // learn default race/class spells
+ // learn default race/class skills
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass());
- for (PlayerCreateInfoSpells::const_iterator itr = info->spells.begin(); itr != info->spells.end(); ++itr)
+ for (PlayerCreateInfoSkills::const_iterator itr = info->skills.begin(); itr != info->skills.end(); ++itr)
{
- uint32 tspell = *itr;
- TC_LOG_DEBUG("entities.player.loading", "PLAYER (Class: %u Race: %u): Adding initial spell, id = %u", uint32(getClass()), uint32(getRace()), tspell);
- if (!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add
- AddSpell(tspell, true, true, true, false);
- else // but send in normal spell in game learn case
- LearnSpell(tspell, true);
+ uint32 skillId = itr->SkillId;
+ if (HasSkill(skillId))
+ continue;
+
+ LearnDefaultSkill(skillId, itr->Rank);
+ }
+}
+
+void Player::LearnDefaultSkill(uint32 skillId, uint16 rank)
+{
+ SkillRaceClassInfoEntry const* rcInfo = GetSkillRaceClassInfo(skillId, getRace(), getClass());
+ if (!rcInfo)
+ return;
+
+ switch (GetSkillRangeType(rcInfo))
+ {
+ case SKILL_RANGE_LANGUAGE:
+ SetSkill(skillId, 0, 300, 300);
+ break;
+ case SKILL_RANGE_LEVEL:
+ {
+ uint16 skillValue = 1;
+ uint16 maxValue = GetMaxSkillValueForLevel();
+ if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE)
+ skillValue = maxValue;
+ else if (getClass() == CLASS_DEATH_KNIGHT)
+ skillValue = std::min(std::max<uint16>({ 1, uint16((getLevel() - 1) * 5) }), maxValue);
+ else if (skillId == SKILL_FIST_WEAPONS)
+ skillValue = std::max<uint16>(1, GetSkillValue(SKILL_UNARMED));
+ else if (skillId == SKILL_LOCKPICKING)
+ skillValue = std::max<uint16>(1, GetSkillValue(SKILL_LOCKPICKING));
+
+ SetSkill(skillId, 0, skillValue, maxValue);
+ break;
+ }
+ case SKILL_RANGE_MONO:
+ SetSkill(skillId, 0, 1, 1);
+ break;
+ case SKILL_RANGE_RANK:
+ {
+ if (!rank)
+ break;
+
+ SkillTiersEntry const* tier = sSkillTiersStore.LookupEntry(rcInfo->SkillTierID);
+ uint16 maxValue = tier->Value[std::max<int32>(rank - 1, 0)];
+ uint16 skillValue = 1;
+ if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE)
+ skillValue = maxValue;
+ else if (getClass() == CLASS_DEATH_KNIGHT)
+ skillValue = std::min(std::max<uint16>({ uint16(1), uint16((getLevel() - 1) * 5) }), maxValue);
+
+ SetSkill(skillId, rank, skillValue, maxValue);
+ break;
+ }
+ default:
+ break;
}
}
+
void Player::LearnQuestRewardedSpells(Quest const* quest)
{
int32 spell_id = quest->GetRewSpellCast();
@@ -23396,31 +23526,41 @@ void Player::LearnQuestRewardedSpells()
void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue)
{
- uint32 raceMask = getRaceMask();
+ uint32 raceMask = getRaceMask();
uint32 classMask = getClassMask();
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
{
- SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j);
- if (!pAbility || pAbility->SkillLine != skillId || pAbility->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE)
+ SkillLineAbilityEntry const* ability = sSkillLineAbilityStore.LookupEntry(j);
+ if (!ability || ability->SkillLine != skillId)
+ continue;
+
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ability->SpellID);
+ if (!spellInfo)
+ continue;
+
+ if (ability->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE && ability->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN)
continue;
+
// Check race if set
- if (pAbility->RaceMask && !(pAbility->RaceMask & raceMask))
+ if (ability->RaceMask && !(ability->RaceMask & raceMask))
continue;
+
// Check class if set
- if (pAbility->ClassMask && !(pAbility->ClassMask & classMask))
+ if (ability->ClassMask && !(ability->ClassMask & classMask))
continue;
- if (sSpellMgr->GetSpellInfo(pAbility->SpellID))
- {
- // need unlearn spell
- if (skillValue < pAbility->MinSkillLineRank)
- RemoveSpell(pAbility->SpellID);
- // need learn
- else if (!IsInWorld())
- AddSpell(pAbility->SpellID, true, true, true, false);
- else
- LearnSpell(pAbility->SpellID, true);
- }
+ // check level, skip class spells if not high enough
+ if (getLevel() < spellInfo->SpellLevel)
+ continue;
+
+ // need unlearn spell
+ if (skillValue < ability->MinSkillLineRank && ability->AquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE)
+ RemoveSpell(ability->SpellID);
+ // need learn
+ else if (!IsInWorld())
+ AddSpell(ability->SpellID, true, true, true, false, false, true);
+ else
+ LearnSpell(ability->SpellID, true, true);
}
}
@@ -25135,8 +25275,8 @@ void Player::_LoadSkills(PreparedQueryResult result)
uint16 value = fields[1].GetUInt16();
uint16 max = fields[2].GetUInt16();
- SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skill);
- if (!skillLine)
+ SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass());
+ if (!rcEntry)
{
TC_LOG_ERROR("entities.player", "Character: %s (%s Race: %u Class: %u) has skill %u not allowed for his race/class combination",
GetName().c_str(), GetGUID().ToString().c_str(), uint32(getRace()), uint32(getClass()), skill);
@@ -25146,7 +25286,7 @@ void Player::_LoadSkills(PreparedQueryResult result)
}
// set fixed skill ranges
- switch (GetSkillRangeType(skillLine, false))
+ switch (GetSkillRangeType(rcEntry))
{
case SKILL_RANGE_LANGUAGE: // 300..300
value = max = 300;
@@ -25180,15 +25320,19 @@ void Player::_LoadSkills(PreparedQueryResult result)
SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_ID_OFFSET + field, offset, skill);
uint16 step = 0;
- if (skillLine->CategoryID == SKILL_CATEGORY_SECONDARY)
- step = max / 75;
-
- if (skillLine->CategoryID == SKILL_CATEGORY_PROFESSION)
+ SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(rcEntry->SkillID);
+ if (skillLine)
{
- step = max / 75;
+ if (skillLine->CategoryID == SKILL_CATEGORY_SECONDARY)
+ step = max / 75;
+
+ if (skillLine->CategoryID == SKILL_CATEGORY_PROFESSION)
+ {
+ step = max / 75;
- if (professionCount < 2)
- SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + professionCount++, skill);
+ if (professionCount < 2)
+ SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + professionCount++, skill);
+ }
}
SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_STEP_OFFSET + field, offset, step);
@@ -25407,37 +25551,36 @@ void Player::CompletedAchievement(AchievementEntry const* entry)
bool Player::LearnTalent(uint32 talentId)
{
- uint8 group = GetActiveTalentGroup();
-
- // check if talent specialization is learnt
- if (!GetTalentSpec(group))
- return false;
-
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
if (!talentInfo)
return false;
+
+ uint32 maxTalentTier = GetUInt32Value(PLAYER_FIELD_MAX_TALENT_TIERS);
// prevent learn talent for different class (cheating)
- if (getClass() != talentInfo->ClassID)
+ if (talentInfo->ClassID != getClass())
return false;
- // Check player level
- // TODO: fix level requirements for deathknights
- uint8 levelReq = std::min(15*talentInfo->TierID + 15, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL));
- if (getLevel() < levelReq)
+ // check if we have enough talent points
+ if (talentInfo->TierID > maxTalentTier)
return false;
- // Check if such tier talent hasn't been picked already
- TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(group);
- if (talentGroupInfo->Talents[talentInfo->TierID])
- return false;
+ // Check if player doesnt have any spell in selected collumn
+ for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++)
+ {
+ if (TalentEntry const* talent = sTalentStore.LookupEntry(i))
+ {
+ if (talentInfo->TierID == talent->TierID && HasSpell(talent->SpellID))
+ return false;
+ }
+ }
// spell not set in talent.dbc
uint32 spellid = talentInfo->SpellID;
if (spellid == 0)
{
- TC_LOG_ERROR("entities.player", "Talent.dbc have for talent: %u spell id = 0", talentId);
+ TC_LOG_ERROR("entities.player", "Talent.dbc has no spellInfo for talent: %u (spell id = 0)", talentId);
return false;
}
@@ -25445,54 +25588,39 @@ bool Player::LearnTalent(uint32 talentId)
if (HasSpell(spellid))
return false;
- // Check talent spec
- if (talentInfo->SpecID != GetTalentSpec(group))
+ if (!AddTalent(talentId, GetActiveTalentGroup(), true))
return false;
- // learn! (other talent ranks will unlearned at learning)
LearnSpell(spellid, false);
- AddTalent(talentId, group);
- TC_LOG_INFO("misc", "TalentID: %u Spell: %u Group: %u\n", talentId, spellid, group);
+ TC_LOG_INFO("misc", "TalentID: %u Spell: %u Group: %u\n", talentId, spellid, GetActiveTalentGroup());
return true;
}
void Player::LearnTalentSpecialization(uint32 talentSpec)
{
- SetTalentSpec(GetActiveTalentGroup(), talentSpec);
-
- // Replace default spells by specialization spells
- auto specSpells = sSpecializationSpellsBySpecStore.find(talentSpec);
- if (specSpells != sSpecializationSpellsBySpecStore.end())
- {
- for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it)
- {
- SpecializationSpellsEntry const* specSpell = *it;
+ if (GetActiveTalentSpec())
+ return;
- // Unlearn spell if it is replaced by new specialization
- if (specSpell->OverridesSpellID)
- RemoveSpell(specSpell->OverridesSpellID, true);
+ SetTalentSpec(GetActiveTalentGroup(), talentSpec);
- // Learn new spell
- if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID))
- if (spellInfo->BaseLevel <= getLevel())
- LearnSpell(specSpell->SpellID, false);
- }
- }
+ SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, talentSpec);
+ SendTalentsInfoData();
- if (CanUseMastery())
+ std::list<uint32> learnList = GetSpellsForLevels(0, getRaceMask(), GetActiveTalentSpec(), 0, getLevel());
+ for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++)
{
- ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(talentSpec);
- for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
- if (SpellInfo const* masterySpell = sSpellMgr->GetSpellInfo(chrSpec->MasterySpellID[i]))
- if (masterySpell->IsPassive() && IsNeedCastPassiveSpellAtLearn(masterySpell))
- CastSpell(this, masterySpell->Id, true);
+ if (!HasSpell(*iter))
+ LearnSpell(*iter, true);
}
+ SaveToDB();
+
SendTalentsInfoData();
}
+
void Player::AddKnownCurrency(uint32 itemId)
{
if (CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemId))
@@ -25577,23 +25705,39 @@ void Player::SendTalentsInfoData()
for (uint8 i = 0; i < groupsCount; ++i)
{
- TalentGroupInfo* groupInfo = GetTalentGroupInfo(i);
WorldPackets::Talent::TalentGroupInfo groupInfoPkt;
- groupInfoPkt.SpecID = groupInfo->SpecID;
+ groupInfoPkt.SpecID = GetTalentSpec(i);
+
+ groupInfoPkt.TalentIDs.reserve(GetTalentMap(i)->size());
- groupInfoPkt.TalentIDs.reserve(MAX_TALENT_TIERS);
- for (uint32 x = 0; x < MAX_TALENT_TIERS; ++x)
+ for (PlayerTalentMap::const_iterator itr = GetTalentMap(i)->begin(); itr != GetTalentMap(i)->end(); ++itr)
{
- // Do not send empty talents
- if (!groupInfo->Talents[x])
- break;
+ TalentEntry const* talentInfo = sTalentStore.LookupEntry(itr->first);
+ if (!talentInfo)
+ {
+ TC_LOG_ERROR("entities.player", "Player %s has unknown talent id: %u", GetName().c_str(), itr->first);
+ continue;
+ }
- groupInfoPkt.TalentIDs.push_back(groupInfo->Talents[x]);
+ if (talentInfo->ClassID != getClass())
+ continue;
+
+ SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
+ if (!spellEntry)
+ {
+ TC_LOG_ERROR("entities.player", "Player %s has unknown talent spell: %u", GetName().c_str(), talentInfo->SpellID);
+ continue;
+ }
+
+ if (!HasTalent(itr->first, i))
+ continue;
+
+ groupInfoPkt.TalentIDs.push_back(uint16(itr->first));
}
for (uint32 x = 0; x < MAX_GLYPH_SLOT_INDEX; ++x)
- groupInfoPkt.GlyphIDs[x] = groupInfo->Glyphs[x];
+ groupInfoPkt.GlyphIDs[x] = uint16(GetGlyph(i, x));
packet.Info.TalentGroups.push_back(groupInfoPkt);
}
@@ -25905,7 +26049,7 @@ void Player::_LoadTalents(PreparedQueryResult result)
if (result)
{
do
- AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8());
+ AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8(), false);
while (result->NextRow());
}
}
@@ -25918,17 +26062,12 @@ void Player::_SaveTalents(SQLTransaction& trans)
for (uint8 group = 0; group < MAX_TALENT_GROUPS; ++group)
{
- TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(group);
-
- for (uint32 tier = 0; tier < MAX_TALENT_TIERS; ++tier)
+ for (PlayerTalentMap::iterator itr = GetTalentMap(group)->begin(); itr != GetTalentMap(group)->end(); ++itr)
{
- if (!talentGroupInfo->Talents[tier])
- continue;
-
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT);
stmt->setUInt64(0, GetGUID().GetCounter());
- stmt->setUInt32(1, talentGroupInfo->Talents[tier]);
- stmt->setUInt8(2, group);
+ stmt->setUInt32(1, itr->first);
+ stmt->setUInt8(2, itr->second->spec);
trans->Append(stmt);
}
}
@@ -26027,30 +26166,27 @@ void Player::ActivateTalentGroup(uint8 group)
if (getClass() != talentInfo->ClassID)
continue;
+ SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
+ if (!spellEntry)
+ continue;
+
RemoveSpell(talentInfo->SpellID, true);
+
+ // search for spells that the talent teaches and unlearn them
+ for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
+ RemoveSpell(effect->TriggerSpell, true);
}
// Unlearn specialization specific spells
- auto specSpells = sSpecializationSpellsBySpecStore.find(GetActiveTalentSpec());
- if (specSpells != sSpecializationSpellsBySpecStore.end())
+ std::list<uint32> learnList = GetSpellsForLevels(0, getRaceMask(), GetActiveTalentSpec(), 0, getLevel());
+ for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++)
{
- for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it)
- {
- SpecializationSpellsEntry const* specSpell = *it;
- if (HasSpell(specSpell->SpellID)) {
- RemoveSpell(specSpell->SpellID, true);
- LearnSpell(specSpell->OverridesSpellID, false);
- }
- }
+ if (HasSpell(*iter))
+ RemoveSpell(*iter, true);
}
- // Unlearn mastery spells
- ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec());
- for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
- if (chrSpec->MasterySpellID[i])
- RemoveSpell(chrSpec->MasterySpellID[i], true);
-
- // set glyphs
+ // remove glyphs
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
// remove secondary glyph
if (uint32 oldglyph = GetGlyph(GetActiveTalentGroup(), slot))
@@ -26060,6 +26196,15 @@ void Player::ActivateTalentGroup(uint8 group)
// Activate new group
SetActiveTalentGroup(group);
+ uint32 spentTalents = 0;
+
+ learnList = GetSpellsForLevels(getClass(), getRaceMask(), GetActiveTalentSpec(), 0, getLevel());
+ for (std::list<uint32>::const_iterator iter = learnList.begin(); iter != learnList.end(); iter++)
+ {
+ if (!HasSpell(*iter))
+ LearnSpell(*iter, true);
+ }
+
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
{
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
@@ -26071,31 +26216,12 @@ void Player::ActivateTalentGroup(uint8 group)
if (getClass() != talentInfo->ClassID)
continue;
- LearnSpell(talentInfo->SpellID, false);
- }
+ ++spentTalents;
- // Replace default spells with specialization specific spells
- auto newSpecSpells = sSpecializationSpellsBySpecStore.find(GetActiveTalentSpec());
- if (newSpecSpells != sSpecializationSpellsBySpecStore.end())
- {
- for (auto it = newSpecSpells->second.begin(); it != newSpecSpells->second.end(); ++it)
- {
- SpecializationSpellsEntry const* specSpell = *it;
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID);
- if (getLevel() >= spellInfo->BaseLevel) {
- if (specSpell->OverridesSpellID)
- RemoveSpell(specSpell->OverridesSpellID, true);
- LearnSpell(specSpell->SpellID, false);
- }
- }
+ if (HasTalent(talentInfo->SpellID, group))
+ LearnSpell(talentInfo->SpellID, false);
}
- if (CanUseMastery())
- if (ChrSpecializationEntry const* newChrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
- for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
- if (newChrSpec->MasterySpellID[i])
- LearnSpell(newChrSpec->MasterySpellID[i], false);
-
// set glyphs
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
{
@@ -26109,6 +26235,7 @@ void Player::ActivateTalentGroup(uint8 group)
SetGlyph(slot, glyph);
}
+ SetUsedTalentCount(spentTalents);
InitTalentForLevel();
{
@@ -26128,7 +26255,9 @@ void Player::ActivateTalentGroup(uint8 group)
SetPower(pw, 0);
if (!sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
+ {
ResetTalents(true);
+ }
}
void Player::ResetTimeSync()
@@ -27168,3 +27297,9 @@ void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell)
data << uint32(newSpell) << uint32(oldSpell);
GetSession()->SendPacket(&data);
}
+
+uint32 Player::CalculateTalentsPoints() const
+{
+ // 1 talent point for every 15 levels
+ return getLevel() >= 100 ? 7 : uint32(floor(getLevel() / 15.f));
+} \ No newline at end of file
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 2d919159819..6b9e925e28d 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -116,6 +116,12 @@ struct PlayerSpell
bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks
};
+struct PlayerTalent
+{
+ PlayerSpellState state : 8;
+ uint8 spec : 8;
+};
+
extern uint32 const MasterySpells[MAX_CLASSES];
enum TalentSpecialization // talent tabs
@@ -184,6 +190,7 @@ struct PlayerCurrency
uint32 weekCount;
};
+typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
typedef std::list<SpellModifier*> SpellModList;
typedef std::unordered_map<uint32, PlayerCurrency> PlayerCurrenciesMap;
@@ -412,9 +419,9 @@ struct PlayerInfo
uint16 displayId_f;
PlayerCreateInfoItems item;
PlayerCreateInfoSpells customSpells;
- PlayerCreateInfoSpells spells;
PlayerCreateInfoSpells castSpells;
PlayerCreateInfoActions action;
+ PlayerCreateInfoSkills skills;
PlayerLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1
};
@@ -1223,56 +1230,41 @@ private:
bool _isPvP;
};
-struct TalentGroupInfo
+struct PlayerTalentInfo
{
- uint32 Talents[MAX_TALENT_TIERS];
- uint32 Glyphs[MAX_GLYPH_SLOT_INDEX];
- uint32 SpecID;
-
- bool HasTalent(uint32 talentId)
- {
- for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i)
- if (Talents[i] == talentId)
- return true;
- return false;
- }
-
- uint32 TalentCount()
+ PlayerTalentInfo() : UsedTalentCount(0), ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), GroupsCount(1)
{
- for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i)
- if (!Talents[i])
- return i;
- return MAX_TALENT_TIERS;
+ for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
+ {
+ GroupInfo[i].Talents = new PlayerTalentMap();
+ memset(GroupInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32));
+ GroupInfo[i].TalentTree = 0;
+ }
}
- void Reset()
- {
- for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i)
- Talents[i] = 0;
- }
-};
-
-struct PlayerTalentInfo
-{
- PlayerTalentInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), GroupsCount(1)
+ ~PlayerTalentInfo()
{
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
{
- memset(GroupInfo[i].Talents, 0, sizeof(uint32)*MAX_TALENT_TIERS);
- memset(GroupInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32));
- GroupInfo[i].SpecID = 0;
+ for (PlayerTalentMap::const_iterator itr = GroupInfo[i].Talents->begin(); itr != GroupInfo[i].Talents->end(); ++itr)
+ delete itr->second;
+ delete GroupInfo[i].Talents;
}
}
- TalentGroupInfo GroupInfo[MAX_TALENT_GROUPS];
+ struct TalentGroupInfo
+ {
+ PlayerTalentMap* Talents;
+ uint32 Glyphs[MAX_GLYPH_SLOT_INDEX];
+ uint32 TalentTree;
+ } GroupInfo[MAX_TALENT_GROUPS];
+
+ uint32 UsedTalentCount;
uint32 ResetTalentsCost;
time_t ResetTalentsTime;
uint8 ActiveGroup;
uint8 GroupsCount;
-
- uint32 UsedTalentCount;
-
private:
PlayerTalentInfo(PlayerTalentInfo const&);
};
@@ -1824,7 +1816,8 @@ class Player : public Unit, public GridObject<Player>
void RemoveSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true);
void ResetSpells(bool myClassOnly = false);
void LearnCustomSpells();
- void LearnDefaultSpells();
+ void LearnDefaultSkills();
+ void LearnDefaultSkill(uint32 skillId, uint16 rank);
void LearnQuestRewardedSpells();
void LearnQuestRewardedSpells(Quest const* quest);
void LearnSpellHighestRank(uint32 spellid);
@@ -1837,26 +1830,33 @@ class Player : public Unit, public GridObject<Player>
// Talents
uint32 GetUsedTalentCount() const { return _talentMgr->UsedTalentCount; }
void SetUsedTalentCount(uint32 talents) { _talentMgr->UsedTalentCount = talents; }
-
uint32 GetTalentResetCost() const { return _talentMgr->ResetTalentsCost; }
void SetTalentResetCost(uint32 cost) { _talentMgr->ResetTalentsCost = cost; }
uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; }
void SetTalentResetTime(time_t time_) { _talentMgr->ResetTalentsTime = time_; }
- uint8 GetActiveTalentGroup() const { return _talentMgr->ActiveGroup; }
- void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; }
+
uint8 GetTalentGroupsCount() const { return _talentMgr->GroupsCount; }
void SetTalentGroupsCount(uint8 count) { _talentMgr->GroupsCount = count; }
- uint32 GetTalentSpec(uint8 group) const { return _talentMgr->GroupInfo[group].SpecID; }
- void SetTalentSpec(uint8 group, uint32 talentSpec) const { _talentMgr->GroupInfo[group].SpecID = talentSpec; }
- uint32 GetActiveTalentSpec() const { return _talentMgr->GroupInfo[_talentMgr->ActiveGroup].SpecID; }
+ uint8 GetActiveTalentGroup() const { return _talentMgr->ActiveGroup; }
+ void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; }
+
+ uint32 GetTalentSpec(uint8 group) const { return _talentMgr->GroupInfo[group].TalentTree; }
+ void SetTalentSpec(uint8 group, uint32 talentSpec) const { _talentMgr->GroupInfo[group].TalentTree = talentSpec; }
+ uint32 GetActiveTalentSpec() const { return _talentMgr->GroupInfo[_talentMgr->ActiveGroup].TalentTree; }
+
+
+ bool ResetTalents(bool noCost = false, bool resetTalents = true, bool resetSpecialization = true);
+ bool RemoveTalent(uint32 talentId);
- bool ResetTalents(bool no_cost = false);
uint32 GetNextResetTalentsCost() const;
void InitTalentForLevel();
void SendTalentsInfoData();
bool LearnTalent(uint32 talentId);
- bool AddTalent(uint32 talentId, uint8 spec);
+ bool AddTalent(uint32 talentId, uint8 spec, bool learning);
bool HasTalent(uint32 talentId, uint8 spec);
+ uint32 CalculateTalentsPoints() const;
+
+
void LearnTalentSpecialization(uint32 talentSpec);
// Dual Spec
@@ -1870,7 +1870,8 @@ class Player : public Unit, public GridObject<Player>
void SetGlyph(uint8 slot, uint32 glyph);
uint32 GetGlyph(uint8 group, uint8 slot) const { return _talentMgr->GroupInfo[group].Glyphs[slot]; }
- TalentGroupInfo* GetTalentGroupInfo(uint8 group) { return &_talentMgr->GroupInfo[group]; }
+ PlayerTalentMap const* GetTalentMap(uint8 spec) const { return _talentMgr->GroupInfo[spec].Talents; }
+ PlayerTalentMap* GetTalentMap(uint8 spec) { return _talentMgr->GroupInfo[spec].Talents; }
ActionButtonList const& GetActionButtons() const { return m_actionButtons; }
uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS); }
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 5fbc6e7632c..e4f12614b33 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -3033,7 +3033,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint3
bp = *(baseAmount + effect->EffectIndex);
else
bp = effect->BasePoints;
- TC_LOG_ERROR("spells", "_TryStackingOrRefreshingExistingAura spell %u effMask %u currIdx %u", newAura->Id, effMask, effect->EffectIndex);
+
int32* oldBP = const_cast<int32*>(&(foundAura->GetEffect(effect->EffectIndex)->m_baseAmount)); // todo 6.x review GetBaseAmount and GetCastItemGUID in this case
*oldBP = bp;
}
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 4858800b3d2..ae39c405e26 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -3279,16 +3279,16 @@ void ObjectMgr::LoadPlayerInfo()
}
}
- // Load playercreate spells
- TC_LOG_INFO("server.loading", "Loading Player Create Spell Data...");
+ // Load playercreate skills
+ TC_LOG_INFO("server.loading", "Loading Player Create Skill Data...");
{
uint32 oldMSTime = getMSTime();
- QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM playercreateinfo_spell");
+ QueryResult result = WorldDatabase.PQuery("SELECT raceMask, classMask, skill, rank FROM playercreateinfo_skills");
if (!result)
{
- TC_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `playercreateinfo_spell` is empty.");
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 player create skills. DB table `playercreateinfo_skills` is empty.");
}
else
{
@@ -3299,17 +3299,31 @@ void ObjectMgr::LoadPlayerInfo()
Field* fields = result->Fetch();
uint32 raceMask = fields[0].GetUInt32();
uint32 classMask = fields[1].GetUInt32();
- uint32 spellId = fields[2].GetUInt32();
+ PlayerCreateInfoSkill skill;
+ skill.SkillId = fields[2].GetUInt16();
+ skill.Rank = fields[3].GetUInt16();
+
+ if (skill.Rank >= MAX_SKILL_STEP)
+ {
+ TC_LOG_ERROR("sql.sql", "Skill rank value %hu set for skill %hu raceMask %u classMask %u is too high, max allowed value is %d", skill.Rank, skill.SkillId, raceMask, classMask, MAX_SKILL_STEP);
+ continue;
+ }
if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE))
{
- TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_spell` table, ignoring.", raceMask);
+ TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_skills` table, ignoring.", raceMask);
continue;
}
if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE))
{
- TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_spell` table, ignoring.", classMask);
+ TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_skills` table, ignoring.", classMask);
+ continue;
+ }
+
+ if (!sSkillLineStore.LookupEntry(skill.SkillId))
+ {
+ TC_LOG_ERROR("sql.sql", "Wrong skill id %u in `playercreateinfo_skills` table, ignoring.", skill.SkillId);
continue;
}
@@ -3321,23 +3335,21 @@ void ObjectMgr::LoadPlayerInfo()
{
if (classMask == 0 || ((1 << (classIndex - 1)) & classMask))
{
+ if (!GetSkillRaceClassInfo(skill.SkillId, raceIndex, classIndex))
+ continue;
+
if (PlayerInfo* info = _playerInfo[raceIndex][classIndex])
{
- info->spells.push_back(spellId);
+ info->skills.push_back(skill);
++count;
}
- // We need something better here, the check is not accounting for spells used by multiple races/classes but not all of them.
- // Either split the masks per class, or per race, which kind of kills the point yet.
- // else if (raceMask != 0 && classMask != 0)
- // TC_LOG_ERROR("sql.sql", "Racemask/classmask (%u/%u) combination was found containing an invalid race/class combination (%u/%u) in `%s` (Spell %u), ignoring.", raceMask, classMask, raceIndex, classIndex, tableName.c_str(), spellId);
}
}
}
}
- }
- while (result->NextRow());
+ } while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u player create spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded %u player create skills in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
}
@@ -7846,34 +7858,27 @@ int32 ObjectMgr::GetBaseReputationOf(FactionEntry const* factionEntry, uint8 rac
return 0;
}
-SkillRangeType GetSkillRangeType(SkillLineEntry const* pSkill, bool racial)
+SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry)
{
- switch (pSkill->CategoryID)
+ SkillLineEntry const* skill = sSkillLineStore.LookupEntry(rcEntry->SkillID);
+ if (!skill)
+ return SKILL_RANGE_NONE;
+
+ if (sSkillTiersStore.LookupEntry(rcEntry->SkillTierID))
+ return SKILL_RANGE_RANK;
+
+ if (rcEntry->SkillID == SKILL_RUNEFORGING)
+ return SKILL_RANGE_MONO;
+
+ switch (skill->CategoryID)
{
+ case SKILL_CATEGORY_ARMOR:
+ return SKILL_RANGE_MONO;
case SKILL_CATEGORY_LANGUAGES:
return SKILL_RANGE_LANGUAGE;
- case SKILL_CATEGORY_WEAPON:
- return SKILL_RANGE_LEVEL;
- case SKILL_CATEGORY_ARMOR:
- case SKILL_CATEGORY_CLASS:
- if (pSkill->ID != SKILL_LOCKPICKING)
- return SKILL_RANGE_MONO;
- else
- return SKILL_RANGE_LEVEL;
- case SKILL_CATEGORY_SECONDARY:
- case SKILL_CATEGORY_PROFESSION:
- // not set skills for professions and racial abilities
- if (IsProfessionSkill(pSkill->ID))
- return SKILL_RANGE_RANK;
- else if (racial)
- return SKILL_RANGE_NONE;
- else
- return SKILL_RANGE_MONO;
- default:
- case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc
- case SKILL_CATEGORY_GENERIC: //only GENERIC(DND)
- return SKILL_RANGE_NONE;
}
+
+ return SKILL_RANGE_LEVEL;
}
void ObjectMgr::LoadGameTele()
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index bf0d889057b..e7191735ca1 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -668,7 +668,7 @@ enum SkillRangeType
SKILL_RANGE_NONE // 0..0 always
};
-SkillRangeType GetSkillRangeType(SkillLineEntry const* pSkill, bool racial);
+SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry);
#define MAX_PLAYER_NAME 12 // max allowed by client name length
#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length (> MAX_PLAYER_NAME for support declined names)
diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index f0c1b28117b..278169c2d63 100644
--- a/src/server/game/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
@@ -28,59 +28,22 @@
#include "WorldSession.h"
#include "TalentPackets.h"
-void WorldSession::HandleLearnTalentOpcode(WorldPacket& recvData)
+void WorldSession::HandleLearnTalentOpcode(WorldPackets::Talent::LearnTalent& packet)
{
- /* TODO: 6.x update packet struct (note: LearnTalent no longer has rank argument)
- uint32 talentId, requestedRank;
- recvData >> talentId >> requestedRank;
-
- if (_player->LearnTalent(talentId, requestedRank))
- _player->SendTalentsInfoData(false);*/
+ bool anythingLearned = false;
+ for (uint32 talentId : packet.Talents)
+ {
+ if (_player->LearnTalent(talentId))
+ anythingLearned = true;
+ }
+
+ if (anythingLearned)
+ _player->SendTalentsInfoData();
}
void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
{
- /* TODO: 6.x update packet struct
TC_LOG_DEBUG("network", "CMSG_LEARN_PREVIEW_TALENTS");
-
- int32 tabPage;
- uint32 talentsCount;
- recvPacket >> tabPage; // talent tree
-
- // prevent cheating (selecting new tree with points already in another)
- if (tabPage >= 0) // -1 if player already has specialization
- {
- if (TalentTabEntry const* talentTabEntry = sTalentTabStore.LookupEntry(_player->GetPrimaryTalentTree(_player->GetActiveSpec())))
- {
- if (talentTabEntry->tabpage != uint32(tabPage))
- {
- recvPacket.rfinish();
- return;
- }
- }
- }
-
- recvPacket >> talentsCount;
-
- uint32 talentId, talentRank;
-
- // Client has max 21 talents for tree for 3 trees, rounded up : 70
- uint32 const MaxTalentsCount = 70;
-
- for (uint32 i = 0; i < talentsCount && i < MaxTalentsCount; ++i)
- {
- recvPacket >> talentId >> talentRank;
-
- if (!_player->LearnTalent(talentId, talentRank))
- {
- recvPacket.rfinish();
- break;
- }
- }
-
- _player->SendTalentsInfoData(false);
-
- recvPacket.rfinish();*/
}
void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recvData)
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index 3ca660dccd1..a6bd43f72c6 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -371,6 +371,29 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::SpellCastRequest&
// not have spell in spellbook
return;
}
+
+ if (Player* plr = caster->ToPlayer())
+ {
+ uint32 specId = plr->GetActiveTalentSpec();
+ if (specId)
+ {
+ if (sSpecializationOverrideSpellMap.find(specId) != sSpecializationOverrideSpellMap.end())
+ {
+ if (sSpecializationOverrideSpellMap[specId].find(castRequest.SpellID) != sSpecializationOverrideSpellMap[specId].end())
+ {
+ SpellInfo const* newSpellInfo = sSpellMgr->GetSpellInfo(sSpecializationOverrideSpellMap[specId][castRequest.SpellID]);
+ if (newSpellInfo)
+ {
+ if (newSpellInfo->SpellLevel <= caster->getLevel())
+ {
+ spellInfo = newSpellInfo;
+ castRequest.SpellID = newSpellInfo->Id;
+ }
+ }
+ }
+ }
+ }
+ }
Unit::AuraEffectList swaps = mover->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS);
Unit::AuraEffectList const& swaps2 = mover->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2);
diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp
index 7c536363335..1e181d37ff9 100644
--- a/src/server/game/Server/Packets/SpellPackets.cpp
+++ b/src/server/game/Server/Packets/SpellPackets.cpp
@@ -182,8 +182,6 @@ void WorldPackets::Spells::SpellCastRequest::Read()
_worldPacket >> SpellID;
_worldPacket >> Misc;
- TC_LOG_ERROR("spells", "SpellID %u Misc %u", SpellID, Misc);
-
_worldPacket.ResetBitPos();
TargetFlags = _worldPacket.ReadBits(21);
@@ -469,3 +467,12 @@ WorldPacket const* WorldPackets::Spells::SetSpellModifier::Write()
return &_worldPacket;
}
+
+WorldPacket const* WorldPackets::Spells::SendRemovedSpell::Write()
+{
+ _worldPacket << uint32(Spells.size());
+ for (uint32 spellId : Spells)
+ _worldPacket << uint32(spellId);
+
+ return &_worldPacket;
+} \ No newline at end of file
diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h
index e9ae7ada77b..6971b730742 100644
--- a/src/server/game/Server/Packets/SpellPackets.h
+++ b/src/server/game/Server/Packets/SpellPackets.h
@@ -223,6 +223,16 @@ namespace WorldPackets
std::vector<SpellModifier> Modifiers;
};
+
+ class SendRemovedSpell final : public ServerPacket
+ {
+ public:
+ SendRemovedSpell() : ServerPacket(SMSG_REMOVED_SPELL, 4) { }
+
+ WorldPacket const* Write() override;
+
+ std::vector<uint32> Spells;
+ };
}
}
diff --git a/src/server/game/Server/Packets/TalentPackets.cpp b/src/server/game/Server/Packets/TalentPackets.cpp
index 4855f663662..d340b476cf9 100644
--- a/src/server/game/Server/Packets/TalentPackets.cpp
+++ b/src/server/game/Server/Packets/TalentPackets.cpp
@@ -41,3 +41,17 @@ void WorldPackets::Talent::SetSpecialization::Read()
{
_worldPacket >> SpecGroupIndex;
}
+
+
+void WorldPackets::Talent::LearnTalent::Read()
+{
+ uint32 count;
+ _worldPacket >> count;
+
+ for (uint32 i = 0; i < count; ++i)
+ {
+ uint16 talent;
+ _worldPacket >> talent;
+ Talents.push_back(talent);
+ }
+} \ No newline at end of file
diff --git a/src/server/game/Server/Packets/TalentPackets.h b/src/server/game/Server/Packets/TalentPackets.h
index 21753e22c8d..2bc8b3934a8 100644
--- a/src/server/game/Server/Packets/TalentPackets.h
+++ b/src/server/game/Server/Packets/TalentPackets.h
@@ -57,6 +57,19 @@ namespace WorldPackets
uint32 SpecGroupIndex = 0;
};
+
+ class LearnTalent final : public ClientPacket
+ {
+ public:
+ LearnTalent(WorldPacket&& packet) : ClientPacket(std::move(packet))
+ {
+ ASSERT(packet.GetOpcode() == CMSG_LEARN_TALENT);
+ }
+
+ void Read() override;
+ std::vector<uint16> Talents;
+
+ };
}
}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 79671b85892..671f0deb919 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -369,7 +369,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_KEEP_ALIVE, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess );
DEFINE_OPCODE_HANDLER_OLD(CMSG_LEARN_PREVIEW_TALENTS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalents );
DEFINE_OPCODE_HANDLER_OLD(CMSG_LEARN_PREVIEW_TALENTS_PET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalentsPet );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_LEARN_TALENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnTalentOpcode );
+ DEFINE_HANDLER(CMSG_LEARN_TALENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Talent::LearnTalent, &WorldSession::HandleLearnTalentOpcode);
DEFINE_HANDLER(CMSG_LEAVE_CHANNEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Channel::LeaveChannel, &WorldSession::HandleLeaveChannel);
DEFINE_OPCODE_HANDLER_OLD(CMSG_LFG_GET_STATUS, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleLfgGetStatus );
DEFINE_OPCODE_HANDLER_OLD(CMSG_LFG_JOIN, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgJoinOpcode );
@@ -1247,7 +1247,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_FAILURE, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFORGE_RESULT, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFRESH_SPELL_HISTORY, STATUS_UNHANDLED);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_REMOVED_SPELL, STATUS_UNHANDLED);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_REMOVED_SPELL, STATUS_NEVER);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REPORT_PVP_AFK_RESULT, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REQUEST_CEMETERY_LIST_RESPONSE, STATUS_UNHANDLED);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REQUEST_PVP_REWARDS_RESPONSE, STATUS_UNHANDLED);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index f6bdf0892d7..ee95bd840ab 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -314,7 +314,7 @@ enum OpcodeClient : uint32
CMSG_KEEP_ALIVE = 0xBADD,
CMSG_LEARN_PREVIEW_TALENTS = 0xBADD,
CMSG_LEARN_PREVIEW_TALENTS_PET = 0xBADD,
- CMSG_LEARN_TALENT = 0xBADD,
+ CMSG_LEARN_TALENT = 0x0BB6,
CMSG_LEAVE_CHANNEL = 0x19F2,
CMSG_LFG_GET_STATUS = 0xBADD,
CMSG_LFG_JOIN = 0xBADD,
@@ -1269,7 +1269,7 @@ enum OpcodeServer : uint32
SMSG_REFER_A_FRIEND_FAILURE = 0xBADD,
SMSG_REFORGE_RESULT = 0xBADD,
SMSG_REFRESH_SPELL_HISTORY = 0x0A2A,
- SMSG_REMOVED_SPELL = 0xBADD,
+ SMSG_REMOVED_SPELL = 0x0B3B,
SMSG_REPORT_PVP_AFK_RESULT = 0xBADD,
SMSG_REQUEST_CEMETERY_LIST_RESPONSE = 0x059E,
SMSG_REQUEST_PVP_REWARDS_RESPONSE = 0xBADD,
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 26db96b232d..910a8ad4aa6 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -147,6 +147,7 @@ namespace WorldPackets
namespace Talent
{
class SetSpecialization;
+ class LearnTalent;
}
namespace Trade
@@ -876,7 +877,7 @@ class WorldSession
void HandleCancelGrowthAuraOpcode(WorldPacket& recvPacket);
void HandleCancelAutoRepeatSpellOpcode(WorldPacket& recvPacket);
- void HandleLearnTalentOpcode(WorldPacket& recvPacket);
+ void HandleLearnTalentOpcode(WorldPackets::Talent::LearnTalent& packet);
void HandleLearnPreviewTalents(WorldPacket& recvPacket);
void HandleTalentWipeConfirmOpcode(WorldPacket& recvPacket);
void HandleUnlearnSkillOpcode(WorldPacket& recvPacket);
diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp
index 9d2d4426efe..e571f30b74e 100644
--- a/src/server/scripts/Commands/cs_learn.cpp
+++ b/src/server/scripts/Commands/cs_learn.cpp
@@ -204,7 +204,7 @@ public:
// learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
player->LearnSpellHighestRank(talentInfo->SpellID);
- player->AddTalent(talentInfo->SpellID, player->GetActiveTalentGroup());
+ player->AddTalent(talentInfo->SpellID, player->GetActiveTalentGroup(), true);
}
handler->SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
@@ -306,7 +306,7 @@ public:
if (!handler->extractPlayerTarget((char*)args, &target))
return false;
- target->LearnDefaultSpells();
+ target->LearnDefaultSkills();
target->LearnCustomSpells();
target->LearnQuestRewardedSpells();