Skip to content

Instantly share code, notes, and snippets.

@Emtec
Created July 11, 2010 14:26
Show Gist options
  • Save Emtec/471587 to your computer and use it in GitHub Desktop.
Save Emtec/471587 to your computer and use it in GitHub Desktop.
diff --git a/sql/v01_vehicle_data.sql b/sql/v01_vehicle_data.sql
new file mode 100644
index 0000000..74dc665
--- /dev/null
+++ b/sql/v01_vehicle_data.sql
@@ -0,0 +1,21 @@
+--
+-- Table structure for table `vehicle_data`
+--
+
+DROP TABLE IF EXISTS `vehicle_data`;
+CREATE TABLE `vehicle_data` (
+ `entry` mediumint(5) unsigned NOT NULL,
+ `flags` mediumint(8) unsigned NOT NULL default '0',
+ `Spell1` mediumint(8) unsigned NOT NULL default '0',
+ `Spell2` mediumint(8) unsigned NOT NULL default '0',
+ `Spell3` mediumint(8) unsigned NOT NULL default '0',
+ `Spell4` mediumint(8) unsigned NOT NULL default '0',
+ `Spell5` mediumint(8) unsigned NOT NULL default '0',
+ `Spell6` mediumint(8) unsigned NOT NULL default '0',
+ `Spell7` mediumint(8) unsigned NOT NULL default '0',
+ `Spell8` mediumint(8) unsigned NOT NULL default '0',
+ `Spell9` mediumint(8) unsigned NOT NULL default '0',
+ `Spell10` mediumint(8) unsigned NOT NULL default '0',
+ `req_aura` mediumint(8) unsigned NOT NULL default '0',
+ PRIMARY KEY (`entry`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Vehicle System';
\ No newline at end of file
diff --git a/sql/v02_vehicle_seat_data.sql b/sql/v02_vehicle_seat_data.sql
new file mode 100644
index 0000000..5c3a390
--- /dev/null
+++ b/sql/v02_vehicle_seat_data.sql
@@ -0,0 +1,10 @@
+--
+-- Table structure for table `vehicle_seat_data`
+--
+
+DROP TABLE IF EXISTS `vehicle_seat_data`;
+CREATE TABLE `vehicle_seat_data` (
+ `seat` mediumint(5) unsigned NOT NULL,
+ `flags` mediumint(8) unsigned NOT NULL default '0',
+ PRIMARY KEY (`seat`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Vehicle Seat System';
\ No newline at end of file
diff --git a/sql/v03_creature_addon_tables.sql b/sql/v03_creature_addon_tables.sql
new file mode 100644
index 0000000..7240ed4
--- /dev/null
+++ b/sql/v03_creature_addon_tables.sql
@@ -0,0 +1,7 @@
+ALTER TABLE creature_addon
+ ADD COLUMN vehicle_id smallint(5) unsigned NOT NULL default '0' AFTER moveflags,
+ ADD COLUMN passengers text AFTER vehicle_id;
+
+ALTER TABLE creature_template_addon
+ ADD COLUMN vehicle_id smallint(5) unsigned NOT NULL default '0' AFTER moveflags,
+ ADD COLUMN passengers text AFTER vehicle_id;
\ No newline at end of file
diff --git a/sql/v10_vehicle_test_data.sql b/sql/v10_vehicle_test_data.sql
new file mode 100644
index 0000000..e6aeecc
--- /dev/null
+++ b/sql/v10_vehicle_test_data.sql
@@ -0,0 +1,553 @@
+INSERT INTO `vehicle_data` VALUES
+('106', '4', '50896', '0', '50652', '0', '0', '0', '0', '0', '0', '0', '0'),
+('116', '5', '51362', '51421', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('117', '4', '50652', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('156', '24', '53114', '0', '53110', '0', '0', '0', '0', '0', '0', '0', '0'),
+('200', '30', '52362', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('210', '166', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('6', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('7', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('8', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('14', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('16', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('17', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('21', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('22', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('23', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('24', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('25', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('26', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('27', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('28', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('29', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('30', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('31', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('32', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('33', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('34', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('35', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('36', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('37', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('38', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('39', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('40', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('41', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('42', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('43', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('44', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('46', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('47', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('48', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('49', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('50', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('51', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('52', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('53', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('54', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('55', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('56', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('57', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('58', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('59', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('60', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('61', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('62', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('64', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('65', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('69', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('70', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('71', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('72', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('74', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('75', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('76', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('77', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('79', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('80', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('81', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('86', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('87', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('88', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('89', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('90', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('91', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('92', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('93', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('97', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('99', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('100', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('102', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('104', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('105', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('107', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('108', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('109', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('110', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('111', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('112', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('113', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('114', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('115', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('118', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('120', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('121', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('122', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('124', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('125', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('126', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('127', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('128', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('129', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('130', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('131', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('132', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('134', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('137', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('138', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('139', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('142', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('143', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('145', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('146', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('147', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('148', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('149', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('150', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('152', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('153', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('154', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('158', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('160', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('162', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('163', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('164', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('165', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('166', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('167', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('168', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('169', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('171', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('173', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('174', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('175', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('176', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('177', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('178', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('179', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('180', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('181', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('182', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('183', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('186', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('188', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('189', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('190', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('191', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('192', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('193', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('194', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('196', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('197', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('198', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('199', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('201', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('202', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('203', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('204', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('205', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('206', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('207', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('208', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('209', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('211', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('212', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('213', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('214', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('215', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('216', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('217', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('218', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('219', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('220', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('221', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('222', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('223', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('224', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('225', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('226', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('227', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('228', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('229', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('230', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('231', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('232', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('233', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('234', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('236', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('237', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('238', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('240', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('241', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('242', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('243', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('244', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('245', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('246', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('247', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('248', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('249', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('250', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('252', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('253', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('254', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('255', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('256', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('257', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('258', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('259', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('260', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('261', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('262', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('263', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('264', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('265', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('266', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('267', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('268', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('269', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('270', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('271', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('272', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('273', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('274', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('275', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('276', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('277', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('278', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('279', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('280', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('281', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('282', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('283', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('284', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('285', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('286', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('287', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('288', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('289', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('290', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('291', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('292', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('293', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('294', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('295', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('296', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('297', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('298', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('299', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('300', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('301', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('302', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('303', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('304', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('305', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('308', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('309', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('310', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('311', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('312', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('313', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('314', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('315', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('316', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('317', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('318', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('320', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('321', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('322', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('323', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('324', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('325', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('327', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('328', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('329', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('331', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('332', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('335', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('336', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('337', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('338', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('339', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('340', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('341', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('342', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('343', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('344', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('345', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('347', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('348', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('352', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('353', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('354', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('356', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('357', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('358', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('359', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('363', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('368', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('369', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('370', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('371', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('372', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('373', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('374', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('375', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('376', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('380', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('381', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('385', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('387', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('388', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('389', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('390', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('392', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('395', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('396', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('397', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('399', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('135', '12', '52362', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'),
+('349', '24', '62544', '62575', '62960', '62552', '64077', '62863', '0', '0', '0', '0', '62853'),
+('68', '24', '52435', '52576', '52588', '0', '0', '0', '0', '0', '0', '0', '0');
+
+UPDATE creature_template SET maxhealth = 133525, minhealth = 133525, maxmana = 51360, minmana = 51360 WHERE entry = 28670;
+UPDATE creature_template SET maxhealth = 50000, minhealth = 50000 WHERE entry = 28094;
+UPDATE creature_template SET maxhealth = 75000, minhealth = 75000 WHERE entry IN (28312,32627);
+UPDATE creature_template SET maxhealth = 50000, minhealth = 50000 WHERE entry IN (28319,32629);
+
+UPDATE creature_template SET minlevel = 80, maxlevel = 80 WHERE entry IN (28312,32627,28319,32629,28094,28670);
+
+UPDATE creature_template SET speed_run = 2, InhabitType = 1 WHERE entry IN (28312,32627,28319,32629,28094,29929,28782);
+UPDATE creature_template SET speed_run = 2.4, InhabitType = 4 WHERE entry IN (28670);
+UPDATE creature_template SET mechanic_immune_mask = 652951551 WHERE entry IN (28670,28312,32627,28319,32629,28094,29929,28782);
+
+DELETE FROM npc_spellclick_spells WHERE npc_entry in (28670, 28312, 32629, 28319, 32627, 28094, 29929, 28782);
+INSERT INTO npc_spellclick_spells VALUES
+(28670, 52196, 0, 0, 0, 0),
+(28312, 60968, 0, 0, 0, 1),
+(32627, 60968, 0, 0, 0, 1),
+(28319, 60968, 0, 0, 0, 1),
+(32629, 60968, 0, 0, 0, 1),
+(28094, 60968, 0, 0, 0, 1),
+(29929, 58961, 0, 0, 0, 1),
+(28782, 52280, 12687, 1, 12687, 1);
+
+DELETE FROM creature_template_addon WHERE entry in (28670, 28312, 32629, 28319, 32627, 28094, 29929, 28782);
+INSERT INTO creature_template_addon VALUES
+(28670, 0, 50331648, 1, 0, 1024, 156, NULL, '53112 0 53112 1'),
+(28312, 0, 0, 0, 0, 0, 117, '28319 7', NULL),
+(32627, 0, 0, 0, 0, 0, 117, '32629 7', NULL),
+(28319, 0, 0, 0, 0, 0, 116, NULL, NULL),
+(32629, 0, 0, 0, 0, 0, 116, NULL, NULL),
+(28094, 0, 0, 0, 0, 0, 106, NULL, NULL),
+(29929, 0, 0, 0, 0, 0, 210, NULL, NULL),
+(28782, 0, 0, 0, 0, 0, 200, NULL, NULL);
+
+DELETE FROM vehicle_data WHERE entry in (106, 116, 117, 156, 200, 210);
+INSERT INTO vehicle_data VALUES (106, 4, 50896, 0, 50652, 0, 0, 0, 0, 0, 0, 0, 0),
+(116, 5, 51362, 51421, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+(117, 4, 50652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+(156, 24, 53114, 0, 53110, 0, 0, 0, 0, 0, 0, 0, 0),
+(200, 30, 52362, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+(210, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+DELETE FROM vehicle_seat_data WHERE seat in (1643, 1648, 1649, 1650, 1652, 1554, 1556, 1557, 1986, 1987, 2144, 2181, 2182);
+INSERT INTO vehicle_seat_data VALUES
+(1643, 3),
+(1648, 3),
+(1649, 2),
+(1650, 2),
+(1652, 4),
+(1554, 3),
+(1556, 6),
+(1557, 6),
+(1986, 3),
+(1987, 8),
+(2144, 1),
+(2181, 1),
+(2182, 0);
+
+/* Some quests
+Argent tournament*/
+UPDATE creature_template SET speed_run = '1.5', unit_flags = 8 WHERE entry IN (33844,33845);
+DELETE FROM creature_addon WHERE guid IN (SELECT guid FROM creature WHERE id IN (33844,33845));
+DELETE FROM creature WHERE id IN (33844,33845);
+DELETE FROM vehicle_data WHERE entry in (349);
+INSERT INTO `vehicle_data` VALUES ('349', '24', '62544', '62575', '62960', '62552', '64077', '62863', '0', '0', '0', '0', '62853');
+DELETE FROM vehicle_seat_data WHERE seat in (3129);
+INSERT INTO `vehicle_seat_data` VALUES ('3129', '1');
+INSERT INTO `npc_spellclick_spells` VALUES ('33842', '63791', '13829', '1', '0', '3');
+INSERT INTO `npc_spellclick_spells` VALUES ('33842', '63791', '13839', '1', '0', '3');
+INSERT INTO `npc_spellclick_spells` VALUES ('33842', '63791', '13838', '1', '0', '3');
+INSERT INTO `npc_spellclick_spells` VALUES ('33843', '63792', '13828', '1', '0', '3');
+INSERT INTO `npc_spellclick_spells` VALUES ('33843', '63792', '13837', '1', '0', '3');
+INSERT INTO `npc_spellclick_spells` VALUES ('33843', '63792', '13835', '1', '0', '3');
+DELETE FROM creature_template_addon WHERE entry IN (33844,33845);
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (33844, 0, 0, 2049, 0, 0, 349, '', '');
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (33845, 0, 0, 2049, 0, 0, 349, '', '');
+
+/*Quest Into the Realm of Shadows (12687)*/
+UPDATE creature_template SET faction_A = 2082, faction_H = 2082, unit_flags = 0 WHERE entry = 28782;
+DELETE FROM creature_addon WHERE guid IN (SELECT guid FROM creature WHERE id = 28782);
+DELETE FROM vehicle_data WHERE entry in (135);
+INSERT INTO vehicle_data VALUES (135, 12, 52362, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+DELETE FROM vehicle_seat_data WHERE seat in (1871);
+INSERT INTO vehicle_seat_data VALUES (1871, 1);
+DELETE FROM npc_spellclick_spells WHERE npc_entry in (28782);
+INSERT INTO npc_spellclick_spells VALUES (28782, 52349, 12687, 1, 12687, 3);
+DELETE FROM creature_template_addon WHERE entry IN (28782);
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (28782, 0, 0, 1, 0, 0, 135, '', '');
+
+/*Quest Grand Theft Palomino (12680)*/
+DELETE FROM creature_addon WHERE guid IN (SELECT guid FROM creature WHERE id IN (28605,28606,28607));
+REPLACE INTO spell_script_target VALUES (52264,1,28653);
+DELETE FROM vehicle_data WHERE entry in (123);
+INSERT INTO vehicle_data VALUES (123, 12, 52264, 52268, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+DELETE FROM vehicle_seat_data WHERE seat in (1782);
+INSERT INTO vehicle_seat_data VALUES (1782, 1);
+DELETE FROM npc_spellclick_spells WHERE npc_entry in (28605,28606,28607);
+INSERT INTO npc_spellclick_spells VALUES (28605, 52263, 12680, 1, 12680, 3);
+INSERT INTO npc_spellclick_spells VALUES (28606, 52263, 12680, 1, 12680, 3);
+INSERT INTO npc_spellclick_spells VALUES (28607, 52263, 12680, 1, 12680, 3);
+DELETE FROM creature_template_addon WHERE entry IN (28605,28606,28607);
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (28605, 0, 0, 1, 0, 0, 123, '', '');
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (28606, 0, 0, 1, 0, 0, 123, '', '');
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (28607, 0, 0, 1, 0, 0, 123, '', '');
+
+/*Quest Going Bearback*/
+DELETE FROM npc_spellclick_spells WHERE npc_entry in (29598);
+INSERT INTO npc_spellclick_spells VALUES (29598, 54908, 12851, 1, 12851, 1);
+DELETE FROM creature_template_addon WHERE entry IN (29598);
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (29598, 0, 0, 1, 0, 0, 308, '', '');
+DELETE FROM vehicle_data WHERE entry in (308);
+INSERT INTO `vehicle_data` VALUES ('308', '24', '54897', '54907', '0', '0', '0', '0', '0', '0', '0', '0', '0');
+REPLACE INTO vehicle_seat_data VALUES (2699, 3);
+
+/*Mamonth*/
+DELETE FROM creature_template_addon WHERE entry in (32633,32640);
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (32633, 0, 0, 1, 0, 0, 312, '', '');
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (32640, 0, 0, 1, 0, 0, 312, '', '');
+DELETE FROM vehicle_data WHERE entry in (312);
+
+/*Massacre At Light's Point*/
+UPDATE `creature_template` SET `minhealth` = 26140, `maxhealth` = 26140, `dynamicflags` = 0, `minmana` = 2117, `maxmana` = 2117, `unit_flags` = 772, `minlevel` = 55, `maxlevel` = 55, `unk16` = 10, `unk17` = 1, `InhabitType` = 3, `scale` = 1, `mindmg` = 685, `maxdmg` = 715, `armor` = 3232, `attackpower` = 214, `unit_class` = 2, `type` = 10 WHERE `entry` = 28833;
+UPDATE `creature_template` SET `minhealth` = 26140, `maxhealth` = 26140, `dynamicflags` = 0, `minmana` = 0, `maxmana` = 0, `unit_flags` = 772, `minlevel` = 55, `maxlevel` = 55, `unk16` = 10, `unk17` = 1, `InhabitType` = 3, `scale` = 1, `mindmg` = 685, `maxdmg` = 715, `armor` = 3232, `attackpower` = 214, `unit_class` = 2, `type` = 10 WHERE `entry` = 28887;
+
+DELETE FROM creature_addon WHERE guid IN (SELECT guid FROM creature WHERE id IN (28887,28833));
+DELETE FROM vehicle_data WHERE entry in (68);
+INSERT INTO `vehicle_data` VALUES ('68', '24', '52435', '52576', '52588', '0', '0', '0', '0', '0', '0', '0', '0');
+DELETE FROM vehicle_seat_data WHERE seat in (1301);
+INSERT INTO `vehicle_seat_data` VALUES ('1301', '3');
+INSERT INTO `npc_spellclick_spells` VALUES ('28833', '52447', '12701', '1', '12701', '1');
+INSERT INTO `npc_spellclick_spells` VALUES ('28887', '52447', '12701', '1', '12701', '1');
+
+DELETE FROM creature_template_addon WHERE entry IN (28887,28833);
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (28887, 0, 0, 2049, 0, 0, 68, '', '');
+INSERT INTO creature_template_addon (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `vehicle_id`, `passengers`, `auras`) VALUES (28833, 0, 0, 2049, 0, 0, 68, '', '');
+
+
+
+/*Traveler's Tundra Mammoth */
+REPLACE INTO npc_spellclick_spells VALUES (32633, 52196, 0, 0, 0, 0);
+REPLACE INTO creature_template_addon VALUES (32633, 0, 0, 0, 0, 0, 312, NULL, NULL);
+REPLACE INTO vehicle_data VALUES (312, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+/* Grand Ice Mammoth */
+REPLACE INTO npc_spellclick_spells VALUES (31857, 52196, 0, 0, 0, 0);
+REPLACE INTO creature_template_addon VALUES (31857, 0, 0, 0, 0, 0, 312, NULL, NULL);
+
+/* Salvaged Chopper */
+REPLACE INTO npc_spellclick_spells VALUES (33062, 52196, 0, 0, 0, 0);
+REPLACE INTO creature_template_addon VALUES (33062, 0, 0, 0, 0, 0, 335, NULL, NULL);
+REPLACE INTO vehicle_data VALUES (335, 12, 62974, 62286, 62299, 64660, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (3005, 1);
+
+/* Salvaged Demolisher */
+REPLACE INTO npc_spellclick_spells VALUES (33109, 52196, 0, 0, 0, 0);
+REPLACE INTO creature_template_addon VALUES (33109, 0, 0, 0, 0, 0, 338, NULL, NULL);
+REPLACE INTO vehicle_data VALUES (338, 12, 62306, 62490, 62308, 62324, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (3011, 1),(3005, 1),(3004, 2);
+
+/* Salvaged Siege Engine */
+REPLACE INTO npc_spellclick_spells VALUES (33060, 52196, 0, 0, 0, 0);
+REPLACE INTO creature_template_addon VALUES (33060, 0, 0, 0, 0, 0, 336, NULL, NULL);
+REPLACE INTO vehicle_data VALUES (336, 12, 62345, 62522, 62346, 0, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (3006, 1);
+
+/* Wintergrasp Tower Cannon */
+DELETE FROM npc_spellclick_spells WHERE npc_entry IN (28366);
+INSERT INTO npc_spellclick_spells VALUES (28366, 60968, 0, 0, 0, 1);
+REPLACE INTO creature_template_addon VALUES (28366, 0, 0, 0, 0, 0, 160, NULL, NULL);
+REPLACE INTO vehicle_data VALUES (160, 5, 51362, 51421, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (2029, 1);
+
+/* Salvaged Siege Turret */
+DELETE FROM npc_spellclick_spells WHERE npc_entry = 33067;
+INSERT INTO npc_spellclick_spells VALUES (33067, 67373, 0, 0, 0, 1);
+REPLACE INTO creature_template_addon VALUES (33067, 0, 0, 0, 0, 0, 337, NULL, NULL);
+REPLACE INTO vehicle_data VALUES (337, 5, 62358, 64677, 62359, 0, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_data VALUES (336, 4, 62345, 62522, 62346, 0, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (3006, 1),(3010, 1),(4026, 8),(4027, 8),(3009, 8);
+UPDATE `creature_template` SET `minhealth` = 1134000, `maxhealth` = 1134000 WHERE `entry` = 33067;
+UPDATE `creature_template` SET `unit_flags` = 16384 WHERE `entry` = 33067;
+DELETE FROM `creature` WHERE `id`= 33067;
+
+/* Gunner Salvaged Demolisher */
+DELETE FROM npc_spellclick_spells WHERE npc_entry IN (33167);
+INSERT INTO npc_spellclick_spells VALUES (33167, 67373, 0, 0, 0, 1);
+REPLACE INTO creature_template_addon VALUES (33167, 0, 0, 0, 0, 0, 345, NULL, NULL);
+REPLACE INTO vehicle_data VALUES (345, 5, 62634, 64979, 62479, 62471, 0, 62428, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_data VALUES (338, 4, 62306, 62490, 62308, 62324, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (3077, 1),(3106, 8);
+REPLACE INTO vehicle_seat_data VALUES (3011, 1),(3146, 8),(3013, 8),(3147, 8);
+UPDATE `creature_template` SET `unit_flags` = 16384 WHERE `entry` = 33167;
+UPDATE `creature_template` SET `minhealth` = 630000, `maxhealth` = 630000 WHERE `entry` = 33167;
+DELETE FROM `creature` WHERE `id`=33167;
+
+/* Massacre At Light's Point */
+DELETE FROM creature_addon WHERE guid IN (SELECT guid FROM creature WHERE id IN (28887, 28833, 28864));
+DELETE FROM vehicle_data WHERE entry IN (25, 79);
+INSERT INTO vehicle_data VALUES (25, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),(79, 5, 52435, 52576, 52588, 0, 0, 0, 0, 0, 0, 0, 0);
+DELETE FROM vehicle_seat_data WHERE seat IN (1427, 341);
+INSERT INTO vehicle_seat_data VALUES (1427, 1),(341, 1);
+DELETE FROM npc_spellclick_spells WHERE npc_entry IN (28887, 28833, 28864);
+INSERT INTO npc_spellclick_spells VALUES (28833, 52447, 12701, 1, 12701, 1),(28887, 52447, 12701, 1, 12701, 1),(28864, 67373, 0, 0, 0, 1);
+DELETE FROM creature_template_addon WHERE entry IN (28887, 28833, 28864);
+INSERT INTO creature_template_addon VALUES (28887, 0, 0, 2049, 0, 0, 79, '', ''),(28833, 0, 0, 2049, 0, 0, 79, '', ''),(28864,0,0,0,0,0,25,NULL,'61453 0 61453 2');
+
+DELETE FROM creature_template_addon WHERE entry = 28670;
+INSERT INTO creature_template_addon VALUES (28670, 0, 50331648, 1, 0, 1024, 156, NULL, '53112 0 53112 1 53112 2');
+UPDATE creature_template SET InhabitType = 3 WHERE entry = 28670;
+
+/* the Oculus */
+DELETE FROM spell_script_target where entry IN (49460, 49346, 49464);
+DELETE FROM npc_spellclick_spells where npc_entry IN (27755, 27692, 27756);
+DELETE FROM creature_template_addon where entry IN (27755, 27692, 27756);
+/* Amber Drake */
+INSERT INTO spell_script_target VALUES (49460, 1, 27755);
+INSERT INTO npc_spellclick_spells VALUES (27755, 49459, 0, 0, 0, 1);
+INSERT INTO creature_template_addon VALUES (27755, 0, 0, 0, 0, 0, 29, NULL, '53112 0 53112 1');
+REPLACE INTO vehicle_data VALUES (29, 12, 49840, 49838, 49592, 0, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (422, 3);
+/* Emerald Drake */
+INSERT INTO spell_script_target VALUES (49346, 1, 27692);
+INSERT INTO npc_spellclick_spells VALUES (27692, 49427, 0, 0, 0, 1);
+INSERT INTO creature_template_addon VALUES (27692, 0, 0, 0, 0, 0, 39, NULL, '53112 0 53112 1');
+REPLACE INTO vehicle_data VALUES (39, 12, 50328, 50341, 50344, 0, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (662, 3);
+/* Ruby Drake */
+INSERT INTO spell_script_target VALUES (49464, 1, 27756);
+INSERT INTO npc_spellclick_spells VALUES (27756, 49463, 0, 0, 0, 1);
+INSERT INTO creature_template_addon VALUES (27756, 0, 0, 0, 0, 0, 43, NULL, '53112 0 53112 1');
+REPLACE INTO vehicle_data VALUES (43, 12, 50232, 50248, 50240, 0, 0, 0, 0, 0, 0, 0, 0);
+REPLACE INTO vehicle_seat_data VALUES (742, 3);
\ No newline at end of file
diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp
index 2cb7606..2fb5d75 100644
--- a/src/game/AggressorAI.cpp
+++ b/src/game/AggressorAI.cpp
@@ -103,7 +103,7 @@ void AggressorAI::EnterEvadeMode()
//i_tracker.Reset(TIME_INTERVAL_LOOK);
}
- if (!m_creature->isCharmed())
+ if(!m_creature->isCharmed() && !m_creature->GetVehicleGUID())
{
m_creature->RemoveAllAuras();
diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp
index a735417..206da8d 100644
--- a/src/game/BattleGroundMgr.cpp
+++ b/src/game/BattleGroundMgr.cpp
@@ -1345,11 +1345,15 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
*data << (uint32)0x00000001; // count of next fields
*data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
break;
+ case BATTLEGROUND_SA:
+ *data << (uint32)0x00000002; // count of next fields
+ *data << (uint32)((BattleGroundSAScore*)itr->second)->DemolishersDestroyed; // demolishers destroyed
+ *data << (uint32)((BattleGroundSAScore*)itr->second)->GatesDestroyed; // gates destroyed
+ break;
case BATTLEGROUND_NA:
case BATTLEGROUND_BE:
case BATTLEGROUND_AA:
case BATTLEGROUND_RL:
- case BATTLEGROUND_SA: // wotlk
case BATTLEGROUND_DS: // wotlk
case BATTLEGROUND_RV: // wotlk
case BATTLEGROUND_IC: // wotlk
diff --git a/src/game/BattleGroundSA.h b/src/game/BattleGroundSA.h
index 31a3ffa..9324999 100644
--- a/src/game/BattleGroundSA.h
+++ b/src/game/BattleGroundSA.h
@@ -24,8 +24,10 @@ class BattleGround;
class BattleGroundSAScore : public BattleGroundScore
{
public:
- BattleGroundSAScore() {};
+ BattleGroundSAScore(): DemolishersDestroyed(0), GatesDestroyed(0) {};
virtual ~BattleGroundSAScore() {};
+ uint32 DemolishersDestroyed;
+ uint32 GatesDestroyed;
};
class BattleGroundSA : public BattleGround
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index 8dc9148..ee7f905 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -497,6 +497,8 @@ ChatCommand * ChatHandler::getCommandTable()
{ "spell_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL },
{ "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL },
{ "spell_threats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL },
+ { "vehicle_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadVehicleDataCommand, "", NULL },
+ { "vehicle_seat_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadVehicleSeatDataCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
@@ -1815,7 +1817,7 @@ Creature* ChatHandler::getSelectedCreature()
if(!m_session)
return NULL;
- return m_session->GetPlayer()->GetMap()->GetCreatureOrPetOrVehicle(m_session->GetPlayer()->GetSelection());
+ return ObjectAccessor::GetCreatureOrPetOrVehicle(*m_session->GetPlayer(),m_session->GetPlayer()->GetSelection());
}
char* ChatHandler::extractKeyFromLink(char* text, char const* linkType, char** something1)
diff --git a/src/game/Chat.h b/src/game/Chat.h
index b82899e..daa5170 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -405,6 +405,8 @@ class ChatHandler
bool HandleReloadSpellTargetPositionCommand(const char* args);
bool HandleReloadSpellThreatsCommand(const char* args);
bool HandleReloadSpellPetAurasCommand(const char* args);
+ bool HandleReloadVehicleDataCommand(const char* args);
+ bool HandleReloadVehicleSeatDataCommand(const char* args);
bool HandleResetAchievementsCommand(const char * args);
bool HandleResetAllCommand(const char * args);
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp
index ee759fd..be296fa 100644
--- a/src/game/Creature.cpp
+++ b/src/game/Creature.cpp
@@ -43,6 +43,7 @@
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
+#include "Vehicle.h"
// apply implementation of the singletons
#include "Policies/SingletonImp.h"
@@ -1129,7 +1130,7 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 team, const
}
m_originalEntry = Entry;
- Object::_Create(guidlow, Entry, HIGHGUID_UNIT);
+ Object::_Create(guidlow, Entry, HIGHGUID_UNIT);
if (!UpdateEntry(Entry, team, data, false))
return false;
@@ -1351,6 +1352,8 @@ void Creature::setDeathState(DeathState s)
}
Unit::setDeathState(CORPSE);
+ if(isVehicle())
+ ((Vehicle*)this)->Die();
}
if (s == JUST_ALIVED)
{
@@ -1454,6 +1457,32 @@ bool Creature::IsImmunedToSpellEffect(SpellEntry const* spellInfo, SpellEffectIn
return true;
}
+ // Heal immunity
+ if (isVehicle() && !(((Vehicle*)this)->GetVehicleFlags() & VF_CAN_BE_HEALED))
+ {
+ switch(spellInfo->Effect[index])
+ {
+ case SPELL_EFFECT_APPLY_AURA:
+ switch(spellInfo->EffectApplyAuraName[index])
+ {
+ case SPELL_AURA_PERIODIC_HEAL:
+ case SPELL_AURA_OBS_MOD_HEALTH:
+ case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
+ case SPELL_AURA_MOD_REGEN:
+ return true;
+ default: break;
+ }
+ break;
+ case SPELL_EFFECT_HEAL:
+ case SPELL_EFFECT_HEAL_MAX_HEALTH:
+ // NOTE : this too?
+ case SPELL_EFFECT_HEAL_MECHANICAL:
+ case SPELL_EFFECT_HEAL_PCT:
+ return true;
+ default : break;
+ }
+ }
+
return Unit::IsImmunedToSpellEffect(spellInfo, index);
}
@@ -1977,6 +2006,29 @@ bool Creature::IsInEvadeMode() const
return !i_motionMaster.empty() && i_motionMaster.GetCurrentMovementGeneratorType() == HOME_MOTION_TYPE;
}
+float Creature::GetBaseSpeed() const
+{
+ if( isPet() )
+ {
+ switch( ((Pet*)this)->getPetType() )
+ {
+ case SUMMON_PET:
+ case HUNTER_PET:
+ {
+ //fixed speed fur hunter (and summon!?) pets
+ return 1.15;
+ }
+ case GUARDIAN_PET:
+ case MINI_PET:
+ {
+ //speed of CreatureInfo for guardian- and minipets
+ break;
+ }
+ }
+ }
+ return m_creatureInfo->speed_run;
+}
+
bool Creature::HasSpell(uint32 spellID) const
{
uint8 i;
diff --git a/src/game/Creature.h b/src/game/Creature.h
index 23d47e5..89e4514 100644
--- a/src/game/Creature.h
+++ b/src/game/Creature.h
@@ -212,6 +212,15 @@ struct CreatureDataAddonAura
SpellEffectIndex effect_idx;
};
+struct CreatureDataAddonPassengers
+{
+ CreatureDataAddonPassengers() : entry(0), guid(0), seat_idx(-1) {}
+
+ uint32 entry;
+ uint32 guid;
+ int8 seat_idx;
+};
+
// from `creature_addon` table
struct CreatureDataAddon
{
@@ -220,7 +229,9 @@ struct CreatureDataAddon
uint32 bytes1;
uint32 bytes2;
uint32 emote;
- uint32 splineFlags;
+ uint32 splineFlags;
+ uint32 vehicle_id;
+ CreatureDataAddonPassengers const* passengers; // loaded as char* "entry1 seatid1 entry2 seatid2 ... "
CreatureDataAddonAura const* auras; // loaded as char* "spell1 eff1 spell2 eff2 ... "
};
@@ -400,6 +411,9 @@ class MANGOS_DLL_SPEC Creature : public Unit
void GetRespawnCoord(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
uint32 GetEquipmentId() const { return m_equipmentId; }
+ bool CreateVehicleKit(uint32 id);
+ Vehicle *GetVehicleKit()const { return m_vehicleKit; }
+
CreatureSubtype GetSubtype() const { return m_subtype; }
bool isPet() const { return m_subtype == CREATURE_SUBTYPE_PET; }
bool isVehicle() const { return m_subtype == CREATURE_SUBTYPE_VEHICLE; }
@@ -570,6 +584,7 @@ class MANGOS_DLL_SPEC Creature : public Unit
MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
+ float GetBaseSpeed() const;
// for use only in LoadHelper, Map::Add Map::CreatureCellRelocation
Cell const& GetCurrentCell() const { return m_currentCell; }
@@ -681,7 +696,7 @@ class MANGOS_DLL_SPEC Creature : public Unit
float CombatStartX;
float CombatStartY;
float CombatStartZ;
-
+ Vehicle* m_vehicleKit;
float m_summonXpoint;
float m_summonYpoint;
float m_summonZpoint;
diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp
index 33cb568..f14bf62 100644
--- a/src/game/CreatureAI.cpp
+++ b/src/game/CreatureAI.cpp
@@ -26,6 +26,10 @@ CreatureAI::~CreatureAI()
void CreatureAI::AttackedBy( Unit* attacker )
{
+ // vehicle dont have threat list, so this is unnecessary, because it calls move chase
+ if(m_creature->isVehicle())
+ return;
+
if(!m_creature->getVictim())
AttackStart(attacker);
}
diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp
index 87eb1fe..5b5dfbc 100644
--- a/src/game/CreatureAISelector.cpp
+++ b/src/game/CreatureAISelector.cpp
@@ -47,7 +47,7 @@ namespace FactorySelector
// excplicit check for isControlled() and owner type to allow guardian, mini-pets and pets controlled by NPCs to be scripted by EventAI
Unit *owner=NULL;
if ((creature->isPet() && ((Pet*)creature)->isControlled() &&
- ((owner=creature->GetOwner()) && owner->GetTypeId()==TYPEID_PLAYER)) || creature->isCharmed())
+ ((owner=creature->GetOwner()) && owner->GetTypeId()==TYPEID_PLAYER)) || (creature->isCharmed() && !creature->isVehicle()))
ai_factory = ai_registry.GetRegistryItem("PetAI");
else if (creature->isTotem())
ai_factory = ai_registry.GetRegistryItem("TotemAI");
diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp
index 65cfedd..4ab3f69 100644
--- a/src/game/CreatureEventAI.cpp
+++ b/src/game/CreatureEventAI.cpp
@@ -847,6 +847,7 @@ void CreatureEventAI::JustReachedHome()
void CreatureEventAI::EnterEvadeMode()
{
+ m_creature->ExitVehicle();
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop(true);
diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h
index 07d40a2..185a726 100644
--- a/src/game/DBCStructure.h
+++ b/src/game/DBCStructure.h
@@ -1725,7 +1725,7 @@ struct VehicleEntry
uint32 m_uiLocomotionType; // 34
float m_msslTrgtImpactTexRadius; // 35
uint32 m_uiSeatIndicatorType; // 36
- // 37, new in 3.1
+ uint32 m_powerType; // 37, new in 3.1 // 37, new in 3.1
// 38, new in 3.1
// 39, new in 3.1
};
@@ -1779,6 +1779,8 @@ struct VehicleSeatEntry
int32 m_uiSkin; // 44
uint32 m_flagsB; // 45
// 46-57 added in 3.1, floats mostly
+
+ bool IsUsable() const { return m_flags & 0x2000000; }
};
struct WMOAreaTableEntry
diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h
index 3538095..ff83d03 100644
--- a/src/game/DBCfmt.h
+++ b/src/game/DBCfmt.h
@@ -104,7 +104,7 @@ const char TaxiNodesEntryfmt[]="nifffssssssssssssssssxii";
const char TaxiPathEntryfmt[]="niii";
const char TaxiPathNodeEntryfmt[]="diiifffiiii";
const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
-const char VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifixxx";
+const char VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifiixx";
const char VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx";
const char WMOAreaTableEntryfmt[]="niiixxxxxiixxxxxxxxxxxxxxxxx";
const char WorldMapAreaEntryfmt[]="xinxffffixx";
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
index 0834d18..94580b0 100644
--- a/src/game/GameObject.cpp
+++ b/src/game/GameObject.cpp
@@ -418,11 +418,7 @@ void GameObject::Update(uint32 /*p_time*/)
if(!m_respawnDelayTime)
return;
- if(!m_spawnedByDefault)
- {
- m_respawnTime = 0;
- return;
- }
+ m_respawnTime = m_spawnedByDefault ? time(NULL) + m_respawnDelayTime : 0;
// since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless
m_respawnTime = time(NULL) + m_respawnDelayTime;
@@ -1515,6 +1511,18 @@ bool GameObject::IsFriendlyTo(Unit const* unit) const
// common faction based case (GvC,GvP)
return tester_faction->IsFriendlyTo(*target_faction);
}
+void GameObject::DealSiegeDamage(uint32 damage)
+{
+ m_actualHealth -= damage;
+
+ // TODO : there are a lot of thinghts to do here
+ if(m_actualHealth < 0)
+ {
+ m_actualHealth = GetGOInfo()->destructibleBuilding.intactNumHits;
+ SetLootState(GO_JUST_DEACTIVATED);
+ }
+}
+
float GameObject::GetObjectBoundingRadius() const
{
@@ -1525,4 +1533,4 @@ float GameObject::GetObjectBoundingRadius() const
return fabs(dispEntry->unknown12) * GetObjectScale();
return DEFAULT_WORLD_OBJECT_SIZE;
-}
\ No newline at end of file
+}
diff --git a/src/game/GameObject.h b/src/game/GameObject.h
index d7a9ee6..d77b23a 100644
--- a/src/game/GameObject.h
+++ b/src/game/GameObject.h
@@ -706,12 +706,14 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
GridReference<GameObject> &GetGridRef() { return m_gridRef; }
uint64 GetRotation() const { return m_rotation; }
+ void DealSiegeDamage(uint32 damage);
protected:
uint32 m_spellId;
time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),
uint32 m_respawnDelayTime; // (secs) if 0 then current GO state no dependent from timer
LootState m_lootState;
bool m_spawnedByDefault;
+ int32 m_actualHealth; // current health state
time_t m_cooldownTime; // used as internal reaction delay time store (not state change reaction).
// For traps this: spell casting cooldown, for doors/buttons: reset time.
std::list<uint32> m_SkillupList;
diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp
index da6aa90..d0d360d 100644
--- a/src/game/GridNotifiers.cpp
+++ b/src/game/GridNotifiers.cpp
@@ -92,7 +92,12 @@ VisibleNotifier::Notify()
{
// target aura duration for caster show only if target exist at caster client
if ((*vItr) != &player && (*vItr)->isType(TYPEMASK_UNIT))
+ {
player.SendAurasForTarget((Unit*)(*vItr));
+ WorldPacket data;
+ ((Unit*)(*vItr))->BuildHeartBeatMsg(&data);
+ player.GetSession()->SendPacket(&data);
+ }
// non finished movements show to player
if ((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive())
diff --git a/src/game/Group.h b/src/game/Group.h
index ea8d737..eef86a7 100644
--- a/src/game/Group.h
+++ b/src/game/Group.h
@@ -115,7 +115,8 @@ enum GroupUpdateFlags
GROUP_UPDATE_FLAG_PET_AURAS = 0x00040000, // uint64 mask, for each bit set uint32 spellid + uint8 unk, pet auras...
GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00080000, // uint32 vehicle_seat_id (index from VehicleSeat.dbc)
GROUP_UPDATE_PET = 0x0007FC00, // all pet flags
- GROUP_UPDATE_FULL = 0x0007FFFF, // all known flags
+ GROUP_UPDATE_VEHICLE = 0x000FFC00, // all vehicle flags
+ GROUP_UPDATE_FULL = 0x000FFFFF, // all known flags
};
#define GROUP_UPDATE_FLAGS_COUNT 20
diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp
index d73b233..46f7897 100644
--- a/src/game/GroupHandler.cpp
+++ b/src/game/GroupHandler.cpp
@@ -28,6 +28,7 @@
#include "Group.h"
#include "SocialMgr.h"
#include "Util.h"
+#include "Vehicle.h"
/* differeces from off:
-you can uninvite yourself - is is useful
@@ -711,7 +712,7 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacke
}
}
- Pet *pet = player->GetPet();
+ Unit *pet = player->GetCharmOrPet();
if (mask & GROUP_UPDATE_FLAG_PET_GUID)
{
if(pet)
@@ -794,6 +795,11 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacke
else
*data << uint64(0);
}
+
+ if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT)
+ {
+ *data << (uint32) player->m_movementInfo.GetTransportDBCSeat();
+ }
}
/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/
@@ -815,7 +821,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
return;
}
- Pet *pet = player->GetPet();
+ Unit *pet = player->GetCharmOrPet();
WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8);
data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related
@@ -823,7 +829,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF
if(pet)
- mask1 = 0x7FFFFFFF; // for hunters and other classes with pets
+ mask1 = 0xFFFFFFFF; // for hunters and other classes with pets
Powers powerType = player->getPowerType();
data << uint32(mask1); // group update mask
@@ -877,6 +883,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data )
}
}
data.put<uint64>(petMaskPos, petauramask); // GROUP_UPDATE_FLAG_PET_AURAS
+ data << (uint32) player->m_movementInfo.GetTransportDBCSeat();
}
else
{
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index d3bcbb8..e4a1142 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -74,6 +74,9 @@ bool ChatHandler::HandleReloadAllCommand(const char*)
HandleReloadReservedNameCommand("");
HandleReloadMangosStringCommand("");
HandleReloadGameTeleCommand("");
+
+ HandleReloadVehicleDataCommand("");
+ HandleReloadVehicleSeatDataCommand("");
return true;
}
@@ -891,6 +894,22 @@ bool ChatHandler::HandleReloadMailLevelRewardCommand(const char* /*arg*/)
return true;
}
+bool ChatHandler::HandleReloadVehicleDataCommand(const char*)
+{
+ sLog.outString( "Re-Loading `vehicle_data` Table!" );
+ sObjectMgr.LoadVehicleData();
+ SendGlobalSysMessage("DB table `vehicle_data` reloaded.");
+ return true;
+}
+
+bool ChatHandler::HandleReloadVehicleSeatDataCommand(const char*)
+{
+ sLog.outString( "Re-Loading `vehicle_seat_data` Table!" );
+ sObjectMgr.LoadVehicleSeatData();
+ SendGlobalSysMessage("DB table `vehicle_seat_data` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleLoadScriptsCommand(const char* args)
{
if(!LoadScriptingModule(args)) return true;
diff --git a/src/game/Map.h b/src/game/Map.h
index c798c61..f28acb4 100644
--- a/src/game/Map.h
+++ b/src/game/Map.h
@@ -38,7 +38,6 @@
#include <bitset>
#include <list>
-class Creature;
class Unit;
class WorldPacket;
class InstanceData;
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index b4ddc71..643ee61 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -267,6 +267,7 @@ void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
//Can not logout if...
if( GetPlayer()->isInCombat() || //...is in combat
GetPlayer()->duel || //...is in Duel
+ GetPlayer()->GetVehicleGUID() || //...is in vehicle
//...is jumping ...is falling
GetPlayer()->m_movementInfo.HasMovementFlag(MovementFlags(MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR)))
{
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp
index c637664..b3f98d2 100644
--- a/src/game/MovementHandler.cpp
+++ b/src/game/MovementHandler.cpp
@@ -248,7 +248,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
}
/* handle special cases */
- if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT))
+ if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT) && !mover->GetVehicleGUID())
{
// transports size limited
// (also received at zeppelin/lift leave by some reason with t_* as absolute in continent coordinates, can be safely skipped)
@@ -296,6 +296,17 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
// now client not include swimming flag in case jumping under water
plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) );
}
+ if (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING))
+ {
+ if(mover->GetTypeId() == TYPEID_UNIT)
+ {
+ if(((Creature*)mover)->isVehicle() && !((Creature*)mover)->canSwim())
+ {
+ // NOTE : we should enter evade mode here, but...
+ ((Vehicle*)mover)->SetSpawnDuration(1);
+ }
+ }
+ }
/*----------------------*/
@@ -354,7 +365,11 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
else // creature charmed
{
if(mover->IsInWorld())
+ {
mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o);
+ if(((Creature*)mover)->isVehicle())
+ ((Vehicle*)mover)->RellocatePassengers(mover->GetMap());
+ }
}
}
@@ -480,18 +495,124 @@ void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data)
recv_data >> guid.ReadAsPacked();
recv_data >> mi;
- uint64 vehicleGUID = _player->GetCharmGUID();
+ uint64 vehicleGUID = _player->GetVehicleGUID();
+
+ if(!vehicleGUID) // something wrong here...
+ return;
+
+ _player->m_movementInfo = mi;
+
+ if(Vehicle *vehicle = ObjectAccessor::GetVehicle(vehicleGUID))
+ {
+ if(vehicle->GetVehicleFlags() & VF_DESPAWN_AT_LEAVE)
+ vehicle->Dismiss();
+ else
+ _player->ExitVehicle();
+ }
+}
+
+void WorldSession::HandleRequestVehicleExit(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: Recvd CMSG_REQUEST_VEHICLE_EXIT");
+ recv_data.hexlike();
+
+ uint64 vehicleGUID = _player->GetVehicleGUID();
+
+ if(!vehicleGUID) // something wrong here...
+ return;
+
+ if(Vehicle *vehicle = ObjectAccessor::GetVehicle(vehicleGUID))
+ {
+ _player->ExitVehicle();
+ }
+}
+
+void WorldSession::HandleRequestVehicleSwitchSeat(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: Recvd CMSG_REQUEST_VEHICLE_SWITCH_SEAT");
+ recv_data.hexlike();
+
+ uint64 vehicleGUID = _player->GetVehicleGUID();
+
+ if(!vehicleGUID) // something wrong here...
+ return;
+
+ if(Vehicle *vehicle = ObjectAccessor::GetVehicle(vehicleGUID))
+ {
+ ObjectGuid guid;
+ recv_data >> guid.ReadAsPacked();
+
+ int8 seatId = 0;
+ recv_data >> seatId;
+
+ if(!guid.IsEmpty())
+ {
+ if(vehicleGUID != guid.GetRawValue())
+ {
+ if(Vehicle *veh = ObjectAccessor::GetVehicle(guid.GetRawValue()))
+ {
+ if(!_player->IsWithinDistInMap(veh, 10))
+ return;
+
+ if(Vehicle *v = veh->FindFreeSeat(&seatId, false))
+ {
+ vehicle->RemovePassenger(_player);
+ _player->EnterVehicle(v, seatId, false);
+ }
+ }
+ return;
+ }
+ }
+ if(Vehicle *v = vehicle->FindFreeSeat(&seatId, false))
+ {
+ vehicle->RemovePassenger(_player);
+ _player->EnterVehicle(v, seatId, false);
+ }
+ }
+}
+
+void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data)
+{
+ sLog.outDebug("WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE");
+ recv_data.hexlike();
+
+ uint64 vehicleGUID = _player->GetVehicleGUID();
if(!vehicleGUID) // something wrong here...
return;
+ if(recv_data.GetOpcode() == CMSG_REQUEST_VEHICLE_PREV_SEAT)
+ {
+ _player->ChangeSeat(-1, false);
+ return;
+ }
+ else if(recv_data.GetOpcode() == CMSG_REQUEST_VEHICLE_NEXT_SEAT)
+ {
+ _player->ChangeSeat(-1, true);
+ return;
+ }
+
+ ObjectGuid guid, guid2;
+ recv_data >> guid.ReadAsPacked();
+
+ MovementInfo mi;
+ recv_data >> mi;
_player->m_movementInfo = mi;
- // using charm guid, because we don't have vehicle guid...
- if(Vehicle *vehicle = _player->GetMap()->GetVehicle(vehicleGUID))
+ recv_data >> guid2.ReadAsPacked(); //guid of vehicle or of vehicle in target seat
+
+ int8 seatId;
+ recv_data >> seatId;
+
+ if(guid.GetRawValue() == guid2.GetRawValue())
+ _player->ChangeSeat(seatId, false);
+ else if(Vehicle *vehicle = ObjectAccessor::GetVehicle(guid2.GetRawValue()))
{
- // Aura::HandleAuraControlVehicle will call Player::ExitVehicle
- vehicle->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE);
+ if(vehicle->HasEmptySeat(seatId))
+ {
+ _player->ExitVehicle();
+ _player->EnterVehicle(vehicle, seatId);
+ }
}
}
@@ -554,4 +675,4 @@ void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data)
recv_data >> agree;
_player->SummonIfPossible(agree);
-}
+}
\ No newline at end of file
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index 8386721..32a60fd 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -289,6 +289,9 @@ void Object::BuildMovementUpdate(ByteBuffer * data, uint16 updateFlags) const
}
}
}
+ if(unit->GetVehicleGUID())
+ unit->m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
+
}
break;
case TYPEID_PLAYER:
@@ -303,6 +306,8 @@ void Object::BuildMovementUpdate(ByteBuffer * data, uint16 updateFlags) const
// remove unknown, unused etc flags for now
player->m_movementInfo.RemoveMovementFlag(MOVEFLAG_SPLINE_ENABLED);
+ if(((Unit*)this)->GetVehicleGUID())
+ player->m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
if(player->isInFlight())
{
ASSERT(player->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
@@ -1113,7 +1118,11 @@ void WorldObject::Relocate(float x, float y, float z, float orientation)
m_orientation = orientation;
if(isType(TYPEMASK_UNIT))
+ {
((Unit*)this)->m_movementInfo.ChangePosition(x, y, z, orientation);
+ if(((Creature*)this)->isVehicle() && IsInWorld())
+ ((Vehicle*)this)->RellocatePassengers(GetMap());
+ }
}
void WorldObject::Relocate(float x, float y, float z)
@@ -1123,7 +1132,11 @@ void WorldObject::Relocate(float x, float y, float z)
m_positionZ = z;
if(isType(TYPEMASK_UNIT))
+ {
((Unit*)this)->m_movementInfo.ChangePosition(x, y, z, GetOrientation());
+ if(((Creature*)this)->isVehicle() && IsInWorld())
+ ((Vehicle*)this)->RellocatePassengers(GetMap());
+ }
}
uint32 WorldObject::GetZoneId() const
@@ -1665,6 +1678,42 @@ Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, floa
return pCreature;
}
+Vehicle* WorldObject::SummonVehicle(uint32 id, float x, float y, float z, float ang, uint32 vehicleId)
+{
+ Vehicle *v = new Vehicle;
+
+ Map *map = GetMap();
+ uint32 team = 0;
+ if (GetTypeId()==TYPEID_PLAYER)
+ team = ((Player*)this)->GetTeam();
+
+ if(!v->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_VEHICLE), map, GetPhaseMask(), id, vehicleId, team))
+ {
+ delete v;
+ return NULL;
+ }
+
+ if (x == 0.0f && y == 0.0f && z == 0.0f)
+ GetClosePoint(x, y, z, v->GetObjectSize());
+
+ v->Relocate(x, y, z, ang);
+
+ if(!v->IsPositionValid())
+ {
+ sLog.outError("ERROR: Vehicle (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
+ v->GetGUIDLow(), v->GetEntry(), v->GetPositionX(), v->GetPositionY());
+ delete v;
+ return NULL;
+ }
+ map->Add((Creature*)v);
+ v->AIM_Initialize();
+
+ if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->AI())
+ ((Creature*)this)->AI()->JustSummoned((Creature*)v);
+
+ return v;
+}
+
namespace MaNGOS
{
class NearUsedPosDo
diff --git a/src/game/Object.h b/src/game/Object.h
index c900e4d..ac1aa7d 100644
--- a/src/game/Object.h
+++ b/src/game/Object.h
@@ -71,6 +71,7 @@ class Unit;
class Map;
class UpdateMask;
class InstanceData;
+class Vehicle;
typedef UNORDERED_MAP<Player*, UpdateData> UpdateDataMapType;
@@ -490,6 +491,9 @@ class MANGOS_DLL_SPEC WorldObject : public Object
bool isActiveObject() const { return m_isActiveObject || m_viewPoint.hasViewers(); }
ViewPoint& GetViewPoint() { return m_viewPoint; }
+
+ Vehicle* SummonVehicle(uint32 id, float x, float y, float z, float ang, uint32 vehicleId = NULL);
+
protected:
explicit WorldObject();
diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp
index 2d39db4..0ecd27b 100644
--- a/src/game/ObjectAccessor.cpp
+++ b/src/game/ObjectAccessor.cpp
@@ -54,6 +54,21 @@ ObjectAccessor::~ObjectAccessor()
}
}
+Creature*
+ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const &u, ObjectGuid guid)
+{
+ if(guid.IsPlayer() || !u.IsInWorld())
+ return NULL;
+
+ if(guid.IsPet())
+ return u.GetMap()->GetPet(guid);
+
+ if(guid.IsVehicle())
+ return u.GetMap()->GetVehicle(guid);
+
+ return u.GetMap()->GetCreature(guid);
+}
+
Unit*
ObjectAccessor::GetUnit(WorldObject const &u, ObjectGuid guid)
{
@@ -63,10 +78,7 @@ ObjectAccessor::GetUnit(WorldObject const &u, ObjectGuid guid)
if(guid.IsPlayer())
return FindPlayer(guid);
- if (!u.IsInWorld())
- return NULL;
-
- return u.GetMap()->GetCreatureOrPetOrVehicle(guid);
+ return GetCreatureOrPetOrVehicle(u, guid);
}
Corpse* ObjectAccessor::GetCorpseInMap(ObjectGuid guid, uint32 mapid)
diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h
index 3caed16..8061ed2 100644
--- a/src/game/ObjectAccessor.h
+++ b/src/game/ObjectAccessor.h
@@ -39,6 +39,7 @@
class Creature;
class Unit;
class GameObject;
+class Vehicle;
class WorldObject;
class Map;
@@ -99,12 +100,20 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor,
// global (obj used for map only location local guid objects (pets currently)
static Unit* GetUnitInWorld(WorldObject const& obj, ObjectGuid guid);
- // FIXME: map local object with global search
+ // map local object with global search
static Creature* GetCreatureInWorld(ObjectGuid guid) { return FindHelper<Creature>(guid); }
static GameObject* GetGameObjectInWorld(ObjectGuid guid) { return FindHelper<GameObject>(guid); }
+ static Pet* GetGameObjectInWorld(uint64 guid, Pet* /*fake*/) { return FindHelper<Pet>(guid); }
+ static Vehicle* GetGameObjectInWorld(uint64 guid, Vehicle* /*fake*/) { return FindHelper<Vehicle>(guid); }
// possible local search for specific object map
static Unit* GetUnit(WorldObject const &, ObjectGuid guid);
+ static Creature* GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid guid);
+ //static Player* GetPlayer(Unit const &, uint64 guid) { return FindPlayer(guid); }
+ //static Corpse* GetCorpse(WorldObject const &u, uint64 guid);
+ //static Pet* GetPet(uint64 guid) { return GetObjectInWorld(guid, (Pet*)NULL); }
+ static Vehicle* GetVehicle(uint64 guid) { return GetGameObjectInWorld(guid, (Vehicle*)NULL); }
+ //static Player* FindPlayer(uint64);
// Player access
static Player* FindPlayer(ObjectGuid guid);
@@ -176,6 +185,9 @@ inline Unit* ObjectAccessor::GetUnitInWorld(WorldObject const& obj, ObjectGuid g
if (guid.IsPet())
return obj.IsInWorld() ? obj.GetMap()->GetPet(guid) : NULL;
+ if (guid.IsVehicle())
+ return obj.IsInWorld() ? ((Unit*)obj.GetMap()->GetVehicle(guid)) : NULL;
+
return GetCreatureInWorld(guid);
}
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 2aa9bb1..b6b3899 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -834,6 +834,93 @@ void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const*
endAura.effect_idx = EFFECT_INDEX_0;
}
+void ObjectMgr::ConvertCreatureAddonPassengers(CreatureDataAddon* addon, char const* table, char const* guidEntryStr)
+{
+ // Now add the passengers, format "creature_entry/guid seatindex creature_entry/guid seatindex..."
+ char *p,*s;
+ std::vector<int> val;
+ s=p=(char*)reinterpret_cast<char const*>(addon->passengers);
+ if(p)
+ {
+ while (p[0]!=0)
+ {
+ ++p;
+ if (p[0]==' ')
+ {
+ val.push_back(atoi(s));
+ s=++p;
+ }
+ }
+ if (p!=s)
+ val.push_back(atoi(s));
+
+ // free char* loaded memory
+ delete[] (char*)reinterpret_cast<char const*>(addon->passengers);
+
+ // wrong list
+ if (val.size()%2)
+ {
+ addon->auras = NULL;
+ sLog.outErrorDb("Creature (%s: %u) has wrong `passengers` data in `%s`.",guidEntryStr,addon->guidOrEntry,table);
+ return;
+ }
+ }
+
+ // empty list
+ if(val.empty())
+ {
+ addon->passengers = NULL;
+ return;
+ }
+
+ // replace by new structures array
+ const_cast<CreatureDataAddonPassengers*&>(addon->passengers) = new CreatureDataAddonPassengers[val.size()/2+1];
+
+ int i=0;
+ for(int j=0;j<val.size()/2;++j)
+ {
+ CreatureDataAddonPassengers& cPas = const_cast<CreatureDataAddonPassengers&>(addon->passengers[i]);
+ if(guidEntryStr == "Entry")
+ cPas.entry = (uint32)val[2*j+0];
+ else
+ cPas.guid = (uint32)val[2*j+0];
+ cPas.seat_idx = (int8)val[2*j+1];
+ if ( cPas.seat_idx > 7 )
+ {
+ sLog.outErrorDb("Creature (%s: %u) has wrong seat %u for creature %u in `passengers` field in `%s`.",guidEntryStr,addon->guidOrEntry,cPas.seat_idx,cPas.entry,table);
+ continue;
+ }
+ if(cPas.entry == 0 && cPas.guid == 0)
+ {
+ sLog.outErrorDb("Creature (%s: %u) has NULL creature entry/guid in `passengers` field in `%s`.",guidEntryStr,addon->guidOrEntry,table);
+ continue;
+ }
+ if(cPas.entry > 0)
+ {
+ if(!sCreatureStorage.LookupEntry<CreatureInfo>(cPas.entry))
+ {
+ sLog.outErrorDb("Creature (%s: %u) has wrong creature entry/guid %u `passengers` field in `%s`.",guidEntryStr,addon->guidOrEntry,cPas.entry,table);
+ continue;
+ }
+ }
+ else
+ {
+ if(mCreatureDataMap.find(cPas.guid)==mCreatureDataMap.end())
+ {
+ sLog.outErrorDb("Creature (%s: %u) has wrong creature entry/guid %u `passengers` field in `%s`.",guidEntryStr,addon->guidOrEntry,cPas.guid,table);
+ continue;
+ }
+ }
+ ++i;
+ }
+
+ // fill terminator element (after last added)
+ CreatureDataAddonPassengers& endPassenger = const_cast<CreatureDataAddonPassengers&>(addon->passengers[i]);
+ endPassenger.entry = 0;
+ endPassenger.guid = 0;
+ endPassenger.seat_idx = -1;
+}
+
void ObjectMgr::LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment)
{
creatureaddons.Load();
@@ -870,6 +957,7 @@ void ObjectMgr::LoadCreatureAddons(SQLStorage& creatureaddons, char const* entry
}
ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), creatureaddons.GetTableName(), entryName);
+ ConvertCreatureAddonPassengers(const_cast<CreatureDataAddon*>(addon), creatureaddons.GetTableName(), entryName);
}
}
@@ -5905,6 +5993,8 @@ uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh)
return m_ItemGuids.Generate();
case HIGHGUID_UNIT:
return m_CreatureGuids.Generate();
+ case HIGHGUID_VEHICLE:
+ return m_VehicleGuids.Generate();
case HIGHGUID_PLAYER:
return m_CharGuids.Generate();
case HIGHGUID_GAMEOBJECT:
@@ -8704,6 +8794,126 @@ CreatureInfo const* GetCreatureTemplateStore(uint32 entry)
return sCreatureStorage.LookupEntry<CreatureInfo>(entry);
}
+void ObjectMgr::LoadVehicleData()
+{
+ mVehicleData.clear();
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry, flags, Spell1, Spell2, Spell3, Spell4, Spell5, Spell6, Spell7, Spell8, Spell9, Spell10, req_aura FROM vehicle_data");
+ if(!result)
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded 0 vehicle data" );
+ sLog.outErrorDb("`vehicle_data` table is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ bar.step();
+
+ Field* fields = result->Fetch();
+
+ VehicleDataStructure VDS;
+ // NOTE : we can use spellid or creature id
+ uint32 v_entry = fields[0].GetUInt32();
+ VDS.v_flags = fields[1].GetUInt32();
+ for(uint8 j = 0; j < MAX_VEHICLE_SPELLS; j++)
+ {
+ VDS.v_spells[j] = fields[j+2].GetUInt32();
+ }
+ VDS.req_aura = fields[12].GetUInt32();
+
+ VehicleEntry const *vehicleInfo = sVehicleStore.LookupEntry(v_entry);
+ if(!vehicleInfo)
+ {
+ sLog.outErrorDb("Vehicle id %u listed in `vehicle_data` does not exist",v_entry);
+ continue;
+ }
+ for(uint8 j = 0; j < MAX_VEHICLE_SPELLS; j++)
+ {
+ if(VDS.v_spells[j])
+ {
+ SpellEntry const* j_spell = sSpellStore.LookupEntry(VDS.v_spells[j]);
+ if(!j_spell)
+ {
+ sLog.outErrorDb("Spell %u listed in `vehicle_data` does not exist, skipped",VDS.v_spells[j]);
+ VDS.v_spells[j] = 0;
+ }
+ }
+ }
+ if(VDS.req_aura)
+ {
+ SpellEntry const* i_spell = sSpellStore.LookupEntry(VDS.req_aura);
+ if(!i_spell)
+ {
+ sLog.outErrorDb("Spell %u listed in `vehicle_data` does not exist, skipped",VDS.req_aura);
+ VDS.req_aura = 0;
+ }
+ }
+
+ mVehicleData[v_entry] = VDS;
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u vehicle data", count );
+}
+
+void ObjectMgr::LoadVehicleSeatData()
+{
+ mVehicleSeatData.clear();
+
+ QueryResult *result = WorldDatabase.Query("SELECT seat,flags FROM vehicle_seat_data");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded 0 vehicle seat data" );
+ sLog.outErrorDb("`vehicle_seat_data` table is empty!");
+ return;
+ }
+ uint32 count = 0;
+
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+ uint32 entry = fields[0].GetUInt32();
+ uint32 flag = fields[1].GetUInt32();
+
+ VehicleSeatEntry const *vsInfo = sVehicleSeatStore.LookupEntry(entry);
+ if(!vsInfo)
+ {
+ sLog.outErrorDb("Vehicle seat %u listed in `vehicle_seat_data` does not exist",entry);
+ continue;
+ }
+
+ mVehicleSeatData[entry] = flag;
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u vehicle seat data", count );
+}
+
Quest const* GetQuestTemplateStore(uint32 entry)
{
return sObjectMgr.GetQuestTemplate(entry);
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index 78b79b9..579221d 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -419,6 +419,8 @@ extern LanguageDesc lang_description[LANGUAGES_COUNT];
MANGOS_DLL_SPEC LanguageDesc const* GetLanguageDescByID(uint32 lang);
class PlayerDumpReader;
+// vehicle system
+#define MAX_VEHICLE_SPELLS 6
template<typename T>
class IdGenerator
@@ -438,6 +440,16 @@ class IdGenerator
T m_nextGuid;
};
+struct VehicleDataStructure
+{
+ uint32 v_flags; // vehicle flags, see enum CustomVehicleFLags
+ uint32 v_spells[MAX_VEHICLE_SPELLS]; // spells
+ uint32 req_aura; // requieres aura on player to enter (eg. in wintergrasp)
+};
+
+typedef UNORDERED_MAP<uint32, VehicleDataStructure> VehicleDataMap;
+typedef std::map<uint32,uint32> VehicleSeatDataMap;
+
class ObjectMgr
{
friend class PlayerDumpReader;
@@ -702,6 +714,9 @@ class ObjectMgr
void LoadVendors();
void LoadTrainerSpell();
+ void LoadVehicleData();
+ void LoadVehicleSeatData();
+
std::string GeneratePetName(uint32 entry);
uint32 GetBaseXP(uint32 level) const;
uint32 GetXPForLevel(uint32 level) const;
@@ -950,6 +965,24 @@ class ObjectMgr
int GetOrNewIndexForLocale(LocaleConstant loc);
+ VehicleDataMap mVehicleData;
+ VehicleSeatDataMap mVehicleSeatData;
+
+ uint32 GetSeatFlags(uint32 seatid)
+ {
+ VehicleSeatDataMap::iterator i = mVehicleSeatData.find(seatid);
+ if(i == mVehicleSeatData.end())
+ return NULL;
+ else
+ return i->second;
+ }
+ VehicleDataStructure const* GetVehicleData(uint32 entry) const
+ {
+ VehicleDataMap::const_iterator itr = mVehicleData.find(entry);
+ if(itr==mVehicleData.end()) return NULL;
+ return &itr->second;
+ }
+
SpellClickInfoMapBounds GetSpellClickInfoMapBounds(uint32 creature_id) const
{
return SpellClickInfoMapBounds(mSpellClickInfoMap.lower_bound(creature_id),mSpellClickInfoMap.upper_bound(creature_id));
@@ -987,6 +1020,7 @@ class ObjectMgr
ObjectGuidGenerator<HIGHGUID_ITEM> m_ItemGuids;
ObjectGuidGenerator<HIGHGUID_GAMEOBJECT> m_GameobjectGuids;
ObjectGuidGenerator<HIGHGUID_CORPSE> m_CorpseGuids;
+ ObjectGuidGenerator<HIGHGUID_VEHICLE> m_VehicleGuids;
QuestMap mQuestTemplates;
@@ -1040,6 +1074,7 @@ class ObjectMgr
void CheckScriptTexts(ScriptMapMap const& scripts,std::set<int32>& ids);
void LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment);
void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr);
+ void ConvertCreatureAddonPassengers(CreatureDataAddon* addon, char const* table, char const* guidEntryStr);
void LoadQuestRelationsHelper(QuestRelations& map,char const* table);
MailLevelRewardMap m_mailLevelRewardMap;
diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp
index 6c26ded..41ceeb1 100644
--- a/src/game/Opcodes.cpp
+++ b/src/game/Opcodes.cpp
@@ -1168,10 +1168,10 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x473*/ { "CMSG_CHAR_CUSTOMIZE", STATUS_AUTHED, &WorldSession::HandleCharCustomize },
/*0x474*/ { "SMSG_CHAR_CUSTOMIZE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x475*/ { "SMSG_PET_RENAMEABLE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x476*/ { "CMSG_REQUEST_VEHICLE_EXIT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x477*/ { "CMSG_REQUEST_VEHICLE_PREV_SEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x478*/ { "CMSG_REQUEST_VEHICLE_NEXT_SEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x479*/ { "CMSG_REQUEST_VEHICLE_SWITCH_SEAT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x476*/ { "CMSG_REQUEST_VEHICLE_EXIT", STATUS_LOGGEDIN, &WorldSession::HandleRequestVehicleExit },
+ /*0x477*/ { "CMSG_REQUEST_VEHICLE_PREV_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle},
+ /*0x478*/ { "CMSG_REQUEST_VEHICLE_NEXT_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle},
+ /*0x479*/ { "CMSG_REQUEST_VEHICLE_SWITCH_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleRequestVehicleSwitchSeat },
/*0x47A*/ { "CMSG_PET_LEARN_TALENT", STATUS_LOGGEDIN, &WorldSession::HandlePetLearnTalent },
/*0x47B*/ { "CMSG_PET_UNLEARN_TALENTS", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x47C*/ { "SMSG_SET_PHASE_SHIFT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
@@ -1205,7 +1205,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x498*/ { "SMSG_SERVER_FIRST_ACHIEVEMENT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x499*/ { "SMSG_PET_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x49A*/ { "SMSG_PET_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
- /*0x49B*/ { "CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x49B*/ { "CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle},
/*0x49C*/ { "CMSG_HEARTH_AND_RESURRECT", STATUS_LOGGEDIN, &WorldSession::HandleHearthandResurrect },
/*0x49D*/ { "SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x49E*/ { "SMSG_CRITERIA_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide },
diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp
index 45339c5..52c41d3 100644
--- a/src/game/Pet.cpp
+++ b/src/game/Pet.cpp
@@ -39,7 +39,7 @@ char const* petTypeSuffix[MAX_PET_TYPE] =
Pet::Pet(PetType type) :
Creature(CREATURE_SUBTYPE_PET), m_removed(false), m_petType(type), m_happinessTimer(7500), m_duration(0), m_resetTalentsCost(0),
-m_bonusdamage(0), m_resetTalentsTime(0), m_usedTalentCount(0), m_auraUpdateMask(0), m_loading(false),
+m_bonusdamage(0), m_resetTalentsTime(0), m_usedTalentCount(0), m_loading(false),
m_declinedname(NULL), m_petModeFlags(PET_MODE_DEFAULT)
{
m_name = "Pet";
diff --git a/src/game/Pet.h b/src/game/Pet.h
index efc9ecd..5d7417a 100644
--- a/src/game/Pet.h
+++ b/src/game/Pet.h
@@ -236,10 +236,6 @@ class Pet : public Creature
time_t m_resetTalentsTime;
uint32 m_usedTalentCount;
- const uint64& GetAuraUpdateMask() const { return m_auraUpdateMask; }
- void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); }
- void ResetAuraUpdateMask() { m_auraUpdateMask = 0; }
-
// overwrite Creature function for name localization back to WorldObject version without localization
const char* GetNameForLocaleIdx(int32 locale_idx) const { return WorldObject::GetNameForLocaleIdx(locale_idx); }
@@ -251,7 +247,6 @@ class Pet : public Creature
PetType m_petType;
int32 m_duration; // time until unsummon (used mostly for summoned guardians and not used for controlled pets)
int32 m_bonusdamage;
- uint64 m_auraUpdateMask;
bool m_loading;
DeclinedName *m_declinedname;
diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp
index 57356b3..1a855da 100644
--- a/src/game/PetHandler.cpp
+++ b/src/game/PetHandler.cpp
@@ -286,7 +286,7 @@ void WorldSession::HandlePetNameQuery( WorldPacket & recv_data )
void WorldSession::SendPetNameQuery( uint64 petguid, uint32 petnumber)
{
- Creature* pet = _player->GetMap()->GetCreatureOrPetOrVehicle(petguid);
+ Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid);
if(!pet || !pet->GetCharmInfo() || pet->GetCharmInfo()->GetPetNumber() != petnumber)
return;
@@ -318,7 +318,12 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
recv_data >> petguid;
- Creature* pet = _player->GetMap()->GetCreatureOrPetOrVehicle(petguid);
+ // FIXME: charmed case
+ //Pet* pet = ObjectAccessor::Instance().GetPet(petguid);
+ if(ObjectAccessor::FindPlayer(petguid))
+ return;
+
+ Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid);
if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
{
@@ -506,7 +511,8 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
return;
// pet/charmed
- if (Creature* pet = _player->GetMap()->GetCreatureOrPetOrVehicle(guid))
+ Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
+ if(pet)
{
if(pet->isPet())
{
@@ -560,29 +566,32 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
uint8 state; //1 for on, 0 for off
recvPacket >> guid >> spellid >> state;
- if(!_player->GetPet() && !_player->GetCharm())
+ if (!_player->GetPet() && !_player->GetCharm())
return;
- Creature* pet = _player->GetMap()->GetCreatureOrPetOrVehicle(guid);
+ if(ObjectAccessor::FindPlayer(guid))
+ return;
- if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
+ Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid);
+
+ if (!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
{
sLog.outError( "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
return;
}
// do not add not learned spells/ passive spells
- if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
+ if (!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
return;
CharmInfo *charmInfo = pet->GetCharmInfo();
- if(!charmInfo)
+ if (!charmInfo)
{
sLog.outError("WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
return;
}
- if(pet->isCharmed())
+ if (pet->isCharmed())
//state can be used as boolean
pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state);
else
@@ -594,6 +603,23 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
{
DETAIL_LOG("WORLD: CMSG_PET_CAST_SPELL");
+ recvPacket.hexlike();
+ recvPacket.print_storage();
+
+ //2 - 0 - 0 - 43 - 129 - 0 - 80 - 241 | - 42 - 211 - 253 - 0 | - 0 | - 2 |- 96 - 0 - 0 - 0 | - 0 - 26
+ //- 164 - 59 - 196 - 174 - 98 - 131 | - 194 - 182 - 171 - 218| - 67 - 0 - 48 - 93| - 0 - 196 - 32
+ //- 177| - 242 - 193 - 22 - 110 - 224 - 67 - 203 - 166 | - 68 - 61 - 133 - 1| - 240 - 66 - 1 - 183 |
+ //- 0 - 0 - 0 - 217| - 2 - 43 - 129 - 80 - 241 - 0 - 10 - 0 - 0 - 0 - 0 - 76 - 109 - 175 - 0
+ //- 238 - 115 - 58 - 196 - 20 - 110 - 121 - 194 - 187 - 107 - 217 - 67 - 32 - 44 - 27 - 62 - 217
+ //- 1 - 36 - 129 - 80 - 241 - 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 192 - 233
+ //- 172 - 62 - 4 - 0 - 0 - 0 - 7 - 230 - 0 - 0 - 0 -
+
+ //5 - 0 - 0 - 43 - 129 - 0 - 80 - 241 | - 85 - 211 - 253 - 0 | - 0 | - 2 | - 96 - 0 - 0 - 0 | - 0 - 69 - 60 - 61
+ //- 196 - 171 - 248 - 107| - 194 - 8 - 236 - 218 | - 67 - 0 - 177 - 11 | - 46 - 196 - 89 - 16 | - 14 - 195
+ //- 5 - 38 - 231 - 67 - 23 - 221 | - 110 - 62 - 15 - 3 | - 240 - 66 -| 1 - 183 | - 0 - 0 - 0 - 217 | - 5 - 43
+ //- 129 - 80 - 241 - 0 - 10 - 0 - 0 - 0 - 0 - 233 - 41 - 203 - 0 - 106 - 207 - 59 - 196 - 179 - 173 - 83
+ //- 194 - 8 - 108 - 217 - 67 - 127 - 153 - 170 - 64 - 217 - 4 - 36 - 129 - 80 - 241 - 0 - 0 - 160 - 64
+ //- 0 - 0 - 160 - 64 - 0 - 0 - 160 - 64 - 7 - 77 - 175 - 64 - 4 - 0 - 0 - 0 - 7 - 195 - 0 - 0 - 0 -
uint64 guid;
uint32 spellid;
@@ -607,7 +633,10 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
if (!_player->GetPet() && !_player->GetCharm())
return;
- Creature* pet = _player->GetMap()->GetCreatureOrPetOrVehicle(guid);
+ if (GUID_HIPART(guid) == HIGHGUID_PLAYER)
+ return;
+
+ Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid);
if (!pet || (pet != _player->GetPet() && pet!= _player->GetCharm()))
{
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 4b71715..4f96537 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -465,7 +465,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
// group is initialized in the reference constructor
SetGroupInvite(NULL);
m_groupUpdateMask = 0;
- m_auraUpdateMask = 0;
duel = NULL;
@@ -1755,6 +1754,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
m_transport = NULL;
m_movementInfo.ClearTransportData();
}
+ ExitVehicle();
// The player was ported to another map and looses the duel immediately.
// We have to perform this check before the teleport, otherwise the
@@ -2237,7 +2237,7 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
return NULL;
// exist (we need look pets also for some interaction (quest/etc)
- Creature *unit = GetMap()->GetCreatureOrPetOrVehicle(guid);
+ Creature *unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid);
if (!unit)
return NULL;
@@ -8454,6 +8454,41 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
break;
case 3703: // Shattrath City
break;
+ case 4384: // SA
+ /*if (bg && bg->GetTypeID() == BATTLEGROUND_SA)
+ bg->FillInitialWorldStates(data);
+ else
+ {*/
+ // 1-3 A defend, 4-6 H defend, 7-9 unk defend, 1 - ok, 2 - half destroyed, 3 - destroyed
+ data << uint32(0xf09) << uint32(0x4); // 7 3849 Gate of Temple
+ data << uint32(0xe36) << uint32(0x4); // 8 3638 Gate of Yellow Moon
+ data << uint32(0xe27) << uint32(0x4); // 9 3623 Gate of Green Emerald
+ data << uint32(0xe24) << uint32(0x4); // 10 3620 Gate of Blue Sapphire
+ data << uint32(0xe21) << uint32(0x4); // 11 3617 Gate of Red Sun
+ data << uint32(0xe1e) << uint32(0x4); // 12 3614 Gate of Purple Ametyst
+
+ data << uint32(0xdf3) << uint32(0x0); // 13 3571 bonus timer (1 - on, 0 - off)
+ data << uint32(0xded) << uint32(0x0); // 14 3565 Horde Attacker
+ data << uint32(0xdec) << uint32(0x1); // 15 3564 Alliance Attacker
+ // End Round (timer), better explain this by example, eg. ends in 19:59 -> A:BC
+ data << uint32(0xde9) << uint32(0x9); // 16 3561 C
+ data << uint32(0xde8) << uint32(0x5); // 17 3560 B
+ data << uint32(0xde7) << uint32(0x19); // 18 3559 A
+ data << uint32(0xe35) << uint32(0x1); // 19 3637 East g - Horde control
+ data << uint32(0xe34) << uint32(0x1); // 20 3636 West g - Horde control
+ data << uint32(0xe33) << uint32(0x1); // 21 3635 South g - Horde control
+ data << uint32(0xe32) << uint32(0x0); // 22 3634 East g - Alliance control
+ data << uint32(0xe31) << uint32(0x0); // 23 3633 West g - Alliance control
+ data << uint32(0xe30) << uint32(0x0); // 24 3632 South g - Alliance control
+ data << uint32(0xe2f) << uint32(0x1); // 25 3631 Chamber of Ancients - Horde control
+ data << uint32(0xe2e) << uint32(0x0); // 26 3630 Chamber of Ancients - Alliance control
+ data << uint32(0xe2d) << uint32(0x0); // 27 3629 Beach1 - Horde control
+ data << uint32(0xe2c) << uint32(0x0); // 28 3628 Beach2 - Horde control
+ data << uint32(0xe2b) << uint32(0x1); // 29 3627 Beach1 - Alliance control
+ data << uint32(0xe2a) << uint32(0x1); // 30 3626 Beach2 - Alliance control
+ // and many unks...
+ //}
+ break;
default:
FillInitialWorldState(data,count, 0x914, 0x0); // 7
FillInitialWorldState(data,count, 0x913, 0x0); // 8
@@ -13064,7 +13099,8 @@ void Player::PrepareQuestMenu( uint64 guid )
QuestRelations* pObjectQIR;
// pets also can have quests
- if (Creature *pCreature = GetMap()->GetCreatureOrPetOrVehicle(guid))
+ Creature *pCreature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, guid);
+ if( pCreature )
{
pObject = (Object*)pCreature;
pObjectQR = &sObjectMgr.mCreatureQuestRelations;
@@ -13158,7 +13194,8 @@ void Player::SendPreparedQuest(uint64 guid)
std::string title = "";
// need pet case for some quests
- if (Creature *pCreature = GetMap()->GetCreatureOrPetOrVehicle(guid))
+ Creature *pCreature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid);
+ if (pCreature)
{
uint32 textid = GetGossipTextId(pCreature);
@@ -13231,7 +13268,8 @@ Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest )
QuestRelations* pObjectQR;
QuestRelations* pObjectQIR;
- if (Creature *pCreature = GetMap()->GetCreatureOrPetOrVehicle(guid))
+ Creature *pCreature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid);
+ if( pCreature )
{
pObject = (Object*)pCreature;
pObjectQR = &sObjectMgr.mCreatureQuestRelations;
@@ -18183,7 +18221,12 @@ void Player::HandleStealthedUnitsDetection()
// target aura duration for caster show only if target exist at caster client
// send data at target visibility change (adding to client)
if((*i)!=this && (*i)->isType(TYPEMASK_UNIT))
+ {
SendAurasForTarget(*i);
+ WorldPacket data;
+ (*i)->BuildHeartBeatMsg(&data);
+ GetSession()->SendPacket(&data);
+ }
}
}
else
@@ -18218,7 +18261,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
if(npc)
{
// not let cheating with start flight mounted
- if(IsMounted())
+ if(IsMounted() || GetVehicleGUID())
{
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
data << uint32(ERR_TAXIPLAYERALREADYMOUNTED);
@@ -18247,6 +18290,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
else
{
RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+ ExitVehicle();
if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW )
RemoveAurasDueToSpell(m_ShapeShiftFormSpellId);
@@ -19366,7 +19410,12 @@ void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* targe
// target aura duration for caster show only if target exist at caster client
// send data at target visibility change (adding to client)
if(target!=this && target->isType(TYPEMASK_UNIT))
+ {
SendAurasForTarget((Unit*)target);
+ WorldPacket data;
+ ((Unit*)target)->BuildHeartBeatMsg(&data);
+ GetSession()->SendPacket(&data);
+ }
if(target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isAlive())
((Creature*)target)->SendMonsterMoveWithSpeedToCurrentDestination(this);
@@ -19431,13 +19480,22 @@ void Player::InitPrimaryProfessions()
void Player::SendComboPoints()
{
Unit *combotarget = ObjectAccessor::GetUnit(*this, m_comboTarget);
- if (combotarget)
- {
- WorldPacket data(SMSG_UPDATE_COMBO_POINTS, combotarget->GetPackGUID().size()+1);
- data << combotarget->GetPackGUID();
- data << uint8(m_comboPoints);
- GetSession()->SendPacket(&data);
- }
+ if (!combotarget)
+ return;
+
+ WorldPacket data;
+ if(!GetVehicleGUID())
+ data.Initialize(SMSG_UPDATE_COMBO_POINTS, combotarget->GetPackGUID().size()+1);
+ else{
+ if(Unit *vehicle = ObjectAccessor::GetUnit(*this, GetVehicleGUID()))
+ {
+ data.Initialize(SMSG_PET_UPDATE_COMBO_POINTS, vehicle->GetPackGUID().size()+combotarget->GetPackGUID().size()+1);
+ data << vehicle->GetPackGUID();
+ }else return;
+ }
+ data << combotarget->GetPackGUID();
+ data << uint8(m_comboPoints);
+ GetSession()->SendPacket(&data);
}
void Player::AddComboPoints(Unit* target, int8 count)
@@ -19560,6 +19618,13 @@ void Player::SendInitialPacketsBeforeAddToMap()
void Player::SendInitialPacketsAfterAddToMap()
{
+ if(getClass() == CLASS_DEATH_KNIGHT)
+ ResyncRunes(MAX_RUNES);
+
+ WorldPacket data0(SMSG_SET_PHASE_SHIFT, 4);
+ data0 << uint32(GetPhaseMask());
+ GetSession()->SendPacket(&data0);
+
// update zone
uint32 newzone, newarea;
GetZoneAndAreaId(newzone,newarea);
@@ -19598,6 +19663,14 @@ void Player::SendInitialPacketsAfterAddToMap()
SendMessageToSet(&data2,true);
}
+ if(GetVehicleGUID())
+ {
+ WorldPacket data3(SMSG_FORCE_MOVE_ROOT, 10);
+ data3 << GetPackGUID();
+ data3 << (uint32)((m_movementInfo.GetVehicleSeatFlags() & SF_CAN_CAST) ? 2 : 0);
+ SendMessageToSet(&data3,true);
+ }
+
SendAurasForTarget(this);
SendEnchantmentDurations(); // must be after add to map
SendItemDurations(); // must be after add to map
@@ -19612,7 +19685,7 @@ void Player::SendUpdateToOutOfRangeGroupMembers()
m_groupUpdateMask = GROUP_UPDATE_FLAG_NONE;
m_auraUpdateMask = 0;
- if(Pet *pet = GetPet())
+ if(Unit *pet = GetCharmOrPet())
pet->ResetAuraUpdateMask();
}
@@ -20057,7 +20130,7 @@ void Player::UpdateForQuestWorldObjects()
}
else if (itr->IsCreatureOrVehicle())
{
- Creature *obj = GetMap()->GetCreatureOrPetOrVehicle(*itr);
+ Creature *obj = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, *itr);
if(!obj)
continue;
@@ -20329,8 +20402,8 @@ void Player::RewardSinglePlayerAtKill(Unit* pVictim)
// honor can be in PvP and !PvP (racial leader) cases
RewardHonor(pVictim,1);
- // xp and reputation only in !PvP case
- if(!PvP)
+ // xp and reputation only in !PvP case and not in vehicle
+ if(!PvP && !(GetVehicleGUID() && (m_movementInfo.GetVehicleFlags() & VF_GIVE_EXP)))
{
RewardReputation(pVictim,1);
GiveXP(xp, pVictim);
@@ -20830,26 +20903,16 @@ void Player::ApplyGlyphs(bool apply)
ApplyGlyph(i,apply);
}
-void Player::EnterVehicle(Vehicle *vehicle)
+void Player::SendEnterVehicle(Vehicle *vehicle)
{
- VehicleEntry const *ve = sVehicleStore.LookupEntry(vehicle->GetVehicleId());
- if(!ve)
- return;
-
- VehicleSeatEntry const *veSeat = sVehicleSeatStore.LookupEntry(ve->m_seatID[0]);
- if(!veSeat)
- return;
-
- vehicle->SetCharmerGUID(GetGUID());
- vehicle->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- vehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
- vehicle->setFaction(getFaction());
-
- SetCharm(vehicle); // charm
- m_camera.SetView(vehicle); // set view
-
- SetClientControl(vehicle, 1); // redirect controls to vehicle
- SetMover(vehicle);
+ if(m_transport) // if we were on a transport, leave
+ {
+ m_transport->RemovePassenger(this);
+ m_transport = NULL;
+ }
+ // vehicle is our transport from now, if we get to zeppelin or boat
+ // with vehicle, ONLY my vehicle will be passenger on that transport
+ // player ----> vehicle ----> zeppelin
WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
GetSession()->SendPacket(&data);
@@ -20866,60 +20929,20 @@ void Player::EnterVehicle(Vehicle *vehicle)
data << vehicle->GetOrientation(); // o
// transport part, TODO: load/calculate seat offsets
data << uint64(vehicle->GetGUID()); // transport guid
- data << float(veSeat->m_attachmentOffsetX); // transport offsetX
- data << float(veSeat->m_attachmentOffsetY); // transport offsetY
- data << float(veSeat->m_attachmentOffsetZ); // transport offsetZ
- data << float(0); // transport orientation
+ data << float(m_movementInfo.GetTransportPos()->x); // transport offsetX
+ data << float(m_movementInfo.GetTransportPos()->y); // transport offsetY
+ data << float(m_movementInfo.GetTransportPos()->z); // transport offsetZ
+ data << float(m_movementInfo.GetTransportPos()->o); // transport orientation
data << uint32(getMSTime()); // transport time
data << uint8(0); // seat
// end of transport part
data << uint32(0); // fall time
GetSession()->SendPacket(&data);
- data.Initialize(SMSG_PET_SPELLS, 8+2+4+4+4*MAX_UNIT_ACTION_BAR_INDEX+1+1);
- data << uint64(vehicle->GetGUID());
- data << uint16(0);
- data << uint32(0);
- data << uint32(0x00000101);
-
- for(uint32 i = 0; i < 10; ++i)
- data << uint16(0) << uint8(0) << uint8(i+8);
-
- data << uint8(0);
- data << uint8(0);
- GetSession()->SendPacket(&data);
-}
-
-void Player::ExitVehicle(Vehicle *vehicle)
-{
- vehicle->SetCharmerGUID(0);
- vehicle->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- vehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
- vehicle->setFaction((GetTeam() == ALLIANCE) ? vehicle->GetCreatureInfo()->faction_A : vehicle->GetCreatureInfo()->faction_H);
-
- SetCharm(NULL);
- m_camera.ResetView();
-
- SetClientControl(vehicle, 0);
- SetMover(NULL);
-
- WorldPacket data(MSG_MOVE_TELEPORT_ACK, 30);
- data << GetPackGUID();
- data << uint32(0); // counter?
- data << uint32(MOVEFLAG_ROOT); // fly unk
- data << uint16(MOVEFLAG2_UNK4); // special flags
- data << uint32(getMSTime()); // time
- data << vehicle->GetPositionX(); // x
- data << vehicle->GetPositionY(); // y
- data << vehicle->GetPositionZ(); // z
- data << vehicle->GetOrientation(); // o
- data << uint32(0); // fall time
- GetSession()->SendPacket(&data);
-
- RemovePetActionBar();
-
- // maybe called at dummy aura remove?
- // CastSpell(this, 45472, true); // Parachute
+ /*data.Initialize(SMSG_UNKNOWN_1191, 12);
+ data << uint64(GetGUID());
+ data << uint64(vehicle->GetVehicleId()); // not sure
+ SendMessageToSet(&data, true);*/
}
bool Player::isTotalImmune()
@@ -20984,7 +21007,8 @@ void Player::ConvertRune(uint8 index, RuneType newType)
void Player::ResyncRunes(uint8 count)
{
- WorldPacket data(SMSG_RESYNC_RUNES, count * 2);
+ WorldPacket data(SMSG_RESYNC_RUNES, 4 + count * 2);
+ data << uint32(count + 1);
for(uint32 i = 0; i < count; ++i)
{
data << uint8(GetCurrentRune(i)); // rune type
diff --git a/src/game/Player.h b/src/game/Player.h
index f7b0afa..e4a2da1 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -2194,6 +2194,7 @@ class MANGOS_DLL_SPEC Player : public Unit
/*********************************************************/
bool HasMovementFlag(MovementFlags f) const; // for script access to m_movementInfo.HasMovementFlag
void UpdateFallInformationIfNeed(MovementInfo const& minfo,uint16 opcode);
+
void SetFallInformation(uint32 time, float z)
{
m_lastFallTime = time;
@@ -2215,8 +2216,8 @@ class MANGOS_DLL_SPEC Player : public Unit
Unit* GetMover() const { return m_mover; }
bool IsSelfMover() const { return m_mover == this; }// normal case for player not controlling other unit
- void EnterVehicle(Vehicle *vehicle);
- void ExitVehicle(Vehicle *vehicle);
+ // vehicle system
+ void SendEnterVehicle(Vehicle *vehicle);
ObjectGuid const& GetFarSightGuid() const { return GetGuidValue(PLAYER_FARSIGHT); }
@@ -2319,8 +2320,6 @@ class MANGOS_DLL_SPEC Player : public Unit
uint8 GetSubGroup() const { return m_group.getSubGroup(); }
uint32 GetGroupUpdateFlag() const { return m_groupUpdateMask; }
void SetGroupUpdateFlag(uint32 flag) { m_groupUpdateMask |= flag; }
- const uint64& GetAuraUpdateMask() const { return m_auraUpdateMask; }
- void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); }
Player* GetNextRandomRaidMember(float radius);
PartyResult CanUninviteFromGroup() const;
// BattleGround Group System
@@ -2571,7 +2570,6 @@ class MANGOS_DLL_SPEC Player : public Unit
GroupReference m_originalGroup;
Group *m_groupInvite;
uint32 m_groupUpdateMask;
- uint64 m_auraUpdateMask;
uint64 m_miniPet;
diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp
index a0b7872..b8c9374 100644
--- a/src/game/QuestHandler.cpp
+++ b/src/game/QuestHandler.cpp
@@ -659,9 +659,8 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket
if (itr->IsCreatureOrPet())
{
// need also pet quests case support
- Creature *questgiver = GetPlayer()->GetMap()->GetCreatureOrPetOrVehicle(*itr);
-
- if (!questgiver || questgiver->IsHostileTo(_player))
+ Creature *questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(),*itr);
+ if(!questgiver || questgiver->IsHostileTo(_player))
continue;
if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER))
diff --git a/src/game/ReactorAI.cpp b/src/game/ReactorAI.cpp
index f39cd1a..fd52ee2 100644
--- a/src/game/ReactorAI.cpp
+++ b/src/game/ReactorAI.cpp
@@ -116,6 +116,7 @@ ReactorAI::EnterEvadeMode()
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature stopped attacking, victim %s [guid=%u]", victim->isAlive() ? "out run him" : "is dead", m_creature->GetGUIDLow());
}
+ m_creature->ExitVehicle();
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
i_victimGuid = 0;
diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h
index 3e25e4b..9e8715b 100644
--- a/src/game/SharedDefines.h
+++ b/src/game/SharedDefines.h
@@ -2462,6 +2462,29 @@ enum DiminishingGroup
DIMINISHING_LIMITONLY
};
+
+/* NOTE : vehicles and seats has their own flags in DBC,
+but for now, they are too unknown for us, to use them */
+enum CustomVehicleFLags
+{
+ VF_CANT_MOVE = 0x0001, // vehicle cant move, only turn, maybe handle by some auras?
+ VF_FACTION = 0x0002, // vehicle retain its own faction
+ VF_DESPAWN_NPC = 0x0004, // vehicle will delete npc on spellclick
+ VF_DESPAWN_AT_LEAVE = 0x0008, // vehicle will be deleted when rider leaves
+ VF_CAN_BE_HEALED = 0x0010, // vehicle can be healed
+ VF_GIVE_EXP = 0x0020, // vehicle will give exp for killing enemies
+ VF_MOVEMENT = 0x0040, // vehicle will move on its own, not depending on rider, however rider can cast spells
+ VF_NON_SELECTABLE = 0x0080 // vehicle will be not selectable after rider enter
+ //VF_HAS_FUEL = 0x0100, // TODO : find out what energy type is fuel and implement this
+};
+
+enum CustomVehicleSeatFLags
+{
+ SF_MAIN_RIDER = 0x0001, // the one who controlls vehicle, can also cast spells
+ SF_UNATTACKABLE = 0x0002, // hided inside, and unatackable until vehicle is destroyed
+ SF_CAN_CAST = 0x0004, // player/npc can rotate, and cast OWN spells
+ SF_UNACCESSIBLE = 0x0008 // player cant enter this seat by normal way (only by script)
+};
enum ResponseCodes
{
RESPONSE_SUCCESS = 0x00,
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index 9727b61..f40ee66 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -120,7 +120,8 @@ SpellCastTargets::SpellCastTargets()
m_itemTargetGUID = 0;
m_itemTargetEntry = 0;
- m_srcX = m_srcY = m_srcZ = m_destX = m_destY = m_destZ = 0.0f;
+ m_srcX = m_srcY = m_srcZ = m_srcO = m_destX = m_destY = m_destZ = 0.0f;
+ m_elevation = m_speed = 0.0f;
m_strTarget = "";
m_targetMask = 0;
}
@@ -257,6 +258,19 @@ void SpellCastTargets::read( ByteBuffer& data, Unit *caster )
data >> m_destX >> m_destY >> m_destZ;
if(!MaNGOS::IsValidMapCoord(m_destX, m_destY, m_destZ))
throw ByteBufferException(false, data.rpos(), 0, data.size());
+
+ if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
+ {
+ if(data.rpos() + 4 + 4 <= data.size())
+ {
+ data >> m_elevation >> m_speed;
+ // TODO: should also read
+ m_srcO = caster->GetOrientation();
+ //*data >> uint16 >> uint8 >> uint32 >> uint32;
+ //*data >> float >> float >> float >> float...
+ }
+ }
+
}
if( m_targetMask & TARGET_FLAG_STRING )
@@ -1596,9 +1610,11 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
case TARGET_TOTEM_FIRE:
case TARGET_SELF:
case TARGET_SELF2:
- case TARGET_AREAEFFECT_CUSTOM_2:
+ {
+ // used for targeting gameobjects
targetUnitMap.push_back(m_caster);
break;
+ }
case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA:
{
m_targets.m_targetMask = 0;
@@ -1867,6 +1883,9 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
break;
default:
FillAreaTargets(targetUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_DEST_CENTER, SPELL_TARGETS_AOE_DAMAGE);
+
+ // exclude caster (this can be important if this not original caster, for example vehicle)
+ targetUnitMap.remove(m_caster);
break;
}
break;
@@ -2361,7 +2380,13 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
case TARGET_DYNAMIC_OBJECT_LEFT_SIDE:
case TARGET_DYNAMIC_OBJECT_RIGHT_SIDE:
{
- if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
+ //This should be targeting of destructible objects by vehicles (ram spells...)
+ if(m_spellInfo->EffectImplicitTargetB[effIndex] == TARGET_AREAEFFECT_CUSTOM_2)
+ {
+ //FIXME
+ break;
+ }
+ else if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
{
float angle = m_caster->GetOrientation();
switch(targetMode)
@@ -3347,7 +3372,7 @@ void Spell::finish(bool ok)
m_caster->resetAttackTimer(RANGED_ATTACK);*/
// Clear combo at finish state
- if(m_caster->GetTypeId() == TYPEID_PLAYER && NeedsComboPoints(m_spellInfo))
+ if((m_caster->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_caster)->isVehicle()) && NeedsComboPoints(m_spellInfo))
{
// Not drop combopoints if negative spell and if any miss on enemy exist
bool needDrop = true;
@@ -3366,7 +3391,12 @@ void Spell::finish(bool ok)
}
}
if (needDrop)
- ((Player*)m_caster)->ClearComboPoints();
+ {
+ if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)m_caster)->ClearComboPoints();
+ else
+ ((Player*)m_caster->GetCharmer())->ClearComboPoints();
+ }
}
// potions disabled by client, send event "not in combat" if need
@@ -4560,11 +4590,16 @@ SpellCastResult Spell::CheckCast(bool strict)
return locRes;
// not let players cast spells at mount (and let do it to creatures)
- if (m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell &&
+ if ((m_caster->IsMounted() || m_caster->GetVehicleGUID()) && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell &&
!IsPassiveSpell(m_spellInfo) && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_MOUNTED))
{
if (m_caster->isInFlight())
return SPELL_FAILED_NOT_ON_TAXI;
+ else if(m_caster->GetVehicleGUID())
+ {
+ if(!(m_caster->m_movementInfo.GetVehicleSeatFlags() & SF_CAN_CAST))
+ return SPELL_FAILED_NOT_MOUNTED;
+ }
else
return SPELL_FAILED_NOT_MOUNTED;
}
@@ -5384,33 +5419,48 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
if(!_target->isAlive())
return SPELL_FAILED_BAD_TARGETS;
- if(IsPositiveSpell(m_spellInfo->Id))
- {
- if(m_caster->IsHostileTo(_target))
- return SPELL_FAILED_BAD_TARGETS;
- }
- else
- {
- bool duelvsplayertar = false;
- for(int j = 0; j < MAX_EFFECT_INDEX; ++j)
- {
- //TARGET_DUELVSPLAYER is positive AND negative
- duelvsplayertar |= (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DUELVSPLAYER);
- }
- if(m_caster->IsFriendlyTo(target) && !duelvsplayertar)
- {
- return SPELL_FAILED_BAD_TARGETS;
- }
- }
+ if(!IsValidSingleTargetSpell(_target))
+ return SPELL_FAILED_BAD_TARGETS;
}
//cooldown
if(((Creature*)m_caster)->HasSpellCooldown(m_spellInfo->Id))
return SPELL_FAILED_NOT_READY;
}
+ // NOTE : this is done twice, also in spell->prepare(&(spell->m_targets));
return CheckCast(true);
}
+bool Spell::IsValidSingleTargetEffect(Unit const* target, Targets type) const
+{
+ switch(type)
+ {
+ case TARGET_CHAIN_DAMAGE:
+ return !m_caster->IsFriendlyTo(target);
+ case TARGET_SINGLE_FRIEND:
+ case TARGET_AREAEFFECT_PARTY:
+ return m_caster->IsFriendlyTo(target);
+ case TARGET_SINGLE_PARTY:
+ return m_caster != target && m_caster->IsInPartyWith(target);
+ case TARGET_SINGLE_FRIEND_2:
+ return m_caster->IsInRaidWith(target);
+ }
+ return true;
+}
+
+bool Spell::IsValidSingleTargetSpell(Unit const* target) const
+{
+ for(int i = 0; i < 3; ++i)
+ {
+ if(!IsValidSingleTargetEffect(target, Targets(m_spellInfo->EffectImplicitTargetA[i])))
+ return false;
+ // Need to check B?
+ //if(!IsValidSingleTargetEffect(m_spellInfo->EffectImplicitTargetB[i], target)
+ // return false;
+ }
+ return true;
+}
+
SpellCastResult Spell::CheckCasterAuras() const
{
// Flag drop spells totally immuned to caster auras
diff --git a/src/game/Spell.h b/src/game/Spell.h
index 2db96b1..b80ad5f 100644
--- a/src/game/Spell.h
+++ b/src/game/Spell.h
@@ -166,8 +166,9 @@ class SpellCastTargets
void Update(Unit* caster);
- float m_srcX, m_srcY, m_srcZ;
+ float m_srcX, m_srcY, m_srcZ, m_srcO;
float m_destX, m_destY, m_destZ;
+ float m_elevation, m_speed;
std::string m_strTarget;
uint32 m_targetMask;
@@ -342,6 +343,8 @@ class Spell
void EffectPlayMusic(SpellEffectIndex eff_idx);
void EffectSpecCount(SpellEffectIndex eff_idx);
void EffectActivateSpec(SpellEffectIndex eff_idx);
+ void EffectSummonVehicle(SpellEffectIndex eff_idx);
+ void EffectDamageBuilding(SpellEffectIndex eff_idx);
Spell( Unit* caster, SpellEntry const *info, bool triggered, ObjectGuid originalCasterGUID = ObjectGuid(), Spell** triggeringContainer = NULL );
~Spell();
@@ -357,6 +360,8 @@ class Spell
SpellCastResult CheckCast(bool strict);
SpellCastResult CheckPetCast(Unit* target);
+ bool IsValidSingleTargetEffect(Unit const* target, Targets type) const;
+ bool IsValidSingleTargetSpell(Unit const* target) const;
// handlers
void handle_immediate();
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 5ff4944..eae5df1 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -3282,7 +3282,7 @@ void Aura::HandleModPossess(bool apply, bool Real)
{
((Creature*)target)->AIM_Initialize();
}
- else if(target->GetTypeId() == TYPEID_PLAYER)
+ else if(target->GetTypeId() == TYPEID_PLAYER && !target->GetVehicleGUID())
{
((Player*)target)->SetClientControl(target, 0);
}
@@ -3313,7 +3313,7 @@ void Aura::HandleModPossess(bool apply, bool Real)
target->SetCharmerGUID(0);
- if(target->GetTypeId() == TYPEID_PLAYER)
+ if(target->GetTypeId() == TYPEID_PLAYER && !target->GetVehicleGUID())
{
((Player*)target)->setFactionForRace(target->getRace());
((Player*)target)->SetClientControl(target, 1);
@@ -3595,10 +3595,13 @@ void Aura::HandleAuraModStun(bool apply, bool Real)
target->SetStandState(UNIT_STAND_STATE_STAND);// in 1.5 client
}
- WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
- data << target->GetPackGUID();
- data << uint32(0);
- target->SendMessageToSet(&data, true);
+ if(!m_target->hasUnitState(UNIT_STAT_ON_VEHICLE))
+ {
+ WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
+ data << target->GetPackGUID();
+ data << uint32(0);
+ target->SendMessageToSet(&data,true);
+ }
// Summon the Naj'entus Spine GameObject on target if spell is Impaling Spine
if(GetId() == 39837)
@@ -3648,7 +3651,7 @@ void Aura::HandleAuraModStun(bool apply, bool Real)
target->clearUnitState(UNIT_STAT_STUNNED);
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
- if(!target->hasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect
+ if(!target->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_ON_VEHICLE)) // prevent allow move if have also root effect
{
if(target->getVictim() && target->isAlive())
target->SetTargetGUID(target->getVictim()->GetGUID());
@@ -3876,11 +3879,13 @@ void Aura::HandleAuraModRoot(bool apply, bool Real)
if(target->GetTypeId() == TYPEID_PLAYER)
{
- WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
- data << target->GetPackGUID();
- data << (uint32)2;
- target->SendMessageToSet(&data, true);
-
+ if(!target->hasUnitState(UNIT_STAT_ON_VEHICLE))
+ {
+ WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
+ data << target->GetPackGUID();
+ data << (uint32)2;
+ target->SendMessageToSet(&data,true);
+ }
//Clear unit movement flags
((Player*)target)->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
}
@@ -3918,7 +3923,7 @@ void Aura::HandleAuraModRoot(bool apply, bool Real)
target->clearUnitState(UNIT_STAT_ROOT);
- if(!target->hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect
+ if(!target->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ON_VEHICLE)) // prevent allow move if have also stun effect
{
if(target->getVictim() && target->isAlive())
target->SetTargetGUID(target->getVictim()->GetGUID());
@@ -3951,7 +3956,7 @@ void Aura::HandleAuraModSilence(bool apply, bool Real)
if(spell->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
// Stop spells on prepare or casting state
target->InterruptSpell(CurrentSpellTypes(i), false);
- }
+ }
else
{
// Real remove called after current aura remove from lists, check if other similar auras active
@@ -7317,32 +7322,40 @@ void Aura::HandleArenaPreparation(bool apply, bool Real)
*/
void Aura::HandleAuraControlVehicle(bool apply, bool Real)
{
- if(!Real)
- return;
+ if(!Real)
+ return;
Unit* target = GetTarget();
+ Unit* caster = GetCaster();
if (target->GetTypeId() != TYPEID_UNIT || !((Creature*)target)->isVehicle())
return;
Vehicle* vehicle = (Vehicle*)target;
- Unit *player = GetCaster();
- if(!player || player->GetTypeId() != TYPEID_PLAYER)
+ if(!caster || !vehicle)
+ return;
+
+ // this can happen due to wrong caster/target spell handling
+ // note : SPELL_AURA_CONTROL_VEHICLE can have EffectImplicitTargetA
+ // TARGET_SCRIPT, TARGET_DUELVSPLAYER.. etc
+ if(caster->GetGUID() == vehicle->GetGUID())
return;
if (apply)
{
- if(Pet *pet = player->GetPet())
- pet->Remove(PET_SAVE_AS_CURRENT);
- ((Player*)player)->EnterVehicle(vehicle);
+ if(caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
+ ((Player*)caster)->GetSession()->SendPacket(&data);
+ }
+ // if we leave and enter again, this will refresh
+ int32 duration = GetSpellMaxDuration(GetSpellProto());
+ if(duration > 0)
+ vehicle->SetSpawnDuration(duration);
}
else
{
- SpellEntry const *spell = GetSpellProto();
-
// some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them
- player->RemoveAurasDueToSpell(spell->Id);
-
- ((Player*)player)->ExitVehicle(vehicle);
+ caster->RemoveAurasDueToSpell(GetId());
}
}
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 28ae6dc..a0c8613 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -57,6 +57,7 @@
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
+#include "Vehicle.h"
pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
{
@@ -147,9 +148,9 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
&Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
&Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
- &Spell::EffectNULL, // 87 SPELL_EFFECT_WMO_DAMAGE (57 spells in 3.3.2)
- &Spell::EffectNULL, // 88 SPELL_EFFECT_WMO_REPAIR (2 spells in 3.3.2)
- &Spell::EffectNULL, // 89 SPELL_EFFECT_WMO_CHANGE (7 spells in 3.3.2)
+ &Spell::EffectDamageBuilding, // 87 SPELL_EFFECT_WMO_DAMAGE
+ &Spell::EffectUnused, // 88 SPELL_EFFECT_WMO_REPAIR
+ &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE
&Spell::EffectKillCreditPersonal, // 90 SPELL_EFFECT_KILL_CREDIT Kill credit but only for single person
&Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
&Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
@@ -3862,7 +3863,7 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
case SUMMON_PROP_TYPE_SIEGE_VEH:
case SUMMON_PROP_TYPE_DRAKE_VEH:
// TODO
- // EffectSummonVehicle(i);
+ EffectSummonVehicle(eff_idx);
break;
default:
sLog.outError("EffectSummonType: Unhandled summon type %u", summon_prop->Type);
@@ -3891,7 +3892,7 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
case SUMMON_PROP_GROUP_VEHICLE:
{
// TODO
- // EffectSummonVehicle(i);
+ EffectSummonVehicle(eff_idx);
break;
}
default:
@@ -3899,7 +3900,6 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
break;
}
}
-
void Spell::DoSummon(SpellEffectIndex eff_idx)
{
if (m_caster->GetPetGUID())
@@ -6519,13 +6519,15 @@ void Spell::EffectAddComboPoints(SpellEffectIndex /*eff_idx*/)
if(!unitTarget)
return;
- if(m_caster->GetTypeId() != TYPEID_PLAYER)
- return;
-
if(damage <= 0)
return;
- ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ {
+ if(((Creature*)m_caster)->isVehicle())
+ ((Player*)m_caster->GetCharmer())->AddComboPoints(unitTarget, damage);
+ }else
+ ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
}
void Spell::EffectDuel(SpellEffectIndex eff_idx)
@@ -7789,6 +7791,54 @@ void Spell::EffectRenamePet(SpellEffectIndex /*eff_idx*/)
unitTarget->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
}
+void Spell::EffectSummonVehicle(SpellEffectIndex eff_idx)
+{
+ uint32 creature_entry = m_spellInfo->EffectMiscValue[eff_idx];
+ if(!creature_entry)
+ return;
+
+ float px, py, pz;
+ // If dest location if present
+ if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ {
+ // Summon unit in dest location
+ px = m_targets.m_destX;
+ py = m_targets.m_destY;
+ pz = m_targets.m_destZ;
+ }
+ // Summon if dest location not present near caster
+ else
+ m_caster->GetClosePoint(px,py,pz,3.0f);
+
+ Vehicle *v = m_caster->SummonVehicle(creature_entry, px, py, pz, m_caster->GetOrientation());
+ if(!v)
+ return;
+
+ v->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+ v->SetCreatorGUID(m_caster->GetGUID());
+
+ if(damage)
+ {
+ m_caster->CastSpell(v, damage, true);
+ m_caster->EnterVehicle(v, 0);
+ }
+ int32 duration = GetSpellMaxDuration(m_spellInfo);
+ if(duration > 0)
+ v->SetSpawnDuration(duration);
+}
+
+void Spell::EffectDamageBuilding(SpellEffectIndex eff_idx)
+{
+ if(!gameObjTarget)
+ return;
+
+ if(gameObjTarget->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
+ return;
+
+ // NOTE : this can be increased by scaling stat system in vehicles
+ gameObjTarget->DealSiegeDamage(damage);
+}
+
void Spell::EffectPlayMusic(SpellEffectIndex eff_idx)
{
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp
index 41adfd3..ef7cda3 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -27,6 +27,7 @@
#include "Spell.h"
#include "ScriptCalls.h"
#include "Totem.h"
+#include "Vehicle.h"
#include "SpellAuras.h"
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
@@ -320,6 +321,11 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
DEBUG_LOG("WORLD: got cast spell packet, spellId - %u, cast_count: %u, unk_flags %u, data length = %i",
spellId, cast_count, unk_flags, (uint32)recvPacket.size());
+ // vehicle spells are handled by CMSG_PET_CAST_SPELL,
+ // but player is still able to cast own spells
+ if(_player->GetCharmGUID() && _player->GetCharmGUID() == _player->GetVehicleGUID())
+ mover = _player;
+
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
if(!spellInfo)
@@ -486,7 +492,7 @@ void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
return;
}
- Creature* pet = GetPlayer()->GetMap()->GetCreatureOrPetOrVehicle(guid);
+ Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid);
if(!pet)
{
@@ -574,19 +580,67 @@ void WorldSession::HandleSpellClick( WorldPacket & recv_data )
if (_player->isInCombat()) // client prevent click and set different icon at combat state
return;
- Creature *unit = _player->GetMap()->GetCreatureOrPetOrVehicle(guid);
+ Creature *unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
if (!unit || unit->isInCombat()) // client prevent click and set different icon at combat state
return;
- SpellClickInfoMapBounds clickPair = sObjectMgr.GetSpellClickInfoMapBounds(unit->GetEntry());
- for(SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr)
+ if(!_player->IsWithinDistInMap(unit, 10))
+ return;
+
+ // cheater?
+ if(!unit->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_SPELLCLICK))
+ return;
+
+ uint32 vehicleId = 0;
+ CreatureDataAddon const *cainfo = unit->GetCreatureAddon();
+ if(cainfo)
+ vehicleId = cainfo->vehicle_id;
+
+ // handled other (hacky) way to avoid overwriting auras
+ if(vehicleId || unit->isVehicle())
+ {
+ if(!unit->isAlive())
+ return;
+
+ if(_player->GetVehicleGUID())
+ return;
+
+ // create vehicle if no one present and kill the original creature to avoid double, triple etc spawns
+ if(!unit->isVehicle())
+ {
+ Vehicle *v = _player->SummonVehicle(unit->GetEntry(), unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetOrientation(), vehicleId);
+ if(!v)
+ return;
+
+ if(v->GetVehicleFlags() & VF_DESPAWN_NPC)
+ {
+ v->SetSpawnDuration(unit->GetRespawnDelay()*IN_MILLISECONDS);
+ unit->setDeathState(JUST_DIED);
+ unit->RemoveCorpse();
+ unit->SetHealth(0);
+ }
+ unit = v;
+ }
+
+ if(((Vehicle*)unit)->GetVehicleData())
+ if(uint32 r_aura = ((Vehicle*)unit)->GetVehicleData()->req_aura)
+ if(!_player->HasAura(r_aura))
+ return;
+
+ _player->EnterVehicle((Vehicle*)unit, 0);
+ }
+ else
{
- if (itr->second.IsFitToRequirements(_player))
+ SpellClickInfoMapBounds clickPair = sObjectMgr.GetSpellClickInfoMapBounds(unit->GetEntry());
+ for(SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr)
{
- Unit *caster = (itr->second.castFlags & 0x1) ? (Unit*)_player : (Unit*)unit;
- Unit *target = (itr->second.castFlags & 0x2) ? (Unit*)_player : (Unit*)unit;
+ if (itr->second.IsFitToRequirements(_player))
+ {
+ Unit *caster = (itr->second.castFlags & 0x1) ? (Unit*)_player : (Unit*)unit;
+ Unit *target = (itr->second.castFlags & 0x2) ? (Unit*)_player : (Unit*)unit;
- caster->CastSpell(target, itr->second.spellId, true);
+ caster->CastSpell(target, itr->second.spellId, true);
+ }
}
}
}
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index 3bb2b78..ec13a6f 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -46,6 +46,7 @@
#include "CellImpl.h"
#include "Path.h"
#include "Traveller.h"
+#include "Vehicle.h"
#include "VMapFactory.h"
#include "MovementGenerator.h"
@@ -242,6 +243,9 @@ Unit::Unit()
// remove aurastates allowing special moves
for(int i=0; i < MAX_REACTIVE; ++i)
m_reactiveTimer[i] = 0;
+
+ m_auraUpdateMask = 0;
+ m_vehicleGUID = 0;
}
Unit::~Unit()
@@ -411,20 +415,9 @@ void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTim
void Unit::BuildHeartBeatMsg(WorldPacket *data) const
{
- MovementFlags move_flags = GetTypeId()==TYPEID_PLAYER
- ? ((Player const*)this)->m_movementInfo.GetMovementFlags()
- : MOVEFLAG_NONE;
-
- data->Initialize(MSG_MOVE_HEARTBEAT, 32);
+ data->Initialize(MSG_MOVE_HEARTBEAT);
*data << GetPackGUID();
- *data << uint32(move_flags); // movement flags
- *data << uint16(0); // 2.3.0
- *data << uint32(getMSTime()); // time
- *data << float(GetPositionX());
- *data << float(GetPositionY());
- *data << float(GetPositionZ());
- *data << float(GetOrientation());
- *data << uint32(0);
+ ((Unit*)this)->m_movementInfo.Write(*data);
}
void Unit::resetAttackTimer(WeaponAttackType type)
@@ -5097,15 +5090,10 @@ void Unit::setPowerType(Powers new_powertype)
if(((Player*)this)->GetGroup())
((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
}
- else if(((Creature*)this)->isPet())
+ else if(Unit* owner = GetCharmerOrOwner())
{
- Pet *pet = ((Pet*)this);
- if(pet->isControlled())
- {
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
- }
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
}
switch(new_powertype)
@@ -5262,6 +5250,38 @@ bool Unit::IsHostileTo(Unit const* unit) const
return tester_faction->IsHostileTo(*target_faction);
}
+bool Unit::IsInPartyWith(Unit const *unit) const
+{
+ if(this == unit)
+ return true;
+
+ const Unit *u1 = GetCharmerOrOwnerOrSelf();
+ const Unit *u2 = unit->GetCharmerOrOwnerOrSelf();
+ if(u1 == u2)
+ return true;
+
+ if(u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
+ return ((Player*)u1)->IsInSameGroupWith((Player*)u2);
+ else
+ return false;
+}
+
+bool Unit::IsInRaidWith(Unit const *unit) const
+{
+ if(this == unit)
+ return true;
+
+ const Unit *u1 = GetCharmerOrOwnerOrSelf();
+ const Unit *u2 = unit->GetCharmerOrOwnerOrSelf();
+ if(u1 == u2)
+ return true;
+
+ if(u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
+ return ((Player*)u1)->IsInSameRaidWith((Player*)u2);
+ else
+ return false;
+}
+
bool Unit::IsFriendlyTo(Unit const* unit) const
{
// always friendly to self
@@ -5413,6 +5433,14 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
if(GetTypeId()==TYPEID_PLAYER && IsMounted())
return false;
+ // player (also npc?) cannot attack on vehicle
+ if(GetTypeId()==TYPEID_PLAYER && GetVehicleGUID())
+ return false;
+
+ // player (also npc?) cannot attack on vehicle
+ if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isVehicle() && GetCharmerGUID())
+ return false;
+
// nobody can attack GM in GM-mode
if(victim->GetTypeId()==TYPEID_PLAYER)
{
@@ -7974,6 +8002,11 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio)
}
float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus;
+
+ //apply creature's base speed
+ if(GetTypeId() == TYPEID_UNIT)
+ bonus *= ((Creature*)this)->GetBaseSpeed();
+
// now we ready for speed calculation
float speed = main_speed_mod ? bonus*(100.0f + main_speed_mod)/100.0f : bonus;
@@ -8170,6 +8203,7 @@ void Unit::setDeathState(DeathState s)
if (s == JUST_DIED)
{
+ ExitVehicle();
RemoveAllAurasOnDeath();
RemoveGuardians();
UnsummonAllTotems();
@@ -8395,7 +8429,8 @@ bool Unit::SelectHostileTarget()
}
// enter in evade mode in other case
- ((Creature*)this)->AI()->EnterEvadeMode();
+ if(!((Creature*)this)->isVehicle())
+ ((Creature*)this)->AI()->EnterEvadeMode();
return false;
}
@@ -8406,7 +8441,14 @@ bool Unit::SelectHostileTarget()
int32 Unit::CalculateSpellDamage(Unit const* target, SpellEntry const* spellProto, SpellEffectIndex effect_index, int32 const* effBasePoints)
{
- Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
+ Player* unitPlayer;
+
+ if(GetTypeId() == TYPEID_PLAYER)
+ unitPlayer = (Player*)this;
+ else if(((Creature*)this)->isVehicle())
+ unitPlayer = (Player*)GetCharmer();
+ else
+ unitPlayer = NULL;
uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
@@ -8471,7 +8513,14 @@ int32 Unit::CalculateSpellDamage(Unit const* target, SpellEntry const* spellProt
int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, SpellEffectIndex effect_index, Unit const* target)
{
- Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
+ Player* unitPlayer;
+
+ if(GetTypeId() == TYPEID_PLAYER)
+ unitPlayer = (Player*)this;
+ else if(((Creature*)this)->isVehicle())
+ unitPlayer = (Player*)GetCharmer();
+ else
+ unitPlayer = NULL;
uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
@@ -8881,15 +8930,10 @@ void Unit::SetHealth(uint32 val)
if(((Player*)this)->GetGroup())
((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
}
- else if(((Creature*)this)->isPet())
+ else if(Unit* owner = GetCharmerOrOwner())
{
- Pet *pet = ((Pet*)this);
- if(pet->isControlled())
- {
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP);
- }
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP);
}
}
@@ -8904,15 +8948,10 @@ void Unit::SetMaxHealth(uint32 val)
if(((Player*)this)->GetGroup())
((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP);
}
- else if(((Creature*)this)->isPet())
+ else if(Unit* owner = GetCharmerOrOwner())
{
- Pet *pet = ((Pet*)this);
- if(pet->isControlled())
- {
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP);
- }
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP);
}
if(val < health)
@@ -8948,20 +8987,19 @@ void Unit::SetPower(Powers power, uint32 val)
if(((Player*)this)->GetGroup())
((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
}
- else if(((Creature*)this)->isPet())
+ else if(Unit* owner = GetCharmerOrOwner())
{
- Pet *pet = ((Pet*)this);
- if(pet->isControlled())
- {
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
- }
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
- // Update the pet's character sheet with happiness damage bonus
- if(pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS)
+ if(((Creature*)this)->isPet())
{
- pet->UpdateDamagePhysical(BASE_ATTACK);
+ Pet *pet = ((Pet*)this);
+ // Update the pet's character sheet with happiness damage bonus
+ if(pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS)
+ {
+ pet->UpdateDamagePhysical(BASE_ATTACK);
+ }
}
}
}
@@ -8977,15 +9015,10 @@ void Unit::SetMaxPower(Powers power, uint32 val)
if(((Player*)this)->GetGroup())
((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
}
- else if(((Creature*)this)->isPet())
+ else if(Unit* owner = GetCharmerOrOwner())
{
- Pet *pet = ((Pet*)this);
- if(pet->isControlled())
- {
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
- }
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
}
if(val < cur_power)
@@ -9002,15 +9035,10 @@ void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply)
if(((Player*)this)->GetGroup())
((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
}
- else if(((Creature*)this)->isPet())
+ else if(Unit* owner = GetCharmerOrOwner())
{
- Pet *pet = ((Pet*)this);
- if(pet->isControlled())
- {
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
- }
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
}
}
@@ -9024,15 +9052,10 @@ void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply)
if(((Player*)this)->GetGroup())
((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
}
- else if(((Creature*)this)->isPet())
+ else if(Unit* owner = GetCharmerOrOwner())
{
- Pet *pet = ((Pet*)this);
- if(pet->isControlled())
- {
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
- }
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
}
}
@@ -9087,6 +9110,7 @@ void Unit::RemoveFromWorld()
void Unit::CleanupsBeforeDelete()
{
+ ExitVehicle(); // make sure we always leave vehicle, otherwise it will crash
if(m_uint32Values) // only for fully created object
{
InterruptNonMeleeSpells(true);
@@ -9662,8 +9686,12 @@ void Unit::SetFeared(bool apply, uint64 const& casterGUID, uint32 spellID, uint3
}
}
- if (GetTypeId() == TYPEID_PLAYER)
+ if (GetTypeId() == TYPEID_PLAYER && !GetVehicleGUID())
((Player*)this)->SetClientControl(this, !apply);
+
+ if (Unit* owner = GetCharmer())
+ if (owner->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)owner)->SetClientControl(this, !apply);
}
void Unit::SetConfused(bool apply, uint64 const& casterGUID, uint32 spellID)
@@ -9692,8 +9720,12 @@ void Unit::SetConfused(bool apply, uint64 const& casterGUID, uint32 spellID)
}
}
- if(GetTypeId() == TYPEID_PLAYER)
+ if(GetTypeId() == TYPEID_PLAYER && !GetVehicleGUID())
((Player*)this)->SetClientControl(this, !apply);
+
+ if (Unit* owner = GetCharmer())
+ if (owner->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)owner)->SetClientControl(this, !apply);
}
void Unit::SetFeignDeath(bool apply, uint64 const& casterGUID, uint32 /*spellID*/)
@@ -9797,17 +9829,12 @@ void Unit::SetDisplayId(uint32 modelId)
{
SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId);
- UpdateModelData();
+ UpdateModelData();
- if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
- {
- Pet *pet = ((Pet*)this);
- if(!pet->isControlled())
- return;
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ if(Unit *owner = GetCharmerOrOwner())
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID);
- }
+
}
void Unit::UpdateModelData()
@@ -10009,16 +10036,14 @@ void Unit::UpdateAuraForGroup(uint8 slot)
player->SetAuraUpdateMask(slot);
}
}
- else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
+ else if(GetTypeId() == TYPEID_UNIT)
{
- Pet *pet = ((Pet*)this);
- if(pet->isControlled())
+ if(Unit *owner = GetCharmerOrOwner())
{
- Unit *owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ if((owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
{
((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS);
- pet->SetAuraUpdateMask(slot);
+ SetAuraUpdateMask(slot);
}
}
}
@@ -10187,6 +10212,7 @@ void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool ca
((Player*)this)->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0));
else
{
+ ExitVehicle();
Creature* c = (Creature*)this;
// Creature relocation acts like instant movement generator, so current generator expects interrupt/reset calls to react properly
if (!c->GetMotionMaster()->empty())
@@ -10258,6 +10284,123 @@ struct SetPvPHelper
bool state;
};
+void Unit::ChangeSeat(int8 seatId, bool next)
+{
+ Vehicle *m_vehicle = ObjectAccessor::GetVehicle(GetVehicleGUID());
+
+ if (!m_vehicle)
+ return;
+
+ if (seatId < 0)
+ {
+ seatId = m_vehicle->GetNextEmptySeatNum(m_movementInfo.GetTransportSeat(), next);
+ if (seatId < 0)
+ return;
+ }
+ else if (seatId == m_movementInfo.GetTransportSeat() || !m_vehicle->HasEmptySeat(seatId))
+ return;
+
+ m_vehicle->RemovePassenger(this);
+ EnterVehicle(m_vehicle, seatId);
+}
+
+void Unit::EnterVehicle(Vehicle *vehicle, int8 seat_id, bool force)
+{
+ // dont allow multiple vehicles
+ ExitVehicle();
+
+ RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+ // NOTE : shapeshift too?
+
+ Vehicle *v = vehicle->FindFreeSeat(&seat_id, force);
+ if(!v)
+ return;
+
+ VehicleEntry const *ve = sVehicleStore.LookupEntry(v->GetVehicleId());
+ if(!ve)
+ return;
+
+ VehicleSeatEntry const *veSeat = sVehicleSeatStore.LookupEntry(ve->m_seatID[seat_id]);
+ if(!veSeat)
+ return;
+
+ m_movementInfo.SetTransportData(v->GetGUID(),
+ (veSeat->m_attachmentOffsetX + v->GetObjectSize()) * GetFloatValue(OBJECT_FIELD_SCALE_X),
+ (veSeat->m_attachmentOffsetY + v->GetObjectSize()) * GetFloatValue(OBJECT_FIELD_SCALE_X),
+ (veSeat->m_attachmentOffsetZ + v->GetObjectSize()) * GetFloatValue(OBJECT_FIELD_SCALE_X),
+ veSeat->m_passengerYaw, v->GetCreationTime(), seat_id, veSeat->m_ID,
+ sObjectMgr.GetSeatFlags(veSeat->m_ID), v->GetVehicleFlags());
+
+ m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
+
+ addUnitState(UNIT_STAT_ON_VEHICLE);
+ InterruptNonMeleeSpells(false);
+
+ if(Pet *pet = GetPet())
+ pet->Remove(PET_SAVE_AS_CURRENT);
+
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player*)this)->SendEnterVehicle(v);
+
+ WorldPacket data(SMSG_MONSTER_MOVE_TRANSPORT, 60);
+ data << GetPackGUID();
+ data << v->GetPackGUID();
+ data << uint8(seat_id);
+ data << uint8(0); // new in 3.1
+ data << v->GetPositionX() << v->GetPositionY() << v->GetPositionZ();
+ data << uint32(getMSTime());
+
+ data << uint8(4); // unknown
+ data << float(0); // facing angle
+
+ data << uint32(SPLINEFLAG_UNKNOWN5);
+
+ data << uint32(0); // Time in between points
+ data << uint32(1); // 1 single waypoint
+ data << m_movementInfo.GetTransportPos()->x;
+ data << m_movementInfo.GetTransportPos()->y;
+ data << m_movementInfo.GetTransportPos()->z;
+ SendMessageToSet(&data, true);
+
+ v->AddPassenger(this, seat_id, force);
+}
+
+void Unit::ExitVehicle()
+{
+ if(uint64 vehicleGUID = GetVehicleGUID())
+ {
+ float v_size = 0.0f;
+ if(Vehicle *vehicle = ObjectAccessor::GetVehicle(vehicleGUID))
+ {
+ if(m_movementInfo.GetVehicleSeatFlags() & SF_MAIN_RIDER)
+ {
+ if(vehicle->GetVehicleFlags() & VF_DESPAWN_AT_LEAVE)
+ {
+ // will be deleted at next update
+ vehicle->SetSpawnDuration(1);
+ }
+ }
+ v_size = vehicle->GetObjectSize();
+ vehicle->RemovePassenger(this);
+ }
+ SetVehicleGUID(0);
+
+ clearUnitState(UNIT_STAT_ON_VEHICLE);
+
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny();
+ ((Player*)this)->m_movementInfo.RemoveMovementFlag(MOVEFLAG_ROOT);
+ }
+
+ float x = GetPositionX();
+ float y = GetPositionY();
+ float z = GetPositionZ() + 2.0f;
+ GetClosePoint(x, y, z, 2.0f + v_size);
+ SendMonsterMove(x, y, z, SPLINETYPE_NORMAL, SPLINEFLAG_WALKMODE, 0);
+ }
+}
+
void Unit::SetPvP( bool state )
{
if(state)
@@ -10478,4 +10621,4 @@ SpellAuraHolder* Unit::GetSpellAuraHolder (uint32 spellid, uint64 casterGUID)
return iter->second;
return NULL;
-}
+}
\ No newline at end of file
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 35c3767..86aedb6 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -303,6 +303,7 @@ class Item;
class Pet;
class PetAura;
class Totem;
+class Vehicle;
struct SpellImmune
{
@@ -440,24 +441,25 @@ enum UnitState
UNIT_STAT_FOLLOW_MOVE = 0x00010000,
UNIT_STAT_FLEEING = 0x00020000, // FleeMovementGenerator/TimedFleeingMovementGenerator active/onstack
UNIT_STAT_FLEEING_MOVE = 0x00040000,
+ UNIT_STAT_ON_VEHICLE = 0x00080000,
// masks (only for check)
// can't move currently
- UNIT_STAT_CAN_NOT_MOVE = UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DIED,
+ UNIT_STAT_CAN_NOT_MOVE = UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DIED | UNIT_STAT_ON_VEHICLE,
// stay by different reasons
UNIT_STAT_NOT_MOVE = UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DIED |
- UNIT_STAT_DISTRACTED,
+ UNIT_STAT_DISTRACTED | UNIT_STAT_ON_VEHICLE,
// stay or scripted movement for effect( = in player case you can't move by client command)
UNIT_STAT_NO_FREE_MOVE = UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DIED |
UNIT_STAT_IN_FLIGHT |
- UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING,
+ UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING | UNIT_STAT_ON_VEHICLE,
// not react at move in sight or other
UNIT_STAT_CAN_NOT_REACT = UNIT_STAT_STUNNED | UNIT_STAT_DIED |
- UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING,
+ UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING | UNIT_STAT_ON_VEHICLE,
// AI disabled by some reason
UNIT_STAT_LOST_CONTROL = UNIT_STAT_FLEEING | UNIT_STAT_CONTROLLED,
@@ -767,7 +769,7 @@ class MovementInfo
// Position manipulations
Position const *GetPos() const { return &pos; }
- void SetTransportData(ObjectGuid guid, float x, float y, float z, float o, uint32 time, int8 seat)
+ void SetTransportData(ObjectGuid guid, float x, float y, float z, float o, uint32 time, int8 seat, uint32 dbc_seat = 0, uint32 seat_flags = 0, uint32 vehicle_flags = 0)
{
t_guid = guid;
t_pos.x = x;
@@ -776,6 +778,9 @@ class MovementInfo
t_pos.o = o;
t_time = time;
t_seat = seat;
+ t_dbc_seat = dbc_seat;
+ t_seat_flags = seat_flags;
+ t_vehicle_flags = vehicle_flags;
}
void ClearTransportData()
{
@@ -786,11 +791,17 @@ class MovementInfo
t_pos.o = 0.0f;
t_time = 0;
t_seat = -1;
+ t_dbc_seat = 0;
+ t_seat_flags = 0;
+ t_vehicle_flags = 0;
}
ObjectGuid const& GetTransportGuid() const { return t_guid; }
Position const *GetTransportPos() const { return &t_pos; }
int8 GetTransportSeat() const { return t_seat; }
uint32 GetTransportTime() const { return t_time; }
+ uint32 GetTransportDBCSeat() const { return t_dbc_seat; }
+ uint32 GetVehicleSeatFlags() const { return t_seat_flags; }
+ uint32 GetVehicleFlags() const { return t_vehicle_flags; }
uint32 GetFallTime() const { return fallTime; }
void ChangePosition(float x, float y, float z, float o) { pos.x = x; pos.y = y; pos.z = z; pos.o = o; }
void UpdateTime(uint32 _time) { time = _time; }
@@ -807,6 +818,9 @@ class MovementInfo
uint32 t_time;
int8 t_seat;
uint32 t_time2;
+ uint32 t_dbc_seat;
+ uint32 t_seat_flags;
+ uint32 t_vehicle_flags;
// swimming and flying
float s_pitch;
// last fall time
@@ -1230,6 +1244,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
bool IsHostileTo(Unit const* unit) const;
bool IsHostileToPlayers() const;
bool IsFriendlyTo(Unit const* unit) const;
+ bool IsInRaidWith(Unit const* unit) const;
+ bool IsInPartyWith(Unit const* unit) const;
bool IsNeutralToAll() const;
bool IsContestedGuard() const
{
@@ -1365,6 +1381,10 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
return m_spellAuraHolders.find(spellId) != m_spellAuraHolders.end();
}
+ const uint64& GetAuraUpdateMask() const { return m_auraUpdateMask; }
+ void SetAuraUpdateMask(uint8 slot) { m_auraUpdateMask |= (uint64(1) << slot); }
+ void ResetAuraUpdateMask() { m_auraUpdateMask = 0; }
+
bool virtual HasSpell(uint32 /*spellID*/) const { return false; }
bool HasStealthAura() const { return HasAuraType(SPELL_AURA_MOD_STEALTH); }
@@ -1465,12 +1485,13 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
Unit* GetCharm() const;
void Uncharm();
Unit* GetCharmerOrOwner() const { return GetCharmerGUID() ? GetCharmer() : GetOwner(); }
- Unit* GetCharmerOrOwnerOrSelf()
+ Unit* GetCharmOrPet() const { return GetCharmGUID() ? GetCharm() : (Unit*)GetPet(); }
+ Unit* GetCharmerOrOwnerOrSelf() const
{
if(Unit* u = GetCharmerOrOwner())
return u;
- return this;
+ return (Unit*)this;
}
bool IsCharmerOrOwnerPlayerOrPlayerItself() const;
Player* GetCharmerOrOwnerPlayerOrPlayerItself();
@@ -1876,6 +1897,13 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
// Movement info
MovementInfo m_movementInfo;
+ // vehicle system
+ void EnterVehicle(Vehicle *vehicle, int8 seat_id, bool force = false);
+ void ExitVehicle();
+ uint64 GetVehicleGUID() { return m_vehicleGUID; }
+ void SetVehicleGUID(uint64 guid) { m_vehicleGUID = guid; }
+ void ChangeSeat(int8 seatId, bool next);
+
protected:
explicit Unit ();
@@ -1924,6 +1952,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint32 m_reactiveTimer[MAX_REACTIVE];
uint32 m_regenTimer;
uint32 m_lastManaUseTimer;
+ uint64 m_auraUpdateMask;
+ uint64 m_vehicleGUID;
private:
void CleanupDeletedAuras();
diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp
index b92e542..a0df6ab 100644
--- a/src/game/Vehicle.cpp
+++ b/src/game/Vehicle.cpp
@@ -18,12 +18,14 @@
#include "Common.h"
#include "Log.h"
-#include "ObjectMgr.h"
#include "Vehicle.h"
#include "Unit.h"
#include "Util.h"
+#include "WorldPacket.h"
+#include "InstanceData.h"
-Vehicle::Vehicle() : Creature(CREATURE_SUBTYPE_VEHICLE), m_vehicleId(0)
+Vehicle::Vehicle() : Creature(CREATURE_SUBTYPE_VEHICLE), m_vehicleId(0), m_vehicleInfo(NULL), m_spawnduration(0),
+ despawn(false), m_creation_time(0), m_VehicleData(NULL)
{
m_updateFlag = (UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_VEHICLE);
}
@@ -51,45 +53,721 @@ void Vehicle::RemoveFromWorld()
Unit::RemoveFromWorld();
}
+void Vehicle::Respawn()
+{
+ Creature::Respawn();
+ InstallAllAccessories();
+}
+
void Vehicle::setDeathState(DeathState s) // overwrite virtual Creature::setDeathState and Unit::setDeathState
{
Creature::setDeathState(s);
+ if(s == JUST_DIED)
+ {
+ if(GetVehicleFlags() & VF_DESPAWN_NPC)
+ Dismiss();
+ else
+ RemoveAllPassengers();
+ }
}
void Vehicle::Update(uint32 diff)
{
Creature::Update(diff);
+
+ if(despawn)
+ {
+ m_spawnduration -= diff;
+ if(m_spawnduration < 0)
+ Dismiss();
+ despawn = false;
+ }
+
+ if(m_regenTimer <= diff)
+ {
+ RegeneratePower(getPowerType());
+ m_regenTimer = 4000;
+ }
+ else
+ m_regenTimer -= diff;
}
-bool Vehicle::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 vehicleId, uint32 team)
+void Vehicle::RegeneratePower(Powers power)
+{
+ uint32 curValue = GetPower(power);
+ uint32 maxValue = GetMaxPower(power);
+
+ if (curValue >= maxValue)
+ return;
+
+ float addvalue = 0.0f;
+
+ // hack: needs more research of power type from the dbc.
+ // It must contains some info about vehicles like Salvaged Chopper.
+ if(m_vehicleInfo->m_powerType == POWER_TYPE_PYRITE)
+ return;
+
+ addvalue = 20.0f;
+
+ ModifyPower(power, (int32)addvalue);
+}
+
+bool Vehicle::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehicleId, uint32 team, const CreatureData *data)
{
SetMap(map);
+ SetPhaseMask(phaseMask,false);
+
+ CreatureInfo const *cinfo = sObjectMgr.GetCreatureTemplate(Entry);
+ if(!cinfo)
+ {
+ sLog.outErrorDb("Creature entry %u does not exist.", Entry);
+ return false;
+ }
Object::_Create(guidlow, Entry, HIGHGUID_VEHICLE);
- if(!InitEntry(Entry, team))
+ if(!UpdateEntry(Entry, team, data))
return false;
- m_defaultMovementType = IDLE_MOTION_TYPE;
+ if(!vehicleId)
+ {
+ CreatureDataAddon const *cainfo = GetCreatureAddon();
+ if(!cainfo)
+ return false;
+ vehicleId = cainfo->vehicle_id;
+ }
+ if(!SetVehicleId(vehicleId))
+ return false;
- AIM_Initialize();
+ LoadCreaturesAddon();
- SetVehicleId(vehicleId);
+ m_regenHealth = false;
+ m_creation_time = getMSTime();
- SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f);
+ //RemoveMonsterMoveFlag(MONSTER_MOVE_WALK);
+
+ //Notify the map's instance data.
+ //Only works if you create the object in it, not if it is moves to that map.
+ //Normally non-players do not teleport to other maps.
+ if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
+ {
+ ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this);
+ }
+
+ if(m_vehicleInfo->m_powerType == POWER_TYPE_STEAM)
+ {
+ setPowerType(POWER_ENERGY);
+ SetMaxPower(POWER_ENERGY, 100);
+ SetPower(POWER_ENERGY, 100);
+ }
+ else if(m_vehicleInfo->m_powerType == POWER_TYPE_PYRITE)
+ {
+ setPowerType(POWER_ENERGY);
+ SetMaxPower(POWER_ENERGY, 50);
+ SetPower(POWER_ENERGY, 50);
+ }
+ else
+ {
+ for (uint32 i = 0; i < MAX_VEHICLE_SPELLS; ++i)
+ {
+ if(!GetVehicleData()->v_spells[i])
+ continue;
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(GetVehicleData()->v_spells[i]);
+ if(!spellInfo)
+ continue;
- CreatureInfo const *ci = GetCreatureInfo();
- setFaction(team == ALLIANCE ? ci->faction_A : ci->faction_H);
+ if(spellInfo->powerType == POWER_MANA)
+ break;
- SelectLevel(ci);
+ if(spellInfo->powerType == POWER_ENERGY)
+ {
+ setPowerType(POWER_ENERGY);
+ SetMaxPower(POWER_ENERGY, 100);
+ SetPower(POWER_ENERGY, 100);
+ break;
+ }
+ }
+ }
+ SetHealth(GetMaxHealth());
+ InstallAllAccessories();
return true;
}
+bool Vehicle::SetVehicleId(uint32 vehicleid)
+{
+ VehicleEntry const *vehicleInfo = sVehicleStore.LookupEntry(vehicleid);
+ if(!vehicleInfo)
+ return false;
+
+ m_vehicleId = vehicleid;
+ m_vehicleInfo = vehicleInfo;
+
+ // can be NULL
+ VehicleDataStructure const *VDStructure = sObjectMgr.GetVehicleData(vehicleid);
+ if(VDStructure)
+ m_VehicleData = VDStructure;
+
+ InitSeats();
+ EmptySeatsCountChanged();
+ return true;
+}
+
+void Vehicle::InitSeats()
+{
+ m_Seats.clear();
+
+ for(uint32 i = 0; i < MAX_SEAT; ++i)
+ {
+ uint32 seatId = m_vehicleInfo->m_seatID[i];
+ if(seatId)
+ {
+ if(VehicleSeatEntry const *veSeat = sVehicleSeatStore.LookupEntry(seatId))
+ {
+ VehicleSeat newseat;
+ newseat.seatInfo = veSeat;
+ newseat.passenger = NULL;
+ newseat.flags = SEAT_FREE;
+ newseat.vs_flags = sObjectMgr.GetSeatFlags(seatId);
+ m_Seats[i] = newseat;
+ }
+ }
+ }
+ // NOTE : there can be vehicles without seats (eg. 180) - probably some TEST vehicles
+}
+void Vehicle::ChangeSeatFlag(uint8 seat, uint8 flag)
+{
+ SeatMap::iterator i_seat = m_Seats.find(seat);
+ // this should never happen
+ if(i_seat == m_Seats.end())
+ return;
+
+ if(i_seat->second.flags != flag)
+ {
+ i_seat->second.flags = flag;
+ EmptySeatsCountChanged();
+ }
+}
+Vehicle* Vehicle::FindFreeSeat(int8 *seatid, bool force)
+{
+ SeatMap::const_iterator i_seat = m_Seats.find(*seatid);
+ if(i_seat == m_Seats.end())
+ return GetFirstEmptySeat(seatid, force);
+ if((i_seat->second.flags & (SEAT_FULL | SEAT_VEHICLE_FULL)) || (!force && (i_seat->second.vs_flags & SF_UNACCESSIBLE)))
+ return GetNextEmptySeat(seatid, true, force);
+ if(i_seat->second.flags & SEAT_VEHICLE_FREE)
+ {
+ // this should never be NULL
+ if(Vehicle *v = (Vehicle*)i_seat->second.passenger)
+ return v->FindFreeSeat(seatid, force);
+ return NULL;
+ }
+ return this;
+}
+
+Vehicle* Vehicle::GetFirstEmptySeat(int8 *seatId, bool force)
+{
+ for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
+ {
+ if(itr->second.flags & SEAT_FREE)
+ {
+ if(!force && (itr->second.vs_flags & SF_UNACCESSIBLE))
+ continue;
+
+ *seatId = itr->first;
+ return this;
+ }
+ else if(itr->second.flags & SEAT_VEHICLE_FREE)
+ {
+ *seatId = itr->first;
+ if(Vehicle *v = (Vehicle*)itr->second.passenger)
+ return v->FindFreeSeat(seatId, force);
+ }
+ }
+
+ return NULL;
+}
+
+Vehicle* Vehicle::GetNextEmptySeat(int8 *seatId, bool next, bool force)
+{
+ SeatMap::const_iterator i_seat = m_Seats.find(*seatId);
+ if(i_seat == m_Seats.end()) return GetFirstEmptySeat(seatId, force);
+
+ while((i_seat->second.flags & (SEAT_FULL | SEAT_VEHICLE_FULL)) || (!force && (i_seat->second.vs_flags & SF_UNACCESSIBLE)))
+ {
+ if(next)
+ {
+ ++i_seat;
+ if(i_seat == m_Seats.end())
+ i_seat = m_Seats.begin();
+ }
+ else
+ {
+ if(i_seat == m_Seats.begin())
+ i_seat = m_Seats.end();
+ --i_seat;
+ }
+ if(i_seat->first == *seatId)
+ return NULL;
+ }
+ *seatId = i_seat->first;
+ if(i_seat->second.flags & SEAT_VEHICLE_FREE)
+ {
+ if(Vehicle *v = (Vehicle*)i_seat->second.passenger)
+ return v->FindFreeSeat(seatId, force);
+ return NULL;
+ }
+
+ return this;
+}
+
+int8 Vehicle::GetEmptySeatsCount(bool force)
+{
+ int8 count = 0;
+ for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
+ {
+ if(itr->second.flags & (SEAT_FREE | SEAT_VEHICLE_FREE))
+ {
+ if(!force && (itr->second.vs_flags & SF_UNACCESSIBLE))
+ continue;
+
+ count++;
+ }
+ }
+
+ return count;
+}
+int8 Vehicle::GetNextEmptySeatNum(int8 seatId, bool next) const
+{
+ SeatMap::const_iterator seat = m_Seats.find(seatId);
+ if(seat == m_Seats.end()) return -1;
+ while(seat->second.passenger || !seat->second.seatInfo->IsUsable())
+ {
+ if(next)
+ {
+ ++seat;
+ if(seat == m_Seats.end())
+ seat = m_Seats.begin();
+ }
+ else
+ {
+ if(seat == m_Seats.begin())
+ seat = m_Seats.end();
+ --seat;
+ }
+ if(seat->first == seatId)
+ return -1; // no available seat
+ }
+ return seat->first;
+}
+
+bool Vehicle::HasEmptySeat(int8 seatId) const
+{
+ SeatMap::const_iterator seat = m_Seats.find(seatId);
+ if(seat == m_Seats.end()) return false;
+ return !seat->second.passenger;
+}
+
+void Vehicle::EmptySeatsCountChanged()
+{
+ uint8 m_count = GetTotalSeatsCount();
+ uint8 p_count = GetEmptySeatsCount(false);
+ uint8 u_count = GetEmptySeatsCount(true);
+
+ // seats accesibles by players
+ if(p_count > 0)
+ SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ else
+ RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+
+ if(u_count == m_count)
+ {
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
+ }
+ else
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
+
+ if(uint64 vehicleGUID = GetVehicleGUID())
+ {
+ if(Vehicle *vehicle = ObjectAccessor::GetVehicle(vehicleGUID))
+ {
+ if(u_count > 0)
+ vehicle->ChangeSeatFlag(m_movementInfo.GetTransportSeat(), SEAT_VEHICLE_FREE);
+ else
+ vehicle->ChangeSeatFlag(m_movementInfo.GetTransportSeat(), SEAT_VEHICLE_FULL);
+ }
+ }
+}
+
+
+
void Vehicle::Dismiss()
{
+ RemoveAllPassengers();
SendObjectDeSpawnAnim(GetGUID());
CombatStop();
AddObjectToRemoveList();
}
+
+void Vehicle::RellocatePassengers(Map *map)
+{
+ for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
+ {
+ if(itr->second.flags & SEAT_FULL)
+ {
+ // passenger cant be NULL here
+ Unit *passengers = itr->second.passenger;
+ assert(passengers);
+
+ float xx = GetPositionX() + passengers->m_movementInfo.GetTransportPos()->x;
+ float yy = GetPositionY() + passengers->m_movementInfo.GetTransportPos()->y;
+ float zz = GetPositionZ() + passengers->m_movementInfo.GetTransportPos()->z;
+ //float oo = passengers->m_SeatData.Orientation;
+ // this is not correct, we should recalculate
+ // actual rotation depending on vehicle
+ float oo = passengers->GetOrientation();
+
+ if(passengers->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)passengers)->SetPosition(xx, yy, zz, oo);
+ else
+ map->CreatureRelocation((Creature*)passengers, xx, yy, zz, oo);
+ }
+ else if(itr->second.flags & (SEAT_VEHICLE_FULL | SEAT_VEHICLE_FREE))
+ {
+ // passenger cant be NULL here
+ Unit *passengers = itr->second.passenger;
+ assert(passengers);
+
+ float xx = GetPositionX() + passengers->m_movementInfo.GetTransportPos()->x;
+ float yy = GetPositionY() + passengers->m_movementInfo.GetTransportPos()->y;
+ float zz = GetPositionZ() + passengers->m_movementInfo.GetTransportPos()->z;
+ //float oo = passengers->m_SeatData.Orientation;
+ // this is not correct, we should recalculate
+ // actual rotation depending on vehicle
+ float oo = passengers->GetOrientation();
+
+ map->CreatureRelocation((Creature*)passengers, xx, yy, zz, oo);
+ }
+ }
+}
+
+void Vehicle::AddPassenger(Unit *unit, int8 seatId, bool force)
+{
+ SeatMap::iterator seat;
+ seat = m_Seats.find(seatId);
+
+ // this should never happen
+ if(seat == m_Seats.end())
+ return;
+
+ unit->SetVehicleGUID(GetGUID());
+ unit->m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
+ unit->m_movementInfo.AddMovementFlag(MOVEFLAG_ROOT);
+
+ seat->second.passenger = unit;
+ if(unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->isVehicle())
+ {
+ if(((Vehicle*)unit)->GetEmptySeatsCount(true) == 0)
+ seat->second.flags = SEAT_VEHICLE_FULL;
+ else
+ seat->second.flags = SEAT_VEHICLE_FREE;
+ }
+ else
+ {
+ seat->second.flags = SEAT_FULL;
+ }
+
+ if(unit->GetTypeId() == TYPEID_PLAYER)
+ {
+ WorldPacket data0(SMSG_FORCE_MOVE_ROOT, 10);
+ data0 << unit->GetPackGUID();
+ data0 << (uint32)((seat->second.vs_flags & SF_CAN_CAST) ? 2 : 0);
+ unit->SendMessageToSet(&data0,true);
+ }
+
+ if(unit->GetTypeId() == TYPEID_PLAYER)
+ {
+ uint8 allowMove = 1;
+ if(GetVehicleFlags() & VF_MOVEMENT)
+ allowMove = 0;
+ ((Player*)unit)->SetMover(this);
+ ((Player*)unit)->SetClientControl(this, 1);
+ ((Player*)unit)->GetCamera().SetView(this);
+ }
+
+ if(seat->second.vs_flags & SF_MAIN_RIDER)
+ {
+ if(!(GetVehicleFlags() & VF_MOVEMENT))
+ {
+ GetMotionMaster()->Clear(false);
+ GetMotionMaster()->MoveIdle();
+ SetCharmerGUID(unit->GetGUID());
+ unit->SetUInt64Value(UNIT_FIELD_CHARM, GetGUID());
+ if(canFly() || HasAuraType(SPELL_AURA_FLY) || HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED))
+ {
+ WorldPacket data3(SMSG_MOVE_SET_CAN_FLY, 12);
+ data3<< GetPackGUID();
+ data3 << (uint32)(0);
+ SendMessageToSet(&data3,false);
+ }
+ }
+
+ SpellClickInfoMapBounds clickPair = sObjectMgr.GetSpellClickInfoMapBounds(GetEntry());
+ for(SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr)
+ {
+ if (unit->GetTypeId() == TYPEID_UNIT || itr->second.IsFitToRequirements((Player*)unit))
+ {
+ Unit *caster = (itr->second.castFlags & 0x1) ? unit : this;
+ Unit *target = (itr->second.castFlags & 0x2) ? unit : this;
+
+ caster->CastSpell(target, itr->second.spellId, true);
+ }
+ }
+ if(unit->GetTypeId() == TYPEID_PLAYER)
+ {
+ // it should be added only on rider enter?
+ if(((Player*)unit)->GetGroup())
+ ((Player*)unit)->SetGroupUpdateFlag(GROUP_UPDATE_VEHICLE);
+
+ BuildVehicleActionBar((Player*)unit);
+ }
+
+ if(!(GetVehicleFlags() & VF_FACTION))
+ setFaction(unit->getFaction());
+
+ if(GetVehicleFlags() & VF_CANT_MOVE)
+ {
+ WorldPacket data2(SMSG_FORCE_MOVE_ROOT, 10);
+ data2<< GetPackGUID();
+ data2 << (uint32)(2);
+ SendMessageToSet(&data2,false);
+ }
+
+ if(GetVehicleFlags() & VF_NON_SELECTABLE)
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ }
+ if(seat->second.vs_flags & SF_UNATTACKABLE)
+ unit->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+
+ EmptySeatsCountChanged();
+}
+
+void Vehicle::RemovePassenger(Unit *unit)
+{
+ SeatMap::iterator seat;
+ for(seat = m_Seats.begin(); seat != m_Seats.end(); ++seat)
+ {
+ if((seat->second.flags & (SEAT_FULL | SEAT_VEHICLE_FREE | SEAT_VEHICLE_FULL)) && seat->second.passenger == unit)
+ {
+ unit->SetVehicleGUID(0);
+ if(unit->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)unit)->SetMover(unit);
+ ((Player*)unit)->SetClientControl(unit, 1);
+ ((Player*)unit)->GetCamera().SetView(unit);
+ }
+
+ if(seat->second.vs_flags & SF_MAIN_RIDER)
+ {
+ RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE);
+ if(unit->GetTypeId() == TYPEID_PLAYER)
+ {
+ ((Player*)unit)->RemovePetActionBar();
+
+ if(((Player*)unit)->GetGroup())
+ ((Player*)unit)->SetGroupUpdateFlag(GROUP_UPDATE_VEHICLE);
+ }
+ unit->SetCharm(NULL);
+ SetCharmerGUID(NULL);
+ setFaction(GetCreatureInfo()->faction_A);
+ }
+ if(GetVehicleFlags() & VF_NON_SELECTABLE)
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ if(seat->second.vs_flags & SF_UNATTACKABLE)
+ unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ // restore player control
+ if(unit->GetTypeId() == TYPEID_PLAYER)
+ {
+ if(seat->second.vs_flags & SF_CAN_CAST)
+ {
+ WorldPacket data0(SMSG_FORCE_MOVE_UNROOT, 10);
+ data0 << unit->GetPackGUID();
+ data0 << (uint32)(2); // can rotate
+ unit->SendMessageToSet(&data0,true);
+ }
+ else
+ {
+ WorldPacket data1(SMSG_FORCE_MOVE_UNROOT, 10);
+ data1 << unit->GetPackGUID();
+ data1 << (uint32)(0); // cannot rotate
+ unit->SendMessageToSet(&data1,true);
+ }
+ }
+ unit->m_movementInfo.RemoveMovementFlag(MOVEFLAG_ONTRANSPORT);
+ unit->m_movementInfo.RemoveMovementFlag(MOVEFLAG_ROOT);
+ unit->m_movementInfo.ClearTransportData();
+
+ seat->second.passenger = NULL;
+ seat->second.flags = SEAT_FREE;
+ EmptySeatsCountChanged();
+ break;
+ }
+ }
+}
+
+void Vehicle::RemoveAllPassengers()
+{
+ for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
+ {
+ if(itr->second.flags & SEAT_FULL)
+ {
+ if(Unit *passenger = itr->second.passenger) // this cant be NULL, but..
+ passenger->ExitVehicle();
+ }
+ else if(itr->second.flags & (SEAT_VEHICLE_FULL | SEAT_VEHICLE_FREE))
+ {
+ if(Unit *passenger = itr->second.passenger) // this cant be NULL, but..
+ {
+ passenger->ExitVehicle();
+ ((Vehicle*)passenger)->Dismiss();
+ }
+ }
+ }
+ // make sure everything is cleared
+ InitSeats();
+}
+
+bool Vehicle::HasSpell(uint32 spell) const
+{
+ if(!m_VehicleData)
+ return false;
+
+ for(uint8 j = 0; j < MAX_VEHICLE_SPELLS; j++)
+ {
+ if(m_VehicleData->v_spells[j] == spell)
+ return true;
+ }
+
+ return false;
+}
+
+void Vehicle::BuildVehicleActionBar(Player *plr) const
+{
+ WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*10+1+1);
+ data << uint64(GetGUID());
+ data << uint16(0x00000000); // creature family, not used in vehicles
+ data << uint32(0x00000000); // unk
+ data << uint32(0x00000101); // react state
+
+ for(uint32 i = 0; i <= MAX_VEHICLE_SPELLS; ++i)
+ {
+ data << uint16(m_VehicleData ? m_VehicleData->v_spells[i] : NULL) << uint8(0) << uint8(i+8);
+ }
+
+ data << uint8(0); //aditional spells in spellbook, not used in vehicles
+
+ uint8 cooldownsCount = m_CreatureSpellCooldowns.size() + m_CreatureCategoryCooldowns.size();
+ data << uint8(cooldownsCount);
+ time_t curTime = time(NULL);
+
+ for(CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.begin(); itr != m_CreatureSpellCooldowns.end(); ++itr)
+ {
+ time_t cooldown = (itr->second > curTime) ? (itr->second - curTime) * IN_MILLISECONDS : 0;
+
+ data << uint32(itr->first); // spellid
+ data << uint16(0); // spell category?
+ data << uint32(cooldown); // cooldown
+ data << uint32(0); // category cooldown
+ }
+
+ for(CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.begin(); itr != m_CreatureCategoryCooldowns.end(); ++itr)
+ {
+ time_t cooldown = (itr->second > curTime) ? (itr->second - curTime) * IN_MILLISECONDS : 0;
+
+ data << uint32(itr->first); // spellid
+ data << uint16(0); // spell category?
+ data << uint32(0); // cooldown
+ data << uint32(cooldown); // category cooldown
+ }
+
+ plr->GetSession()->SendPacket(&data);
+
+ data.Initialize(SMSG_PET_GUIDS, 12);
+ data << uint32(1); // count
+ data << uint64(GetGUID());
+ plr->GetSession()->SendPacket(&data);
+}
+void Vehicle::InstallAllAccessories()
+{
+ if(!GetMap())
+ return;
+
+ CreatureDataAddon const *cainfo = GetCreatureAddon();
+ if(!cainfo || !cainfo->passengers)
+ return;
+ for (CreatureDataAddonPassengers const* cPassanger = cainfo->passengers; cPassanger->seat_idx != -1; ++cPassanger)
+ {
+ // Continue if seat already taken
+ if(GetPassenger(cPassanger->seat_idx))
+ continue;
+
+ uint32 guid = 0;
+ bool isVehicle = false;
+ // Set guid and check whatever it is
+ if(cPassanger->guid != 0)
+ guid = cPassanger->guid;
+ else
+ {
+ CreatureDataAddon const* passAddon;
+ passAddon = ObjectMgr::GetCreatureTemplateAddon(cPassanger->entry);
+ if(passAddon && passAddon->vehicle_id != 0)
+ isVehicle = true;
+ else
+ guid = sObjectMgr.GenerateLowGuid(HIGHGUID_UNIT);
+ }
+ // Create it
+ Creature *pPassenger = new Creature;
+ if(!isVehicle)
+ {
+ uint32 entry = cPassanger->entry;
+ if(entry == 0)
+ {
+ CreatureData const* data = sObjectMgr.GetCreatureData(guid);
+ if(!data)
+ continue;
+ entry = data->id;
+ }
+
+ if(!pPassenger->Create(guid, GetMap(), GetPhaseMask(), entry, 0))
+ continue;
+ pPassenger->LoadFromDB(guid, GetMap());
+ pPassenger->Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
+ GetMap()->Add(pPassenger);
+ pPassenger->AIM_Initialize();
+ }
+ else
+ pPassenger = (Creature*)SummonVehicle(cPassanger->entry, GetPositionX(), GetPositionY(), GetPositionZ(), 0);
+ // Enter vehicle...
+ pPassenger->EnterVehicle(this, cPassanger->seat_idx, true);
+ // ...and send update. Without this, client wont show this new creature/vehicle...
+ WorldPacket data;
+ pPassenger->BuildHeartBeatMsg(&data);
+ pPassenger->SendMessageToSet(&data, false);
+ }
+}
+
+Unit *Vehicle::GetPassenger(int8 seatId) const
+{
+ SeatMap::const_iterator seat = m_Seats.find(seatId);
+ if(seat == m_Seats.end()) return NULL;
+ return seat->second.passenger;
+}
+void Vehicle::Die()
+{
+ for (SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr)
+ if(Unit *passenger = itr->second.passenger)
+ if(((Creature*)passenger)->isVehicle())
+ ((Vehicle*)passenger)->Dismiss();
+ RemoveAllPassengers();
+}
\ No newline at end of file
diff --git a/src/game/Vehicle.h b/src/game/Vehicle.h
index 4233db6..7252bad 100644
--- a/src/game/Vehicle.h
+++ b/src/game/Vehicle.h
@@ -22,6 +22,34 @@
#include "ObjectGuid.h"
#include "Creature.h"
#include "Unit.h"
+#include "ObjectMgr.h"
+
+struct VehicleSeat
+{
+ VehicleSeatEntry const *seatInfo;
+ Unit* passenger;
+ uint8 flags;
+ uint32 vs_flags;
+};
+
+enum VehicleSeatFlags
+{
+ SEAT_FREE = 0x01, // free seat
+ SEAT_FULL = 0x02, // seat occupied by player/creature
+ // special cases
+ SEAT_VEHICLE_FREE = 0x04, // seat occupied by vehicle, but that vehicle is free
+ SEAT_VEHICLE_FULL = 0x08 // seat occupied by vehicle and that vehicle is full too
+};
+
+enum PowerType
+{
+ POWER_TYPE_PYRITE = 41,
+ POWER_TYPE_STEAM = 61
+};
+
+#define MAX_SEAT 8
+
+typedef std::map<int8, VehicleSeat> SeatMap;
class Vehicle : public Creature
{
@@ -32,18 +60,57 @@ class Vehicle : public Creature
void AddToWorld();
void RemoveFromWorld();
- bool Create (uint32 guidlow, Map *map, uint32 Entry, uint32 vehicleId, uint32 team);
+ void Die();
+ bool Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehicleId, uint32 team, const CreatureData *data = NULL);
+ void Respawn();
void setDeathState(DeathState s); // overwrite virtual Creature::setDeathState and Unit::setDeathState
void Update(uint32 diff); // overwrite virtual Creature::Update and Unit::Update
+ void RegeneratePower(Powers power);
+
uint32 GetVehicleId() { return m_vehicleId; }
- void SetVehicleId(uint32 vehicleid) { m_vehicleId = vehicleid; }
+ bool SetVehicleId(uint32 vehicleid);
+
+ void InitSeats();
+
+ void ChangeSeatFlag(uint8 seat, uint8 flag);
+ Vehicle* FindFreeSeat(int8 *seatid, bool force = true);
+ Vehicle* GetNextEmptySeat(int8 *seatId, bool next = true, bool force = true);
+ Vehicle* GetFirstEmptySeat(int8 *seatId, bool force = true);
+ int8 GetEmptySeatsCount(bool force = true);
+ void EmptySeatsCountChanged();
+ int8 GetTotalSeatsCount() { return m_Seats.size(); }
+ bool HasEmptySeat(int8 seatId) const;
+ int8 GetNextEmptySeatNum(int8 seatId, bool next) const;
void Dismiss();
+ void RellocatePassengers(Map *map);
+ void AddPassenger(Unit *unit, int8 seatId, bool force = true);
+ void RemovePassenger(Unit *unit);
+ void RemoveAllPassengers();
+
+ bool HasSpell(uint32 spell) const;
+ void SetSpawnDuration(int32 duration)
+ {
+ duration < 1 ? despawn = false : despawn = true;
+ m_spawnduration = duration;
+ }
+ VehicleDataStructure const* GetVehicleData() { return m_VehicleData; }
+ uint32 GetVehicleFlags() { return m_VehicleData ? m_VehicleData->v_flags : NULL; }
+ uint32 GetCreationTime() { return m_creation_time; }
+ void BuildVehicleActionBar(Player *plr) const;
+ void InstallAllAccessories();
+ Unit *GetPassenger(int8 seatId) const;
protected:
uint32 m_vehicleId;
+ VehicleEntry const *m_vehicleInfo;
+ VehicleDataStructure const *m_VehicleData;
+ uint32 m_creation_time;
+ SeatMap m_Seats;
+ bool despawn;
+ int32 m_spawnduration;
private:
void SaveToDB(uint32, uint8) // overwrited of Creature::SaveToDB - don't must be called
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 5c87bcc..67c4a93 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -1220,6 +1220,11 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls
sObjectMgr.LoadDbScriptStrings();
+ sLog.outString( "Loading VehicleData..." );
+ sObjectMgr.LoadVehicleData();
+ sLog.outString( "Loading VehicleSeatData..." );
+ sObjectMgr.LoadVehicleSeatData();
+
sLog.outString( "Loading CreatureEventAI Texts...");
sEventAIMgr.LoadCreatureEventAI_Texts(false); // false, will checked in LoadCreatureEventAI_Scripts
diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h
index af857e2..e3bc43b 100644
--- a/src/game/WorldSession.h
+++ b/src/game/WorldSession.h
@@ -425,6 +425,9 @@ class MANGOS_DLL_SPEC WorldSession
void HandleSetActiveMoverOpcode(WorldPacket &recv_data);
void HandleMoveNotActiveMover(WorldPacket &recv_data);
void HandleDismissControlledVehicle(WorldPacket &recv_data);
+ void HandleRequestVehicleExit(WorldPacket &recv_data);
+ void HandleRequestVehicleSwitchSeat(WorldPacket &recv_data);
+ void HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data);
void HandleMoveTimeSkippedOpcode(WorldPacket &recv_data);
void HandleRequestRaidInfoOpcode( WorldPacket & recv_data );
diff --git a/src/game/debugcmds.cpp b/src/game/debugcmds.cpp
index 9ea6958..a01de1c 100644
--- a/src/game/debugcmds.cpp
+++ b/src/game/debugcmds.cpp
@@ -636,7 +636,8 @@ bool ChatHandler::HandleDebugSpawnVehicle(const char* args)
Vehicle *v = new Vehicle;
Map *map = m_session->GetPlayer()->GetMap();
- if (!v->Create(map->GenerateLocalLowGuid(HIGHGUID_VEHICLE), map, entry, id, m_session->GetPlayer()->GetTeam()))
+
+ if (!v->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_VEHICLE), map, m_session->GetPlayer()->GetPhaseMaskForSpawn(), entry, id, m_session->GetPlayer()->GetTeam()))
{
delete v;
return false;
@@ -656,6 +657,7 @@ bool ChatHandler::HandleDebugSpawnVehicle(const char* args)
}
map->Add((Creature*)v);
+ v->AIM_Initialize();
return true;
}
diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp
index c7644f2..64c4391 100644
--- a/src/shared/Database/SQLStorage.cpp
+++ b/src/shared/Database/SQLStorage.cpp
@@ -27,9 +27,9 @@ extern DatabaseMysql WorldDatabase;
const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis";
const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii";
-const char CreatureDataAddonInfofmt[]="iiiiiis";
+const char CreatureDataAddonInfofmt[]="iiiiiiiss";
const char CreatureModelfmt[]="iffbi";
-const char CreatureInfoAddonInfofmt[]="iiiiiis";
+const char CreatureInfoAddonInfofmt[]="iiiiiiiss";
const char EquipmentInfofmt[]="iiii";
const char GameObjectInfosrcfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis";
const char GameObjectInfodstfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment