Merge remote branch 'origin/master' into 330

Conflicts:
	src/game/ObjectMgr.h
This commit is contained in:
tomrus88 2009-12-11 21:50:24 +03:00
commit 7c6cae1af7
58 changed files with 1937 additions and 990 deletions

View file

@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_8912_01_mangos_spell_proc_event` bit(1) default NULL
`required_8965_02_mangos_command` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@ -705,6 +705,7 @@ INSERT INTO `command` VALUES
('quest add',3,'Syntax: .quest add #quest_id\r\n\r\nAdd to character quest log quest #quest_id. Quest started from item can\'t be added by this command but correct .additem call provided in command output.'),
('quest complete',3,'Syntax: .quest complete #questid\r\nMark all quest objectives as completed for target character active quest. After this target character can go and get quest reward.'),
('quest remove',3,'Syntax: .quest remove #quest_id\r\n\r\nSet quest #quest_id state to not completed and not active (and remove from active quest list) for selected player.'),
('quit',4,'Syntax: quit\r\n\r\nClose RA connection. Command must be typed fully (quit).'),
('recall',1,'Syntax: .recall [$playername]\r\n\r\nTeleport $playername or selected player to the place where he has been before last use of a teleportation command. If no $playername is entered and no player is selected, it will teleport you.'),
('reload all',3,'Syntax: .reload all\r\n\r\nReload all tables with reload support added and that can be _safe_ reloaded.'),
('reload all_area',3,'Syntax: .reload all_area\r\n\r\nReload all `areatrigger_*` tables if reload support added for this table and this table can be _safe_ reloaded.'),
@ -1078,6 +1079,7 @@ CREATE TABLE `creature_template` (
`name` char(100) NOT NULL default '0',
`subname` char(100) default NULL,
`IconName` char(100) default NULL,
`gossip_menu_id` mediumint(8) unsigned NOT NULL default '0',
`minlevel` tinyint(3) unsigned NOT NULL default '1',
`maxlevel` tinyint(3) unsigned NOT NULL default '1',
`minhealth` int(10) unsigned NOT NULL default '0',
@ -1155,7 +1157,7 @@ CREATE TABLE `creature_template` (
LOCK TABLES `creature_template` WRITE;
/*!40000 ALTER TABLE `creature_template` DISABLE KEYS */;
INSERT INTO `creature_template` VALUES
(1,0,0,0,0,0,10045,0,10045,0,'Waypoint(Only GM can see it)','Visual',NULL,1,1,64,64,0,0,0,35,35,0,0.91,1,0,14,15,0,100,1,2000,2200,8,4096,0,0,0,0,0,0,1.76,2.42,100,8,5242886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,3,1.0,1.0,0,0,0,0,0,0,0,0,1,0,0,0x82,'');
(1,0,0,0,0,0,10045,0,10045,0,'Waypoint(Only GM can see it)','Visual',NULL,0,1,1,64,64,0,0,0,35,35,0,0.91,1,0,14,15,0,100,1,2000,2200,8,4096,0,0,0,0,0,0,1.76,2.42,100,8,5242886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,3,1.0,1.0,0,0,0,0,0,0,0,0,1,0,0,0x82,'');
/*!40000 ALTER TABLE `creature_template` ENABLE KEYS */;
UNLOCK TABLES;
@ -1899,6 +1901,115 @@ LOCK TABLES `gameobject_template` WRITE;
/*!40000 ALTER TABLE `gameobject_template` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `gossip_menu`
--
DROP TABLE IF EXISTS gossip_menu;
CREATE TABLE gossip_menu (
entry smallint(6) unsigned NOT NULL default '0',
text_id mediumint(8) unsigned NOT NULL default '0',
cond_1 tinyint(3) unsigned NOT NULL default '0',
cond_1_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_1_val_2 mediumint(8) unsigned NOT NULL default '0',
cond_2 tinyint(3) unsigned NOT NULL default '0',
cond_2_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_2_val_2 mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (entry, text_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `gossip_menu`
--
LOCK TABLES `gossip_menu` WRITE;
/*!40000 ALTER TABLE `gossip_menu` DISABLE KEYS */;
/*!40000 ALTER TABLE `gossip_menu` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `gossip_menu_option`
--
DROP TABLE IF EXISTS gossip_menu_option;
CREATE TABLE gossip_menu_option (
menu_id smallint(6) unsigned NOT NULL default '0',
id smallint(6) unsigned NOT NULL default '0',
option_icon mediumint(8) unsigned NOT NULL default '0',
option_text text,
option_id tinyint(3) unsigned NOT NULL default '0',
npc_option_npcflag int(10) unsigned NOT NULL default '0',
action_menu_id mediumint(8) unsigned NOT NULL default '0',
action_poi_id mediumint(8) unsigned NOT NULL default '0',
action_script_id mediumint(8) unsigned NOT NULL default '0',
box_coded tinyint(3) unsigned NOT NULL default '0',
box_money int(11) unsigned NOT NULL default '0',
box_text text,
cond_1 tinyint(3) unsigned NOT NULL default '0',
cond_1_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_1_val_2 mediumint(8) unsigned NOT NULL default '0',
cond_2 tinyint(3) unsigned NOT NULL default '0',
cond_2_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_2_val_2 mediumint(8) unsigned NOT NULL default '0',
cond_3 tinyint(3) unsigned NOT NULL default '0',
cond_3_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_3_val_2 mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (menu_id, id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `gossip_menu_option`
--
LOCK TABLES `gossip_menu_option` WRITE;
/*!40000 ALTER TABLE `gossip_menu_option` DISABLE KEYS */;
INSERT INTO gossip_menu_option VALUES
(0,0,0,'GOSSIP_OPTION_QUESTGIVER',2,2,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,1,1,'GOSSIP_OPTION_VENDOR',3,128,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,2,2,'GOSSIP_OPTION_TAXIVENDOR',4,8192,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,3,3,'GOSSIP_OPTION_TRAINER',5,16,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,4,4,'GOSSIP_OPTION_SPIRITHEALER',6,16384,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,5,4,'GOSSIP_OPTION_SPIRITGUIDE',7,32768,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,6,5,'GOSSIP_OPTION_INNKEEPER',8,65536,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,7,6,'GOSSIP_OPTION_BANKER',9,131072,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,8,7,'GOSSIP_OPTION_PETITIONER',10,262144,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,9,8,'GOSSIP_OPTION_TABARDDESIGNER',11,524288,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,10,9,'GOSSIP_OPTION_BATTLEFIELD',12,1048576,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,11,6,'GOSSIP_OPTION_AUCTIONEER',13,2097152,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,12,0,'GOSSIP_OPTION_STABLEPET',14,4194304,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,13,1,'GOSSIP_OPTION_ARMORER',15,4096,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,14,2,'GOSSIP_OPTION_UNLEARNTALENTS',16,16,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,15,2,'GOSSIP_OPTION_UNLEARNPETSKILLS',17,16,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0);
/*!40000 ALTER TABLE `gossip_menu_option` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `gossip_scripts`
--
DROP TABLE IF EXISTS `gossip_scripts`;
CREATE TABLE `gossip_scripts` (
`id` mediumint(8) unsigned NOT NULL default '0',
`delay` int(10) unsigned NOT NULL default '0',
`command` mediumint(8) unsigned NOT NULL default '0',
`datalong` mediumint(8) unsigned NOT NULL default '0',
`datalong2` int(10) unsigned NOT NULL default '0',
`dataint` int(11) NOT NULL default '0',
`x` float NOT NULL default '0',
`y` float NOT NULL default '0',
`z` float NOT NULL default '0',
`o` float NOT NULL default '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `gossip_scripts`
--
LOCK TABLES `gossip_scripts` WRITE;
/*!40000 ALTER TABLE `gossip_scripts` DISABLE KEYS */;
/*!40000 ALTER TABLE `gossip_scripts` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `instance_template`
--
@ -2344,6 +2455,42 @@ LOCK TABLES `locales_gameobject` WRITE;
/*!40000 ALTER TABLE `locales_gameobject` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `locales_gossip_menu_option`
--
DROP TABLE IF EXISTS `locales_gossip_menu_option`;
CREATE TABLE `locales_gossip_menu_option` (
`menu_id` smallint(6) unsigned NOT NULL default '0',
`id` smallint(6) unsigned NOT NULL default '0',
`option_text_loc1` text,
`option_text_loc2` text,
`option_text_loc3` text,
`option_text_loc4` text,
`option_text_loc5` text,
`option_text_loc6` text,
`option_text_loc7` text,
`option_text_loc8` text,
`box_text_loc1` text,
`box_text_loc2` text,
`box_text_loc3` text,
`box_text_loc4` text,
`box_text_loc5` text,
`box_text_loc6` text,
`box_text_loc7` text,
`box_text_loc8` text,
PRIMARY KEY (`menu_id`, `id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `locales_gossip_menu_option`
--
LOCK TABLES `locales_gossip_menu_option` WRITE;
/*!40000 ALTER TABLE `locales_gossip_menu_option` DISABLE KEYS */;
/*!40000 ALTER TABLE `locales_gossip_menu_option` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `locales_item`
--
@ -2379,42 +2526,6 @@ LOCK TABLES `locales_item` WRITE;
/*!40000 ALTER TABLE `locales_item` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `locales_npc_option`
--
DROP TABLE IF EXISTS `locales_npc_option`;
CREATE TABLE `locales_npc_option` (
`entry` mediumint(8) unsigned NOT NULL default '0',
`option_text_loc1` text,
`option_text_loc2` text,
`option_text_loc3` text,
`option_text_loc4` text,
`option_text_loc5` text,
`option_text_loc6` text,
`option_text_loc7` text,
`option_text_loc8` text,
`box_text_loc1` text,
`box_text_loc2` text,
`box_text_loc3` text,
`box_text_loc4` text,
`box_text_loc5` text,
`box_text_loc6` text,
`box_text_loc7` text,
`box_text_loc8` text,
PRIMARY KEY (`entry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `locales_npc_option`
--
LOCK TABLES `locales_npc_option` WRITE;
/*!40000 ALTER TABLE `locales_npc_option` DISABLE KEYS */;
/*!40000 ALTER TABLE `locales_npc_option` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `locales_npc_text`
--
@ -3446,6 +3557,7 @@ INSERT INTO `mangos_string` VALUES
(1012,'===========================================================================',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1013,'|%15s| %20s | %15s |%4d| %9d |',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1014,'No online players.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1015,'Used not fully typed quit command, need type it fully (quit), or command used not in RA command line.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1100,'Account %s (Id: %u) have up to %u expansion allowed now.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1101,'Message of the day changed to:\r\n%s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1102,'Message sent to %s: %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
@ -3530,54 +3642,6 @@ LOCK TABLES `npc_gossip` WRITE;
/*!40000 ALTER TABLE `npc_gossip` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `npc_gossip_textid`
--
DROP TABLE IF EXISTS `npc_gossip_textid`;
CREATE TABLE `npc_gossip_textid` (
`zoneid` smallint(5) unsigned NOT NULL default '0',
`action` smallint(5) unsigned NOT NULL default '0',
`textid` mediumint(8) unsigned NOT NULL default '0',
KEY `zoneid` (`zoneid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `npc_gossip_textid`
--
LOCK TABLES `npc_gossip_textid` WRITE;
/*!40000 ALTER TABLE `npc_gossip_textid` DISABLE KEYS */;
/*!40000 ALTER TABLE `npc_gossip_textid` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `npc_option`
--
DROP TABLE IF EXISTS `npc_option`;
CREATE TABLE `npc_option` (
`id` mediumint(8) unsigned NOT NULL default '0',
`gossip_id` mediumint(8) unsigned NOT NULL default '0',
`npcflag` int(10) unsigned NOT NULL default '0',
`icon` tinyint(3) unsigned NOT NULL default '0',
`action` mediumint(8) unsigned NOT NULL default '0',
`box_money` int(10) unsigned NOT NULL default '0',
`coded` tinyint(3) unsigned NOT NULL default '0',
`option_text` text,
`box_text` text,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `npc_option`
--
LOCK TABLES `npc_option` WRITE;
/*!40000 ALTER TABLE `npc_option` DISABLE KEYS */;
/*!40000 ALTER TABLE `npc_option` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `npc_spellclick_spells`
--
@ -14087,7 +14151,7 @@ INSERT INTO `spell_bonus_data` VALUES
(3606, 0.1667, 0, 0, 'Shaman - Searing Totem Attack'),
/* Warlock */
(17962, 0, 0, 0, 'Warlock - Conflagrate'),
(172, 0, 0.3, 0, 'Warlock - Corruption'),
(172, 0, 0.2, 0, 'Warlock - Corruption'),
(980, 0, 0.1, 0, 'Warlock - Curse of Agony'),
(603, 0, 2, 0, 'Warlock - Curse of Doom'),
(18220, 0.96, 0, 0, 'Warlock - Dark Pact'),
@ -15283,6 +15347,18 @@ INSERT INTO spell_chain VALUES
(26801,12180,3908,5,0),
(51309,26790,3908,6,0),
/*------------------
-- (202) Engineering
------------------*/
/*Engineering*/
(4036,0,4036,1,0),
(4037,4036,4036,2,0),
(4038,4037,4036,3,0),
(12656,4038,4036,4,0),
(20219,12656,4036,5,0),
(20222,12656,4036,5,0),
(30350,12656,4036,5,0),
(51306,30350,4036,6,0),
/*------------------
--(203)Pet-Spider
--(208)Pet-Wolf
--(212)Pet-Crocolisk
@ -15304,18 +15380,6 @@ INSERT INTO spell_chain VALUES
(52473,27050,17253,10,0),
(52474,52473,17253,11,0),
/*------------------
-- (202) Engineering
------------------*/
/*Engineering*/
(4036,0,4036,1,0),
(4037,4036,4036,2,0),
(4038,4037,4036,3,0),
(12656,4038,4036,4,0),
(20219,12656,4036,5,0),
(20222,12656,4036,5,0),
(30350,12656,4036,5,0),
(51306,30350,4036,6,0),
/*------------------
-- (204) Pet - Voidwalker
------------------*/
/*Consume Shadows*/
@ -15376,6 +15440,16 @@ INSERT INTO spell_chain VALUES
(11785,11784,6360,4,0),
(27275,11785,6360,5,0),
/*------------------
-- (208) Pet - Wolf
------------------*/
/* Furious Howl */
(24604,0,24604,1,0),
(64491,24604,24604,2,0),
(64492,64491,24604,3,0),
(64493,64492,24604,4,0),
(64494,64493,24604,5,0),
(64495,64494,24604,6,0),
/*------------------
-- (209) Pet - Cat
------------------*/
/*Prowl*/
@ -17033,6 +17107,16 @@ INSERT INTO spell_chain VALUES
(53597,53596,50274,5,0),
(53598,53597,50274,6,0),
/*------------------
--(767)Pet - Ravager
------------------*/
/*Ravage*/
(50518,0,50518,1,0),
(53558,50518,50518,2,0),
(53559,53558,50518,3,0),
(53560,53559,50518,4,0),
(53561,53560,50518,5,0),
(53562,53561,50518,6,0),
/*------------------
--(768)Pet-Serpent
------------------*/
/*PoisonSpit*/
@ -18168,6 +18252,7 @@ INSERT INTO `spell_proc_event` VALUES
(49622, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 60),
(49657, 0x00000000, 15, 0x00000000, 0x00004000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(50781, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(50880, 0x00000010, 15, 0x00000000, 0x00000800, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(51123, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(51127, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(51128, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
@ -18286,6 +18371,7 @@ INSERT INTO `spell_proc_event` VALUES
(54936, 0x00000000, 10, 0x40000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(54937, 0x00000000, 10, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(54939, 0x00000000, 10, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(55166, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(55380, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45),
(55440, 0x00000000, 11, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(55640, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45),
@ -18322,6 +18408,7 @@ INSERT INTO `spell_proc_event` VALUES
(57352, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00010154, 0x00000003, 0.000000, 0.000000, 45),
(57470, 0x00000000, 6, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(57472, 0x00000000, 6, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(57499, 0x00000000, 4, 0x40000001, 0x00010000, 0x00000000, 0x00014000, 0x00000000, 0.000000, 0.000000, 0),
(57878, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0.000000, 0.000000, 0),
(57880, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0.000000, 0.000000, 0),
(57881, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0.000000, 0.000000, 0),
@ -18330,6 +18417,7 @@ INSERT INTO `spell_proc_event` VALUES
(58364, 0x00000000, 4, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(58372, 0x00000000, 4, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(58386, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000020, 0.000000, 0.000000, 0),
(58597, 0x00000000, 10, 0x40000000, 0x00000000, 0x00000000, 0x00008000, 0x00000000, 0.000000, 100.000000,0),
(58616, 0x00000000, 15, 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(58620, 0x00000000, 15, 0x00000000, 0x00004000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(58626, 0x00000000, 15, 0x02000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
@ -18386,7 +18474,7 @@ INSERT INTO `spell_proc_event` VALUES
(63730, 0x00000000, 6, 0x00000800, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(64928, 0x00000000, 11, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(64976, 0x00000000, 4, 0x00000001, 0x00000000, 0x00000000, 0x00010000, 0x00000000, 0.000000, 0.000000, 0),
(65661, 0x00000000, 15, 0x00400010, 0x20020004, 0x00000000, 0x00000010, 0x00000000, 0.000000, 100.000000,0),
(65661, 0x00000000, 15, 0x00400011, 0x00020004, 0x00000000, 0x00000010, 0x00000001, 0.000000, 100.000000,0),
(64127, 0x00000000, 6, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(67353, 0x00000000, 7, 0x00008000, 0x00100500, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0);

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_8912_01_mangos_spell_proc_event required_8917_01_mangos_spell_proc_event bit;
DELETE FROM `spell_proc_event` WHERE `entry` IN (65661);
INSERT INTO `spell_proc_event` VALUES
(65661, 0x00000000, 15, 0x00400011, 0x00020004, 0x00000000, 0x00000010, 0x00000001, 0.000000, 100.000000,0);

View file

@ -0,0 +1,72 @@
ALTER TABLE db_version CHANGE COLUMN required_8917_01_mangos_spell_proc_event required_8923_01_mangos_gossip bit;
DROP TABLE IF EXISTS gossip_menu;
CREATE TABLE gossip_menu (
entry smallint(6) unsigned NOT NULL default '0',
text_id mediumint(8) unsigned NOT NULL default '0',
cond_1 tinyint(3) unsigned NOT NULL default '0',
cond_1_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_1_val_2 mediumint(8) unsigned NOT NULL default '0',
cond_2 tinyint(3) unsigned NOT NULL default '0',
cond_2_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_2_val_2 mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (entry, text_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS gossip_menu_option;
CREATE TABLE gossip_menu_option (
menu_id smallint(6) unsigned NOT NULL default '0',
id smallint(6) unsigned NOT NULL default '0',
option_icon mediumint(8) unsigned NOT NULL default '0',
option_text text,
option_id tinyint(3) unsigned NOT NULL default '0',
npc_option_npcflag int(10) unsigned NOT NULL default '0',
action_menu_id mediumint(8) unsigned NOT NULL default '0',
action_poi_id mediumint(8) unsigned NOT NULL default '0',
action_script_id mediumint(8) unsigned NOT NULL default '0',
box_coded tinyint(3) unsigned NOT NULL default '0',
box_money int(11) unsigned NOT NULL default '0',
box_text text,
cond_1 tinyint(3) unsigned NOT NULL default '0',
cond_1_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_1_val_2 mediumint(8) unsigned NOT NULL default '0',
cond_2 tinyint(3) unsigned NOT NULL default '0',
cond_2_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_2_val_2 mediumint(8) unsigned NOT NULL default '0',
cond_3 tinyint(3) unsigned NOT NULL default '0',
cond_3_val_1 mediumint(8) unsigned NOT NULL default '0',
cond_3_val_2 mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (menu_id, id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DELETE FROM gossip_menu_option WHERE menu_id=0;
INSERT INTO gossip_menu_option VALUES
(0,0,0,'GOSSIP_OPTION_QUESTGIVER',2,2,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,1,1,'GOSSIP_OPTION_VENDOR',3,128,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,2,2,'GOSSIP_OPTION_TAXIVENDOR',4,8192,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,3,3,'GOSSIP_OPTION_TRAINER',5,16,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,4,4,'GOSSIP_OPTION_SPIRITHEALER',6,16384,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,5,4,'GOSSIP_OPTION_SPIRITGUIDE',7,32768,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,6,5,'GOSSIP_OPTION_INNKEEPER',8,65536,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,7,6,'GOSSIP_OPTION_BANKER',9,131072,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,8,7,'GOSSIP_OPTION_PETITIONER',10,262144,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,9,8,'GOSSIP_OPTION_TABARDDESIGNER',11,524288,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,10,9,'GOSSIP_OPTION_BATTLEFIELD',12,1048576,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,11,6,'GOSSIP_OPTION_AUCTIONEER',13,2097152,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,12,0,'GOSSIP_OPTION_STABLEPET',14,4194304,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,13,1,'GOSSIP_OPTION_ARMORER',15,4096,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,14,2,'GOSSIP_OPTION_UNLEARNTALENTS',16,16,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0),
(0,15,2,'GOSSIP_OPTION_UNLEARNPETSKILLS',17,16,0,0,0,0,0,NULL,0,0,0,0,0,0,0,0,0);
ALTER TABLE creature_template ADD gossip_menu_id mediumint(8) unsigned NOT NULL default 0 AFTER IconName;
ALTER TABLE locales_npc_option CHANGE COLUMN entry id smallint(6) unsigned NOT NULL default '0';
ALTER TABLE locales_npc_option ADD menu_id smallint(6) unsigned NOT NULL default '0' FIRST;
ALTER TABLE locales_npc_option DROP PRIMARY KEY;
ALTER TABLE locales_npc_option ADD PRIMARY KEY (menu_id, id);
RENAME TABLE locales_npc_option TO locales_gossip_menu_option;
DROP TABLE IF EXISTS npc_option;
DROP TABLE IF EXISTS npc_gossip_textid;

View file

@ -0,0 +1,15 @@
ALTER TABLE db_version CHANGE COLUMN required_8923_01_mangos_gossip required_8929_01_mangos_gossip_scripts bit;
DROP TABLE IF EXISTS `gossip_scripts`;
CREATE TABLE `gossip_scripts` (
`id` mediumint(8) unsigned NOT NULL default '0',
`delay` int(10) unsigned NOT NULL default '0',
`command` mediumint(8) unsigned NOT NULL default '0',
`datalong` mediumint(8) unsigned NOT NULL default '0',
`datalong2` int(10) unsigned NOT NULL default '0',
`dataint` int(11) NOT NULL default '0',
`x` float NOT NULL default '0',
`y` float NOT NULL default '0',
`z` float NOT NULL default '0',
`o` float NOT NULL default '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_8929_01_mangos_gossip_scripts required_8930_01_mangos_spell_proc_event bit;
DELETE FROM `spell_proc_event` WHERE `entry` IN (58597);
INSERT INTO `spell_proc_event` VALUES
(58597, 0x00000000, 10, 0x40000000, 0x00000000, 0x00000000, 0x00008000, 0x00000000, 0.000000, 100.000000,0);

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_8930_01_mangos_spell_proc_event required_8931_01_mangos_spell_bonus_data bit;
DELETE FROM spell_bonus_data WHERE entry = 172;
INSERT INTO spell_bonus_data (entry, direct_bonus, dot_bonus, ap_bonus, comments) VALUES
(172, 0, 0.2, 0, 'Warlock - Corruption');

View file

@ -0,0 +1,10 @@
ALTER TABLE db_version CHANGE COLUMN required_8931_01_mangos_spell_bonus_data required_8932_01_mangos_spell_chain bit;
DELETE FROM spell_chain WHERE spell_id IN (50518,53558,53559,53560,53561,53562);
INSERT INTO spell_chain VALUES
(50518,0,50518,1,0),
(53558,50518,50518,2,0),
(53559,53558,50518,3,0),
(53560,53559,50518,4,0),
(53561,53560,50518,5,0),
(53562,53561,50518,6,0);

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_8932_01_mangos_spell_chain required_8938_01_mangos_spell_proc_event bit;
DELETE FROM `spell_proc_event` WHERE `entry` IN (50880);
INSERT INTO `spell_proc_event` VALUES
(50880, 0x00000010, 15, 0x00000000, 0x00000800, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0);

View file

@ -0,0 +1,11 @@
ALTER TABLE db_version CHANGE COLUMN required_8938_01_mangos_spell_proc_event required_8943_01_mangos_spell_chain bit;
DELETE FROM spell_chain WHERE spell_id IN (24604,64491,64492,64493,64494,64495);
-- Furious Howl
INSERT INTO spell_chain VALUES
(24604,0,24604,1,0),
(64491,24604,24604,2,0),
(64492,64491,24604,3,0),
(64493,64492,24604,4,0),
(64494,64493,24604,5,0),
(64495,64494,24604,6,0);

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_8943_01_mangos_spell_chain required_8946_01_mangos_spell_proc_event bit;
DELETE FROM `spell_proc_event` WHERE `entry` IN (57499);
INSERT INTO `spell_proc_event` VALUES
(57499, 0x00000000, 4, 0x40000001, 0x00010000, 0x00000000, 0x00014000, 0x00000000, 0.000000, 0.000000,0);

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_8946_01_mangos_spell_proc_event required_8950_01_mangos_spell_proc_event bit;
DELETE FROM `spell_proc_event` WHERE `entry` IN (55166);
INSERT INTO `spell_proc_event` VALUES
(55166, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000,0);

View file

@ -0,0 +1,6 @@
ALTER TABLE db_version CHANGE COLUMN required_8950_01_mangos_spell_proc_event required_8965_01_mangos_mangos_string bit;
DELETE FROM mangos_string WHERE entry in (1015);
INSERT INTO mangos_string VALUES
(1015,'Used not fully typed quit command, need type it fully (quit), or command used not in RA command line.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);

View file

@ -0,0 +1,6 @@
ALTER TABLE db_version CHANGE COLUMN required_8965_01_mangos_mangos_string required_8965_02_mangos_command bit;
DELETE FROM command where name IN ('quit');
INSERT INTO `command` VALUES
('quit',4,'Syntax: quit\r\n\r\nClose RA connection. Command must be typed fully (quit).');

View file

@ -188,6 +188,18 @@ pkgdata_DATA = \
8908_01_mangos_spell_chain.sql \
8909_01_mangos_spell_proc_event.sql \
8912_01_mangos_spell_proc_event.sql \
8917_01_mangos_spell_proc_event.sql \
8923_01_mangos_gossip.sql \
8929_01_mangos_gossip_scripts.sql \
8930_01_mangos_spell_proc_event.sql \
8931_01_mangos_spell_bonus_data.sql \
8932_01_mangos_spell_chain.sql \
8938_01_mangos_spell_proc_event.sql \
8943_01_mangos_spell_chain.sql \
8946_01_mangos_spell_proc_event.sql \
8950_01_mangos_spell_proc_event.sql \
8965_01_mangos_mangos_string.sql \
8965_02_mangos_command.sql \
README
## Additional files to include when running 'make dist'
@ -356,4 +368,16 @@ EXTRA_DIST = \
8908_01_mangos_spell_chain.sql \
8909_01_mangos_spell_proc_event.sql \
8912_01_mangos_spell_proc_event.sql \
8917_01_mangos_spell_proc_event.sql \
8923_01_mangos_gossip.sql \
8929_01_mangos_gossip_scripts.sql \
8930_01_mangos_spell_proc_event.sql \
8931_01_mangos_spell_bonus_data.sql \
8932_01_mangos_spell_chain.sql \
8938_01_mangos_spell_proc_event.sql \
8943_01_mangos_spell_chain.sql \
8946_01_mangos_spell_proc_event.sql \
8950_01_mangos_spell_proc_event.sql \
8965_01_mangos_mangos_string.sql \
8965_02_mangos_command.sql \
README

View file

@ -519,11 +519,13 @@ void BattleGround::SendPacketToAll(WorldPacket *packet)
{
for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first);
if (plr)
plr->GetSession()->SendPacket(packet);
else
sLog.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
sLog.outError("BattleGround:SendPacketToAll: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
}
}
@ -531,11 +533,12 @@ void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *
{
for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr)
{
sLog.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
sLog.outError("BattleGround:SendPacketToTeam: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
continue;
}
@ -563,11 +566,13 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr)
{
sLog.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
sLog.outError("BattleGround:PlaySoundToTeam: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
continue;
}
@ -586,11 +591,13 @@ void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
{
for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr)
{
sLog.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
sLog.outError("BattleGround:CastSpellOnTeam: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
continue;
}
@ -606,11 +613,13 @@ void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
{
for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr)
{
sLog.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
sLog.outError("BattleGround:RewardHonorToTeam: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
continue;
}
@ -631,11 +640,13 @@ void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation,
for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr)
{
sLog.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
sLog.outError("BattleGround:RewardReputationToTeam: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
continue;
}
@ -721,10 +732,9 @@ void BattleGround::EndBattleGround(uint32 winner)
for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player *plr = sObjectMgr.GetPlayer(itr->first);
uint32 team = itr->second.Team;
if (!plr)
if (itr->second.OfflineRemoveTime)
{
//if rated arena match - make member lost!
if (isArena() && isRated() && winner_arena_team && loser_arena_team)
@ -734,7 +744,12 @@ void BattleGround::EndBattleGround(uint32 winner)
else
loser_arena_team->OfflineMemberLost(itr->first, winner_rating);
}
sLog.outError("BattleGround: Player (GUID: %u) not found!", GUID_LOPART(itr->first));
continue;
}
Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr)
{
sLog.outError("BattleGround:EndBattleGround Player (GUID: %u) not found!", GUID_LOPART(itr->first));
continue;
}
@ -1285,14 +1300,13 @@ void BattleGround::EventPlayerLoggedOut(Player* player)
m_Players[player->GetGUID()].OfflineRemoveTime = sWorld.GetGameTime() + MAX_OFFLINE_TIME;
if (GetStatus() == STATUS_IN_PROGRESS)
{
if (isBattleGround())
EventPlayerDroppedFlag(player);
else
{
//1 player is logging out, if it is the last, then end arena!
// drop flag and handle other cleanups
RemovePlayer(player, player->GetGUID());
// 1 player is logging out, if it is the last, then end arena!
if (isArena())
if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())))
EndBattleGround(GetOtherTeam(player->GetTeam()));
}
}
}

View file

@ -134,7 +134,7 @@ void BattleGroundEY::CheckSomeoneJoinedPoint()
Player *plr = sObjectMgr.GetPlayer(m_PlayersNearPoint[BG_EY_NODES_MAX][j]);
if (!plr)
{
sLog.outError("BattleGroundEY: Player (GUID: %u) not found!", GUID_LOPART(m_PlayersNearPoint[BG_EY_NODES_MAX][j]));
sLog.outError("BattleGroundEY:CheckSomeoneJoinedPoint: Player (GUID: %u) not found!", GUID_LOPART(m_PlayersNearPoint[BG_EY_NODES_MAX][j]));
++j;
continue;
}
@ -170,7 +170,7 @@ void BattleGroundEY::CheckSomeoneLeftPoint()
Player *plr = sObjectMgr.GetPlayer(m_PlayersNearPoint[i][j]);
if (!plr)
{
sLog.outError("BattleGroundEY: Player (GUID: %u) not found!", GUID_LOPART(m_PlayersNearPoint[i][j]));
sLog.outError("BattleGroundEY:CheckSomeoneLeftPoint Player (GUID: %u) not found!", GUID_LOPART(m_PlayersNearPoint[i][j]));
//move not existed player to "free space" - this will cause many error showing in log, but it is a very important bug
m_PlayersNearPoint[BG_EY_NODES_MAX].push_back(m_PlayersNearPoint[i][j]);
m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j);

View file

@ -366,7 +366,8 @@ void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
//if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue
if (_player->getLevel() > bg->GetMaxLevel())
{
sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow());
sLog.outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!",
_player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID());
action = 0;
}
}

View file

@ -698,7 +698,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder *holder)
if(at)
pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation());
else
pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation());
pCurrChar->TeleportToHomebind();
}
sObjectAccessor.AddObject(pCurrChar);

View file

@ -423,6 +423,8 @@ ChatCommand * ChatHandler::getCommandTable()
{ "gameobject_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGOQuestRelationsCommand, "", NULL },
{ "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL },
{ "gameobject_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL },
{ "gossip_menu", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGossipMenuCommand, "", NULL },
{ "gossip_menu_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGossipMenuOptionCommand, "", NULL },
{ "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL },
{ "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL },
{ "item_required_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemRequiredTragetCommand, "", NULL },
@ -439,7 +441,6 @@ ChatCommand * ChatHandler::getCommandTable()
{ "mangos_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadMangosStringCommand, "", NULL },
{ "milling_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesMillingCommand, "", NULL },
{ "npc_gossip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcGossipCommand, "", NULL },
{ "npc_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcOptionCommand, "", NULL },
{ "npc_spellclick_spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellClickSpellsCommand, "",NULL},
{ "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL },
{ "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL },
@ -666,6 +667,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "flusharenapoints",SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
{ "repairitems", SEC_GAMEMASTER, true, &ChatHandler::HandleRepairitemsCommand, "", NULL },
{ "waterwalk", SEC_GAMEMASTER, false, &ChatHandler::HandleWaterwalkCommand, "", NULL },
{ "quit", SEC_CONSOLE, true, &ChatHandler::HandleQuitCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};

View file

@ -335,6 +335,8 @@ class ChatHandler
bool HandleReloadGameGraveyardZoneCommand(const char* args);
bool HandleReloadGameObjectScriptsCommand(const char* args);
bool HandleReloadGameTeleCommand(const char* args);
bool HandleReloadGossipMenuCommand(const char* args);
bool HandleReloadGossipMenuOptionCommand(const char* args);
bool HandleReloadGOQuestRelationsCommand(const char* args);
bool HandleReloadGOQuestInvRelationsCommand(const char* args);
bool HandleReloadItemEnchantementsCommand(const char* args);
@ -362,7 +364,6 @@ class ChatHandler
bool HandleReloadMailLevelRewardCommand(const char* args);
bool HandleReloadMangosStringCommand(const char* args);
bool HandleReloadNpcGossipCommand(const char* args);
bool HandleReloadNpcOptionCommand(const char* args);
bool HandleReloadNpcTrainerCommand(const char* args);
bool HandleReloadNpcVendorCommand(const char* args);
bool HandleReloadPageTextsCommand(const char* args);
@ -497,6 +498,7 @@ class ChatHandler
bool HandleFlushArenaPointsCommand(const char *args);
bool HandleRepairitemsCommand(const char* args);
bool HandleWaterwalkCommand(const char* args);
bool HandleQuitCommand(const char* args);
//! Development Commands
bool HandleSaveAllCommand(const char* args);

View file

@ -110,7 +110,7 @@ Unit(), i_AI(NULL),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0),
m_lootMoney(0), m_lootRecipient(0),
m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f),
m_gossipOptionLoaded(false), m_isPet(false), m_isVehicle(false), m_isTotem(false),
m_isPet(false), m_isVehicle(false), m_isTotem(false),
m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0),
m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false),
m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
@ -744,21 +744,6 @@ bool Creature::isCanTrainingAndResetTalentsOf(Player* pPlayer) const
&& pPlayer->getClass() == GetCreatureInfo()->trainer_class;
}
void Creature::LoadGossipOptions()
{
if(m_gossipOptionLoaded)
return;
uint32 npcflags=GetUInt32Value(UNIT_NPC_FLAGS);
CacheNpcOptionList const& noList = sObjectMgr.GetNpcOptions ();
for (CacheNpcOptionList::const_iterator i = noList.begin (); i != noList.end (); ++i)
if(i->NpcFlag & npcflags)
addGossipOption(*i);
m_gossipOptionLoaded = true;
}
void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, MonsterMovementFlags flags, uint8 type)
{
/* uint32 timeElap = getMSTime();

View file

@ -36,102 +36,6 @@ class Quest;
class Player;
class WorldSession;
enum Gossip_Option
{
GOSSIP_OPTION_NONE = 0, //UNIT_NPC_FLAG_NONE = 0,
GOSSIP_OPTION_GOSSIP = 1, //UNIT_NPC_FLAG_GOSSIP = 1,
GOSSIP_OPTION_QUESTGIVER = 2, //UNIT_NPC_FLAG_QUESTGIVER = 2,
GOSSIP_OPTION_VENDOR = 3, //UNIT_NPC_FLAG_VENDOR = 4,
GOSSIP_OPTION_TAXIVENDOR = 4, //UNIT_NPC_FLAG_TAXIVENDOR = 8,
GOSSIP_OPTION_TRAINER = 5, //UNIT_NPC_FLAG_TRAINER = 16,
GOSSIP_OPTION_SPIRITHEALER = 6, //UNIT_NPC_FLAG_SPIRITHEALER = 32,
GOSSIP_OPTION_SPIRITGUIDE = 7, //UNIT_NPC_FLAG_SPIRITGUIDE = 64,
GOSSIP_OPTION_INNKEEPER = 8, //UNIT_NPC_FLAG_INNKEEPER = 128,
GOSSIP_OPTION_BANKER = 9, //UNIT_NPC_FLAG_BANKER = 256,
GOSSIP_OPTION_PETITIONER = 10, //UNIT_NPC_FLAG_PETITIONER = 512,
GOSSIP_OPTION_TABARDDESIGNER = 11, //UNIT_NPC_FLAG_TABARDDESIGNER = 1024,
GOSSIP_OPTION_BATTLEFIELD = 12, //UNIT_NPC_FLAG_BATTLEFIELDPERSON = 2048,
GOSSIP_OPTION_AUCTIONEER = 13, //UNIT_NPC_FLAG_AUCTIONEER = 4096,
GOSSIP_OPTION_STABLEPET = 14, //UNIT_NPC_FLAG_STABLE = 8192,
GOSSIP_OPTION_ARMORER = 15, //UNIT_NPC_FLAG_ARMORER = 16384,
GOSSIP_OPTION_UNLEARNTALENTS = 16, //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER)
GOSSIP_OPTION_UNLEARNPETSKILLS = 17 //UNIT_NPC_FLAG_TRAINER (bonus option for GOSSIP_OPTION_TRAINER)
};
enum Gossip_Guard
{
GOSSIP_GUARD_BANK = 32,
GOSSIP_GUARD_RIDE = 33,
GOSSIP_GUARD_GUILD = 34,
GOSSIP_GUARD_INN = 35,
GOSSIP_GUARD_MAIL = 36,
GOSSIP_GUARD_AUCTION = 37,
GOSSIP_GUARD_WEAPON = 38,
GOSSIP_GUARD_STABLE = 39,
GOSSIP_GUARD_BATTLE = 40,
GOSSIP_GUARD_SPELLTRAINER = 41,
GOSSIP_GUARD_SKILLTRAINER = 42
};
enum Gossip_Guard_Spell
{
GOSSIP_GUARD_SPELL_WARRIOR = 64,
GOSSIP_GUARD_SPELL_PALADIN = 65,
GOSSIP_GUARD_SPELL_HUNTER = 66,
GOSSIP_GUARD_SPELL_ROGUE = 67,
GOSSIP_GUARD_SPELL_PRIEST = 68,
GOSSIP_GUARD_SPELL_UNKNOWN1 = 69,
GOSSIP_GUARD_SPELL_SHAMAN = 70,
GOSSIP_GUARD_SPELL_MAGE = 71,
GOSSIP_GUARD_SPELL_WARLOCK = 72,
GOSSIP_GUARD_SPELL_UNKNOWN2 = 73,
GOSSIP_GUARD_SPELL_DRUID = 74
};
enum Gossip_Guard_Skill
{
GOSSIP_GUARD_SKILL_ALCHEMY = 80,
GOSSIP_GUARD_SKILL_BLACKSMITH = 81,
GOSSIP_GUARD_SKILL_COOKING = 82,
GOSSIP_GUARD_SKILL_ENCHANT = 83,
GOSSIP_GUARD_SKILL_FIRSTAID = 84,
GOSSIP_GUARD_SKILL_FISHING = 85,
GOSSIP_GUARD_SKILL_HERBALISM = 86,
GOSSIP_GUARD_SKILL_LEATHER = 87,
GOSSIP_GUARD_SKILL_MINING = 88,
GOSSIP_GUARD_SKILL_SKINNING = 89,
GOSSIP_GUARD_SKILL_TAILORING = 90,
GOSSIP_GUARD_SKILL_ENGINERING = 91
};
enum GossipOptionIcon
{
GOSSIP_ICON_CHAT = 0, //white chat bubble
GOSSIP_ICON_VENDOR = 1, //brown bag
GOSSIP_ICON_TAXI = 2, //flight
GOSSIP_ICON_TRAINER = 3, //book
GOSSIP_ICON_INTERACT_1 = 4, //interaction wheel
GOSSIP_ICON_INTERACT_2 = 5, //interaction wheel
GOSSIP_ICON_MONEY_BAG = 6, //brown bag with yellow dot
GOSSIP_ICON_TALK = 7, //white chat bubble with black dots
GOSSIP_ICON_TABARD = 8, //tabard
GOSSIP_ICON_BATTLE = 9, //two swords
GOSSIP_ICON_DOT = 10 //yellow dot
};
struct GossipOption
{
uint32 Id;
uint32 GossipId;
uint32 NpcFlag;
uint32 Icon;
uint32 Action;
uint32 BoxMoney;
bool Coded;
std::string OptionText;
std::string BoxText;
};
enum CreatureFlagsExtra
{
CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
@ -165,6 +69,7 @@ struct CreatureInfo
char* Name;
char* SubName;
char* IconName;
uint32 GossipMenuId;
uint32 minlevel;
uint32 maxlevel;
uint32 minhealth;
@ -259,7 +164,7 @@ struct CreatureLocale
std::vector<std::string> SubName;
};
struct NpcOptionLocale
struct GossipMenuItemsLocale
{
std::vector<std::string> OptionText;
std::vector<std::string> BoxText;
@ -449,8 +354,6 @@ struct TrainerSpellData
void Clear() { spellList.clear(); }
};
typedef std::list<GossipOption> GossipOptionList;
typedef std::map<uint32,time_t> CreatureSpellCooldowns;
// max different by z coordinate for creature aggro reaction
@ -576,10 +479,6 @@ class MANGOS_DLL_SPEC Creature : public Unit
std::string GetScriptName() const;
uint32 GetScriptId() const;
void LoadGossipOptions();
void addGossipOption(GossipOption const& gso) { m_goptions.push_back(gso); }
GossipOptionList &GetGossipOptionList() { return m_goptions; }
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
void TextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(textId,TargetGuid,IsBossEmote); }
@ -708,9 +607,6 @@ class MANGOS_DLL_SPEC Creature : public Unit
uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
float m_respawnradius;
bool m_gossipOptionLoaded;
GossipOptionList m_goptions;
bool m_isPet; // set only in Pet::Pet
bool m_isVehicle; // set only in Vehicle::Vehicle
bool m_isTotem; // set only in Totem::Totem

View file

@ -327,26 +327,26 @@ enum TotemCategoryType
// SummonProperties.dbc, col 1
enum SummonPropGroup
{
SUMMON_PROP_GROUP_UNKNOWN1 = 0, // 1160 spells in 3.0.3
SUMMON_PROP_GROUP_UNKNOWN2 = 1, // 861 spells in 3.0.3
SUMMON_PROP_GROUP_PETS = 2, // 52 spells in 3.0.3, pets mostly
SUMMON_PROP_GROUP_CONTROLLABLE = 3, // 13 spells in 3.0.3, mostly controllable
SUMMON_PROP_GROUP_UNKNOWN3 = 4 // 86 spells in 3.0.3, taxi/mounts
SUMMON_PROP_GROUP_WILD = 0,
SUMMON_PROP_GROUP_FRIENDLY = 1,
SUMMON_PROP_GROUP_PETS = 2,
SUMMON_PROP_GROUP_CONTROLLABLE = 3,
SUMMON_PROP_GROUP_VEHICLE = 4
};
// SummonProperties.dbc, col 3
enum SummonPropType
{
SUMMON_PROP_TYPE_UNKNOWN = 0, // different summons, 1330 spells in 3.0.3
SUMMON_PROP_TYPE_OTHER = 0, // different summons, 1330 spells in 3.0.3
SUMMON_PROP_TYPE_SUMMON = 1, // generic summons, 49 spells in 3.0.3
SUMMON_PROP_TYPE_GUARDIAN = 2, // summon guardian, 393 spells in 3.0.3
SUMMON_PROP_TYPE_ARMY = 3, // summon army, 5 spells in 3.0.3
SUMMON_PROP_TYPE_TOTEM = 4, // summon totem, 169 spells in 3.0.3
SUMMON_PROP_TYPE_CRITTER = 5, // critter/minipet, 195 spells in 3.0.3
SUMMON_PROP_TYPE_DK = 6, // summon DRW/Ghoul, 2 spells in 3.0.3
SUMMON_PROP_TYPE_BOMB = 7, // summon bot/bomb, 4 spells in 3.0.3
SUMMON_PROP_TYPE_PHASING = 8, // something todo with DK prequest line, 2 spells in 3.0.3
SUMMON_PROP_TYPE_SIEGE_VEH = 9, // summon different vehicles, 14 spells in 3.0.3
SUMMON_PROP_TYPE_DK = 6, // summon DRW/Ghoul, 2 spells in 3.0.3 "%s's Runeblade"
SUMMON_PROP_TYPE_CONSTRUCT = 7, // summon bot/bomb, 4 spells in 3.0.3 "%s's Construct"
SUMMON_PROP_TYPE_PHASING = 8, // something todo with DK prequest line, 2 spells in 3.0.3 "%s's Opponent"
SUMMON_PROP_TYPE_SIEGE_VEH = 9, // summon different vehicles, 14 spells in 3.0.3 "%s's Vehicle"
SUMMON_PROP_TYPE_DRAKE_VEH = 10, // summon drake (vehicle), 3 spells
SUMMON_PROP_TYPE_LIGHTWELL = 11 // summon lightwell, 6 spells in 3.0.3
};

View file

@ -129,7 +129,7 @@ DBCStorage <SpellRangeEntry> sSpellRangeStore(SpellRangefmt);
DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore(SpellRuneCostfmt);
DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt);
DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
//DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
TalentSpellPosMap sTalentSpellPosMap;
DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt);
@ -206,7 +206,7 @@ void LoadDBCStores(const std::string& dataPath)
{
std::string dbcPath = dataPath+"dbc/";
const uint32 DBCFilesCount = 80;
const uint32 DBCFilesCount = 81;
barGoLink bar( DBCFilesCount );
@ -360,7 +360,7 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRuneCostStore, dbcPath,"SpellRuneCost.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellShapeshiftStore, dbcPath,"SpellShapeshiftForm.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sStableSlotPricesStore, dbcPath,"StableSlotPrices.dbc");
//LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSummonPropertiesStore, dbcPath,"SummonProperties.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSummonPropertiesStore, dbcPath,"SummonProperties.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentStore, dbcPath,"Talent.dbc");
// create talent spells set

View file

@ -136,7 +136,7 @@ extern DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore;
extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore;
extern DBCStorage <SpellEntry> sSpellStore;
extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore;
//extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore;
extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore;
extern DBCStorage <TalentEntry> sTalentStore;
extern DBCStorage <TalentTabEntry> sTalentTabStore;
extern DBCStorage <TaxiNodesEntry> sTaxiNodesStore;

View file

@ -1540,17 +1540,15 @@ struct StableSlotPricesEntry
uint32 Price;
};
/* unused currently
struct SummonPropertiesEntry
{
uint32 Id; // 0
uint32 Group; // 1, enum SummonPropGroup, 0 - can't be controlled?, 1 - something guardian?, 2 - pet?, 3 - something controllable?, 4 - taxi/mount?
uint32 Group; // 1, enum SummonPropGroup
uint32 FactionId; // 2, 14 rows > 0
uint32 Type; // 3, enum SummonPropType
uint32 Slot; // 4, 0-6
uint32 Slot; // 4, if type = SUMMON_PROP_TYPE_TOTEM, its actual slot 0-6
uint32 Flags; // 5, enum SummonPropFlags
};
*/
#define MAX_TALENT_RANK 5
#define MAX_PET_TALENT_RANK 3 // use in calculations, expected <= MAX_TALENT_RANK

View file

@ -93,7 +93,7 @@ const char SpellRangefmt[]="nffffxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char SpellRuneCostfmt[]="niiii";
const char SpellShapeshiftfmt[]="nxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxx";
const char StableSlotPricesfmt[] = "ni";
//const char SummonPropertiesfmt[] = "niiiii";
const char SummonPropertiesfmt[] = "niiiii";
const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxxxx";
const char TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiiix";
const char TaxiNodesEntryfmt[]="nifffssssssssssssssssxii";

View file

@ -872,13 +872,13 @@ void GameObject::Use(Unit* user)
case GAMEOBJECT_TYPE_QUESTGIVER: //2
{
if(user->GetTypeId()!=TYPEID_PLAYER)
if (user->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)user;
player->PrepareQuestMenu( GetGUID() );
player->SendPreparedQuest( GetGUID() );
player->PrepareGossipMenu(this, GetGOInfo()->questgiver.gossipID);
player->SendPreparedGossip(this);
return;
}
//Sitting: Wooden bench, chairs enzz
@ -952,12 +952,17 @@ void GameObject::Use(Unit* user)
Player* player = (Player*)user;
// show page
if(info->goober.pageId)
if (info->goober.pageId)
{
WorldPacket data(SMSG_GAMEOBJECT_PAGETEXT, 8);
data << GetGUID();
player->GetSession()->SendPacket(&data);
}
else if (info->questgiver.gossipID)
{
player->PrepareGossipMenu(this, info->goober.gossipID);
player->SendPreparedGossip(this);
}
// possible quest objective for active quests
player->CastedCreatureOrGO(info->id, GetGUID(), 0);

View file

@ -489,6 +489,16 @@ struct GameObjectInfo
default: return 0;
}
}
uint32 GetGossipMenuId() const
{
switch(type)
{
case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.gossipID;
case GAMEOBJECT_TYPE_GOOBER: return goober.gossipID;
default: return 0;
}
}
};
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform

View file

@ -27,6 +27,7 @@
GossipMenu::GossipMenu()
{
m_gItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use
m_gMenuId = 0;
}
GossipMenu::~GossipMenu()
@ -44,13 +45,24 @@ void GossipMenu::AddMenuItem(uint8 Icon, const std::string& Message, uint32 dtSe
gItem.m_gMessage = Message;
gItem.m_gCoded = Coded;
gItem.m_gSender = dtSender;
gItem.m_gAction = dtAction;
gItem.m_gOptionId = dtAction;
gItem.m_gBoxMessage = BoxMessage;
gItem.m_gBoxMoney = BoxMoney;
m_gItems.push_back(gItem);
}
void GossipMenu::AddGossipMenuItemData(uint32 action_menu, uint32 action_poi, uint32 action_script)
{
GossipMenuItemData pItemData;
pItemData.m_gAction_menu = action_menu;
pItemData.m_gAction_poi = action_poi;
pItemData.m_gAction_script = action_script;
m_gItemsData.push_back(pItemData);
}
void GossipMenu::AddMenuItem(uint8 Icon, const std::string& Message, bool Coded)
{
AddMenuItem( Icon, Message, 0, 0, "", 0, Coded);
@ -77,7 +89,7 @@ uint32 GossipMenu::MenuItemAction( unsigned int ItemId )
{
if ( ItemId >= m_gItems.size() ) return 0;
return m_gItems[ ItemId ].m_gAction;
return m_gItems[ ItemId ].m_gOptionId;
}
bool GossipMenu::MenuItemCoded( unsigned int ItemId )
@ -90,6 +102,8 @@ bool GossipMenu::MenuItemCoded( unsigned int ItemId )
void GossipMenu::ClearMenu()
{
m_gItems.clear();
m_gItemsData.clear();
m_gMenuId = 0;
}
PlayerMenu::PlayerMenu( WorldSession *session ) : pSession(session)
@ -122,13 +136,13 @@ bool PlayerMenu::GossipOptionCoded( unsigned int Selection )
return mGossipMenu.MenuItemCoded( Selection );
}
void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID )
void PlayerMenu::SendGossipMenu(uint32 TitleTextId, uint64 objectGUID)
{
WorldPacket data( SMSG_GOSSIP_MESSAGE, (100) ); // guess size
data << uint64(npcGUID);
data << uint32(0); // new 2.4.0
data << uint32( TitleTextId );
data << uint32( mGossipMenu.MenuItemCount() ); // max count 0x10
WorldPacket data(SMSG_GOSSIP_MESSAGE, (100)); // guess size
data << uint64(objectGUID);
data << uint32(mGossipMenu.GetMenuId()); // new 2.4.0
data << uint32(TitleTextId);
data << uint32(mGossipMenu.MenuItemCount()); // max count 0x10
for (uint32 iI = 0; iI < mGossipMenu.MenuItemCount(); ++iI )
{

View file

@ -28,6 +28,45 @@ class WorldSession;
#define GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough
#define DEFAULT_GOSSIP_MESSAGE 0xffffff
enum Gossip_Option
{
GOSSIP_OPTION_NONE = 0, //UNIT_NPC_FLAG_NONE (0)
GOSSIP_OPTION_GOSSIP = 1, //UNIT_NPC_FLAG_GOSSIP (1)
GOSSIP_OPTION_QUESTGIVER = 2, //UNIT_NPC_FLAG_QUESTGIVER (2)
GOSSIP_OPTION_VENDOR = 3, //UNIT_NPC_FLAG_VENDOR (128)
GOSSIP_OPTION_TAXIVENDOR = 4, //UNIT_NPC_FLAG_TAXIVENDOR (8192)
GOSSIP_OPTION_TRAINER = 5, //UNIT_NPC_FLAG_TRAINER (16)
GOSSIP_OPTION_SPIRITHEALER = 6, //UNIT_NPC_FLAG_SPIRITHEALER (16384)
GOSSIP_OPTION_SPIRITGUIDE = 7, //UNIT_NPC_FLAG_SPIRITGUIDE (32768)
GOSSIP_OPTION_INNKEEPER = 8, //UNIT_NPC_FLAG_INNKEEPER (65536)
GOSSIP_OPTION_BANKER = 9, //UNIT_NPC_FLAG_BANKER (131072)
GOSSIP_OPTION_PETITIONER = 10, //UNIT_NPC_FLAG_PETITIONER (262144)
GOSSIP_OPTION_TABARDDESIGNER = 11, //UNIT_NPC_FLAG_TABARDDESIGNER (524288)
GOSSIP_OPTION_BATTLEFIELD = 12, //UNIT_NPC_FLAG_BATTLEFIELDPERSON (1048576)
GOSSIP_OPTION_AUCTIONEER = 13, //UNIT_NPC_FLAG_AUCTIONEER (2097152)
GOSSIP_OPTION_STABLEPET = 14, //UNIT_NPC_FLAG_STABLE (4194304)
GOSSIP_OPTION_ARMORER = 15, //UNIT_NPC_FLAG_ARMORER (4096)
GOSSIP_OPTION_UNLEARNTALENTS = 16, //UNIT_NPC_FLAG_TRAINER (16) (bonus option for GOSSIP_OPTION_TRAINER)
GOSSIP_OPTION_UNLEARNPETSKILLS = 17, //UNIT_NPC_FLAG_TRAINER (16) (bonus option for GOSSIP_OPTION_TRAINER)
GOSSIP_OPTION_MAX
};
enum GossipOptionIcon
{
GOSSIP_ICON_CHAT = 0, //white chat bubble
GOSSIP_ICON_VENDOR = 1, //brown bag
GOSSIP_ICON_TAXI = 2, //flight
GOSSIP_ICON_TRAINER = 3, //book
GOSSIP_ICON_INTERACT_1 = 4, //interaction wheel
GOSSIP_ICON_INTERACT_2 = 5, //interaction wheel
GOSSIP_ICON_MONEY_BAG = 6, //brown bag with yellow dot
GOSSIP_ICON_TALK = 7, //white chat bubble with black dots
GOSSIP_ICON_TABARD = 8, //tabard
GOSSIP_ICON_BATTLE = 9, //two swords
GOSSIP_ICON_DOT = 10, //yellow dot
GOSSIP_ICON_MAX
};
//POI icons. Many more exist, list not complete.
enum Poi_Icon
{
@ -80,13 +119,22 @@ struct GossipMenuItem
bool m_gCoded;
std::string m_gMessage;
uint32 m_gSender;
uint32 m_gAction;
uint32 m_gOptionId;
std::string m_gBoxMessage;
uint32 m_gBoxMoney;
};
typedef std::vector<GossipMenuItem> GossipMenuItemList;
struct GossipMenuItemData
{
uint32 m_gAction_menu;
uint32 m_gAction_poi;
uint32 m_gAction_script;
};
typedef std::vector<GossipMenuItemData> GossipMenuItemDataList;
struct QuestMenuItem
{
uint32 m_qId;
@ -108,6 +156,11 @@ class MANGOS_DLL_SPEC GossipMenu
void AddMenuItem(uint8 Icon, char const* Message, bool Coded = false);
void AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded = false);
void SetMenuId(uint32 menu_id) { m_gMenuId = menu_id; }
uint32 GetMenuId() { return m_gMenuId; }
void AddGossipMenuItemData(uint32 action_menu, uint32 action_poi, uint32 action_script);
unsigned int MenuItemCount() const
{
return m_gItems.size();
@ -123,6 +176,11 @@ class MANGOS_DLL_SPEC GossipMenu
return m_gItems[ Id ];
}
GossipMenuItemData const& GetItemData(unsigned int indexId)
{
return m_gItemsData[indexId];
}
uint32 MenuItemSender( unsigned int ItemId );
uint32 MenuItemAction( unsigned int ItemId );
bool MenuItemCoded( unsigned int ItemId );
@ -130,7 +188,10 @@ class MANGOS_DLL_SPEC GossipMenu
void ClearMenu();
protected:
GossipMenuItemList m_gItems;
GossipMenuItemList m_gItems;
GossipMenuItemDataList m_gItemsData;
uint32 m_gMenuId;
};
class QuestMenu

View file

@ -780,7 +780,8 @@ enum MangosStrings
LANG_ACCOUNT_LIST_BAR = 1012,
LANG_ACCOUNT_LIST_LINE = 1013,
LANG_ACCOUNT_LIST_EMPTY = 1014,
// Room for more level 4 1015-1099 not used
LANG_QUIT_WRONG_USE_ERROR = 1015,
// Room for more level 4 1016-1099 not used
// Level 3 (continue)
LANG_ACCOUNT_SETADDON = 1100,

View file

@ -102,7 +102,6 @@ bool ChatHandler::HandleReloadAllLootCommand(const char*)
bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/)
{
HandleReloadNpcGossipCommand("a");
HandleReloadNpcOptionCommand("a");
HandleReloadNpcTrainerCommand("a");
HandleReloadNpcVendorCommand("a");
HandleReloadPointsOfInterestCommand("a");
@ -252,6 +251,22 @@ bool ChatHandler::HandleReloadCreatureQuestInvRelationsCommand(const char*)
return true;
}
bool ChatHandler::HandleReloadGossipMenuCommand(const char*)
{
sLog.outString( "Re-Loading `gossip_menu` Table!" );
sObjectMgr.LoadGossipMenu();
SendGlobalSysMessage("DB table `gossip_menu` reloaded.");
return true;
}
bool ChatHandler::HandleReloadGossipMenuOptionCommand(const char*)
{
sLog.outString( "Re-Loading `gossip_menu_option` Table!" );
sObjectMgr.LoadGossipMenuItems();
SendGlobalSysMessage("DB table `gossip_menu_option` reloaded.");
return true;
}
bool ChatHandler::HandleReloadGOQuestRelationsCommand(const char*)
{
sLog.outString( "Loading Quests Relations... (`gameobject_questrelation`)" );
@ -404,14 +419,6 @@ bool ChatHandler::HandleReloadMangosStringCommand(const char*)
return true;
}
bool ChatHandler::HandleReloadNpcOptionCommand(const char*)
{
sLog.outString( "Re-Loading `npc_option` Table!" );
sObjectMgr.LoadNpcOptions();
SendGlobalSysMessage("DB table `npc_option` reloaded.");
return true;
}
bool ChatHandler::HandleReloadNpcGossipCommand(const char*)
{
sLog.outString( "Re-Loading `npc_gossip` Table!" );

View file

@ -2617,7 +2617,7 @@ void InstanceMap::UnloadAll(bool pForce)
for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
{
Player* plr = itr->getSource();
plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
plr->TeleportToHomebind();
}
}

View file

@ -50,12 +50,12 @@ void WorldSession::HandleMoveWorldportAckOpcode()
// possible errors in the coordinate validity check
if(!MapManager::IsValidMapCoord(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation))
{
sLog.outError("WorldSession::HandleMoveWorldportAckOpcode: player got's teleported far to a not valid location. (map:%u, x:%f, y:%f, z:%f) We log him out and don't save him..", loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z);
// stop teleportation else we would try this again in the beginning of WorldSession::LogoutPlayer...
sLog.outError("WorldSession::HandleMoveWorldportAckOpcode: player %s (%d) was teleported far to a not valid location. (map:%u, x:%f, y:%f, "
"z:%f) We port him to his homebind instead..", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z);
// stop teleportation else we would try this again and again in LogoutPlayer...
GetPlayer()->SetSemaphoreTeleportFar(false);
// player don't gets saved - so his coords will stay at the point where
// he was last saved
LogoutPlayer(false);
// and teleport the player to a valid place
GetPlayer()->TeleportToHomebind();
return;
}
@ -81,14 +81,10 @@ void WorldSession::HandleMoveWorldportAckOpcode()
//if player wasn't added to map, reset his map pointer!
GetPlayer()->ResetMap();
sLog.outDebug("WORLD: teleport of player %s (%d) to location %d, %f, %f, %f, %f failed", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation);
sLog.outError("WorldSession::HandleMoveWorldportAckOpcode: player %s (%d) was teleported far but couldn't be added to map. (map:%u, x:%f, y:%f, "
"z:%f) We port him to his homebind instead..", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z);
// teleport the player home
if(!GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()))
{
// the player must always be able to teleport home
sLog.outError("WORLD: failed to teleport player %s (%d) to homebind location %d, %f, %f, %f, %f!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
assert(false);
}
GetPlayer()->TeleportToHomebind();
return;
}
@ -242,7 +238,6 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
ReadMovementInfo(recv_data, &movementInfo);
/*----------------*/
recv_data.rpos(recv_data.wpos()); // prevent warnings spam
if (!MaNGOS::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o))
{
recv_data.rpos(recv_data.wpos()); // prevent warnings spam

View file

@ -277,7 +277,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data)
if (!Script->GossipHello(_player, pCreature))
{
_player->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID());
_player->PrepareGossipMenu(pCreature);
_player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId);
_player->SendPreparedGossip(pCreature);
}
}
@ -286,41 +286,58 @@ void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
{
sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION");
uint32 option;
uint32 gossipListId;
uint32 menuId;
uint64 guid;
std::string code = "";
recv_data >> guid >> menuId >> option;
recv_data >> guid >> menuId >> gossipListId;
if (_player->PlayerTalkClass->GossipOptionCoded(option))
if (_player->PlayerTalkClass->GossipOptionCoded(gossipListId))
{
sLog.outBasic("reading string");
recv_data >> code;
sLog.outBasic("string read: %s", code.c_str());
}
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!pCreature)
{
sLog.outDebug( "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
return;
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
if (!code.empty())
// TODO: determine if scriptCall is needed for GO and also if scriptCall can be same as current, with modified argument WorldObject*
if (IS_CREATURE_GUID(guid))
{
if (!Script->GossipSelectWithCode(_player, pCreature, _player->PlayerTalkClass->GossipOptionSender(option), _player->PlayerTalkClass->GossipOptionAction(option), code.c_str()))
_player->OnGossipSelect(pCreature, option);
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!pCreature)
{
sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Creature (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid)));
return;
}
if (!code.empty())
{
if (!Script->GossipSelectWithCode(_player, pCreature, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str()))
_player->OnGossipSelect(pCreature, gossipListId, menuId);
}
else
{
if (!Script->GossipSelect(_player, pCreature, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId)))
_player->OnGossipSelect(pCreature, gossipListId, menuId);
}
}
else
else if (IS_GAMEOBJECT_GUID(guid))
{
if (!Script->GossipSelect(_player, pCreature, _player->PlayerTalkClass->GossipOptionSender(option), _player->PlayerTalkClass->GossipOptionAction(option)))
_player->OnGossipSelect(pCreature, option);
GameObject *pGo = GetPlayer()->GetGameObjectIfCanInteractWith(guid);
if (!pGo)
{
sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - GameObject (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid)));
return;
}
_player->OnGossipSelect(pGo, gossipListId, menuId);
}
}
@ -410,13 +427,7 @@ void WorldSession::SendBindPoint(Creature *npc)
uint32 bindspell = 3286;
uint32 zone_id = _player->GetZoneId();
// update sql homebind
CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), zone_id, _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow());
_player->m_homebindMapId = _player->GetMapId();
_player->m_homebindZoneId = zone_id;
_player->m_homebindX = _player->GetPositionX();
_player->m_homebindY = _player->GetPositionY();
_player->m_homebindZ = _player->GetPositionZ();
_player->SetHomebindToCurrentPos();
// send spell for bind 3286 bind magic
npc->CastSpell(_player, bindspell, true);

View file

@ -43,6 +43,7 @@
#include "SpellAuras.h"
#include "Util.h"
#include "WaypointManager.h"
#include "GossipDef.h"
INSTANTIATE_SINGLETON_1(ObjectMgr);
@ -51,6 +52,7 @@ ScriptMapMap sQuestStartScripts;
ScriptMapMap sSpellScripts;
ScriptMapMap sGameObjectScripts;
ScriptMapMap sEventScripts;
ScriptMapMap sGossipScripts;
bool normalizePlayerName(std::string& name)
{
@ -338,16 +340,16 @@ void ObjectMgr::LoadCreatureLocales()
sLog.outString( ">> Loaded %lu creature locale strings", (unsigned long)mCreatureLocaleMap.size() );
}
void ObjectMgr::LoadNpcOptionLocales()
void ObjectMgr::LoadGossipMenuItemsLocales()
{
mNpcOptionLocaleMap.clear(); // need for reload case
mGossipMenuItemsLocaleMap.clear(); // need for reload case
QueryResult *result = WorldDatabase.Query("SELECT entry,"
QueryResult *result = WorldDatabase.Query("SELECT menu_id,id,"
"option_text_loc1,box_text_loc1,option_text_loc2,box_text_loc2,"
"option_text_loc3,box_text_loc3,option_text_loc4,box_text_loc4,"
"option_text_loc5,box_text_loc5,option_text_loc6,box_text_loc6,"
"option_text_loc7,box_text_loc7,option_text_loc8,box_text_loc8 "
"FROM locales_npc_option");
"FROM locales_gossip_menu_option");
if(!result)
{
@ -356,7 +358,7 @@ void ObjectMgr::LoadNpcOptionLocales()
bar.step();
sLog.outString();
sLog.outString(">> Loaded 0 npc_option locale strings. DB table `locales_npc_option` is empty.");
sLog.outString(">> Loaded 0 gossip_menu_option locale strings. DB table `locales_gossip_menu_option` is empty.");
return;
}
@ -367,13 +369,14 @@ void ObjectMgr::LoadNpcOptionLocales()
Field *fields = result->Fetch();
bar.step();
uint32 entry = fields[0].GetUInt32();
uint16 menuId = fields[0].GetUInt16();
uint16 id = fields[1].GetUInt16();
NpcOptionLocale& data = mNpcOptionLocaleMap[entry];
GossipMenuItemsLocale& data = mGossipMenuItemsLocaleMap[MAKE_PAIR32(menuId,id)];
for(int i = 1; i < MAX_LOCALE; ++i)
{
std::string str = fields[1+2*(i-1)].GetCppString();
std::string str = fields[2+2*(i-1)].GetCppString();
if(!str.empty())
{
int idx = GetOrNewIndexForLocale(LocaleConstant(i));
@ -385,7 +388,7 @@ void ObjectMgr::LoadNpcOptionLocales()
data.OptionText[idx] = str;
}
}
str = fields[1+2*(i-1)+1].GetCppString();
str = fields[2+2*(i-1)+1].GetCppString();
if(!str.empty())
{
int idx = GetOrNewIndexForLocale(LocaleConstant(i));
@ -403,7 +406,7 @@ void ObjectMgr::LoadNpcOptionLocales()
delete result;
sLog.outString();
sLog.outString( ">> Loaded %lu npc_option locale strings", (unsigned long)mNpcOptionLocaleMap.size() );
sLog.outString( ">> Loaded %lu gossip_menu_option locale strings", (unsigned long)mGossipMenuItemsLocaleMap.size() );
}
void ObjectMgr::LoadPointOfInterestLocales()
@ -4441,6 +4444,13 @@ void ObjectMgr::LoadEventScripts()
}
}
void ObjectMgr::LoadGossipScripts()
{
LoadScripts(sGossipScripts, "gossip_scripts");
// checks are done in LoadGossipMenuItems
}
void ObjectMgr::LoadItemTexts()
{
QueryResult *result = CharacterDatabase.Query("SELECT id, text FROM item_text");
@ -7296,6 +7306,15 @@ bool PlayerCondition::Meets(Player const * player) const
return !player->HasAura(value1, value2);
case CONDITION_ACTIVE_EVENT:
return sGameEventMgr.IsActiveEvent(value1);
case CONDITION_AREA_FLAG:
{
if (AreaTableEntry const *pAreaEntry = GetAreaEntryByAreaID(player->GetAreaId()))
{
if ((!value1 || (pAreaEntry->flags & value1)) && (!value2 || !(pAreaEntry->flags & value2)))
return true;
}
return false;
}
default:
return false;
}
@ -7440,6 +7459,15 @@ bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 val
}
break;
}
case CONDITION_AREA_FLAG:
{
if (!value1 && !value2)
{
sLog.outErrorDb("Area flag condition has both values like 0, skipped");
return false;
}
break;
}
case CONDITION_NONE:
break;
}
@ -7887,23 +7915,21 @@ void ObjectMgr::LoadNpcTextId()
sLog.outString( ">> Loaded %d NpcTextId ", count );
}
void ObjectMgr::LoadNpcOptions()
void ObjectMgr::LoadGossipMenu()
{
m_mCacheNpcOptionList.clear(); // For reload case
m_mGossipMenusMap.clear();
QueryResult *result = WorldDatabase.Query(
// 0 1 2 3 4 5 6 7 8
"SELECT id,gossip_id,npcflag,icon,action,box_money,coded,option_text,box_text "
"FROM npc_option");
QueryResult* result = WorldDatabase.Query("SELECT entry, text_id, "
"cond_1, cond_1_val_1, cond_1_val_2, cond_2, cond_2_val_1, cond_2_val_2 FROM gossip_menu");
if( !result )
if (!result)
{
barGoLink bar( 1 );
barGoLink bar(1);
bar.step();
sLog.outString();
sLog.outErrorDb(">> Loaded `npc_option`, table is empty!");
sLog.outErrorDb(">> Loaded gossip_menu, table is empty!");
return;
}
@ -7917,26 +7943,186 @@ void ObjectMgr::LoadNpcOptions()
Field* fields = result->Fetch();
GossipOption go;
go.Id = fields[0].GetUInt32();
go.GossipId = fields[1].GetUInt32();
go.NpcFlag = fields[2].GetUInt32();
go.Icon = fields[3].GetUInt32();
go.Action = fields[4].GetUInt32();
go.BoxMoney = fields[5].GetUInt32();
go.Coded = fields[6].GetUInt8()!=0;
go.OptionText = fields[7].GetCppString();
go.BoxText = fields[8].GetCppString();
GossipMenus gMenu;
m_mCacheNpcOptionList.push_back(go);
gMenu.entry = fields[0].GetUInt32();
gMenu.text_id = fields[1].GetUInt32();
ConditionType cond_1 = (ConditionType)fields[2].GetUInt32();
uint32 cond_1_val_1 = fields[3].GetUInt32();
uint32 cond_1_val_2 = fields[4].GetUInt32();
ConditionType cond_2 = (ConditionType)fields[5].GetUInt32();
uint32 cond_2_val_1 = fields[6].GetUInt32();
uint32 cond_2_val_2 = fields[7].GetUInt32();
if (!GetGossipText(gMenu.text_id))
{
sLog.outErrorDb("Table gossip_menu entry %u are using non-existing text_id %u", gMenu.entry, gMenu.text_id);
continue;
}
if (!PlayerCondition::IsValid(cond_1, cond_1_val_1, cond_1_val_2))
{
sLog.outErrorDb("Table gossip_menu entry %u, invalid condition 1 for id %u", gMenu.entry, gMenu.text_id);
continue;
}
if (!PlayerCondition::IsValid(cond_2, cond_2_val_1, cond_2_val_2))
{
sLog.outErrorDb("Table gossip_menu entry %u, invalid condition 2 for id %u", gMenu.entry, gMenu.text_id);
continue;
}
gMenu.cond_1 = GetConditionId(cond_1, cond_1_val_1, cond_1_val_2);
gMenu.cond_2 = GetConditionId(cond_2, cond_2_val_1, cond_2_val_2);
m_mGossipMenusMap.insert(GossipMenusMap::value_type(gMenu.entry, gMenu));
++count;
}
while(result->NextRow());
} while (result->NextRow());
delete result;
sLog.outString();
sLog.outString( ">> Loaded %d npc_option entries", count );
sLog.outString( ">> Loaded %u gossip_menu entries", count);
}
void ObjectMgr::LoadGossipMenuItems()
{
m_mGossipMenuItemsMap.clear();
QueryResult *result = WorldDatabase.Query(
"SELECT menu_id, id, option_icon, option_text, option_id, npc_option_npcflag, "
"action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text, "
"cond_1, cond_1_val_1, cond_1_val_2, "
"cond_2, cond_2_val_1, cond_2_val_2, "
"cond_3, cond_3_val_1, cond_3_val_2 "
"FROM gossip_menu_option");
if (!result)
{
barGoLink bar(1);
bar.step();
sLog.outString();
sLog.outErrorDb(">> Loaded gossip_menu_option, table is empty!");
return;
}
barGoLink bar(result->GetRowCount());
uint32 count = 0;
std::set<uint32> gossipScriptSet;
for(ScriptMapMap::const_iterator itr = sGossipScripts.begin(); itr != sGossipScripts.end(); ++itr)
gossipScriptSet.insert(itr->first);
do
{
bar.step();
Field* fields = result->Fetch();
GossipMenuItems gMenuItem;
gMenuItem.menu_id = fields[0].GetUInt32();
gMenuItem.id = fields[1].GetUInt32();
gMenuItem.option_icon = fields[2].GetUInt8();
gMenuItem.option_text = fields[3].GetCppString();
gMenuItem.option_id = fields[4].GetUInt32();
gMenuItem.npc_option_npcflag = fields[5].GetUInt32();
gMenuItem.action_menu_id = fields[6].GetUInt32();
gMenuItem.action_poi_id = fields[7].GetUInt32();
gMenuItem.action_script_id = fields[8].GetUInt32();
gMenuItem.box_coded = fields[9].GetUInt8() != 0;
gMenuItem.box_money = fields[10].GetUInt32();
gMenuItem.box_text = fields[11].GetCppString();
ConditionType cond_1 = (ConditionType)fields[12].GetUInt32();
uint32 cond_1_val_1 = fields[13].GetUInt32();
uint32 cond_1_val_2 = fields[14].GetUInt32();
ConditionType cond_2 = (ConditionType)fields[15].GetUInt32();
uint32 cond_2_val_1 = fields[16].GetUInt32();
uint32 cond_2_val_2 = fields[17].GetUInt32();
ConditionType cond_3 = (ConditionType)fields[18].GetUInt32();
uint32 cond_3_val_1 = fields[19].GetUInt32();
uint32 cond_3_val_2 = fields[20].GetUInt32();
if (!PlayerCondition::IsValid(cond_1, cond_1_val_1, cond_1_val_2))
{
sLog.outErrorDb("Table gossip_menu_option menu %u, invalid condition 1 for id %u", gMenuItem.menu_id, gMenuItem.id);
continue;
}
if (!PlayerCondition::IsValid(cond_2, cond_2_val_1, cond_2_val_2))
{
sLog.outErrorDb("Table gossip_menu_option menu %u, invalid condition 2 for id %u", gMenuItem.menu_id, gMenuItem.id);
continue;
}
if (!PlayerCondition::IsValid(cond_3, cond_3_val_1, cond_3_val_2))
{
sLog.outErrorDb("Table gossip_menu_option menu %u, invalid condition 3 for id %u", gMenuItem.menu_id, gMenuItem.id);
continue;
}
if (gMenuItem.option_icon >= GOSSIP_ICON_MAX)
{
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown icon id %u. Replacing with GOSSIP_ICON_CHAT", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_icon);
gMenuItem.option_icon = GOSSIP_ICON_CHAT;
}
if (gMenuItem.option_id == GOSSIP_OPTION_NONE)
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u use option id GOSSIP_OPTION_NONE. Option will never be used", gMenuItem.menu_id, gMenuItem.id);
if (gMenuItem.option_id >= GOSSIP_OPTION_MAX)
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_id);
if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id))
{
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u use non-existing action_poi_id %u, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_poi_id);
gMenuItem.action_poi_id = 0;
}
if (gMenuItem.action_script_id)
{
if (gMenuItem.option_id != GOSSIP_OPTION_GOSSIP)
{
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u have action_script_id %u but option_id is not GOSSIP_OPTION_GOSSIP, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_script_id);
continue;
}
if (sGossipScripts.find(gMenuItem.action_script_id) == sGossipScripts.end())
{
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u have action_script_id %u that does not exist in `gossip_scripts`, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_script_id);
continue;
}
gossipScriptSet.erase(gMenuItem.action_script_id);
}
gMenuItem.cond_1 = GetConditionId(cond_1, cond_1_val_1, cond_1_val_2);
gMenuItem.cond_2 = GetConditionId(cond_2, cond_2_val_1, cond_2_val_2);
gMenuItem.cond_3 = GetConditionId(cond_3, cond_3_val_1, cond_3_val_2);
m_mGossipMenuItemsMap.insert(GossipMenuItemsMap::value_type(gMenuItem.menu_id, gMenuItem));
++count;
}
while(result->NextRow());
delete result;
if (!gossipScriptSet.empty())
{
for(std::set<uint32>::const_iterator itr = gossipScriptSet.begin(); itr != gossipScriptSet.end(); ++itr)
sLog.outErrorDb("Table `gossip_scripts` contain unused script, id %u.", *itr);
}
sLog.outString();
sLog.outString(">> Loaded %u gossip_menu_option entries", count);
}
void ObjectMgr::AddVendorItem( uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 extendedcost )

View file

@ -93,6 +93,7 @@ extern ScriptMapMap sQuestStartScripts;
extern ScriptMapMap sSpellScripts;
extern ScriptMapMap sGameObjectScripts;
extern ScriptMapMap sEventScripts;
extern ScriptMapMap sGossipScripts;
struct SpellClickInfo
{
@ -162,7 +163,7 @@ typedef UNORDERED_MAP<uint32,QuestLocale> QuestLocaleMap;
typedef UNORDERED_MAP<uint32,NpcTextLocale> NpcTextLocaleMap;
typedef UNORDERED_MAP<uint32,PageTextLocale> PageTextLocaleMap;
typedef UNORDERED_MAP<int32,MangosStringLocale> MangosStringLocaleMap;
typedef UNORDERED_MAP<uint32,NpcOptionLocale> NpcOptionLocaleMap;
typedef UNORDERED_MAP<uint32,GossipMenuItemsLocale> GossipMenuItemsLocaleMap;
typedef UNORDERED_MAP<uint32,PointOfInterestLocale> PointOfInterestLocaleMap;
typedef std::multimap<uint32,uint32> QuestRelations;
@ -216,6 +217,38 @@ struct PointOfInterest
std::string icon_name;
};
struct GossipMenuItems
{
uint32 menu_id;
uint32 id;
uint8 option_icon;
std::string option_text;
uint32 option_id;
uint32 npc_option_npcflag;
uint32 action_menu_id;
uint32 action_poi_id;
uint32 action_script_id;
bool box_coded;
uint32 box_money;
std::string box_text;
uint16 cond_1;
uint16 cond_2;
uint16 cond_3;
};
struct GossipMenus
{
uint32 entry;
uint32 text_id;
uint16 cond_1;
uint16 cond_2;
};
typedef std::multimap<uint32,GossipMenus> GossipMenusMap;
typedef std::pair<GossipMenusMap::const_iterator, GossipMenusMap::const_iterator> GossipMenusMapBounds;
typedef std::multimap<uint32,GossipMenuItems> GossipMenuItemsMap;
typedef std::pair<GossipMenuItemsMap::const_iterator, GossipMenuItemsMap::const_iterator> GossipMenuItemsMapBounds;
struct QuestPOIPoint
{
int32 x;
@ -223,6 +256,16 @@ struct QuestPOIPoint
QuestPOIPoint() : x(0), y(0) {}
QuestPOIPoint(int32 _x, int32 _y) : x(_x), y(_y) {}
uint32 npc_option_npcflag;
uint32 action_menu_id;
uint32 action_poi_id;
uint32 action_script_id;
bool box_coded;
uint32 box_money;
std::string box_text;
uint16 cond_1;
uint16 cond_2;
uint16 cond_3;
};
struct QuestPOI
@ -277,9 +320,10 @@ enum ConditionType
CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD commission aura active
CONDITION_NO_AURA = 11, // spell_id effindex
CONDITION_ACTIVE_EVENT = 12, // event_id
CONDITION_AREA_FLAG = 13 // area_flag area_flag_not
};
#define MAX_CONDITION 13 // maximum value in ConditionType enum
#define MAX_CONDITION 14 // maximum value in ConditionType enum
struct PlayerCondition
{
@ -301,7 +345,6 @@ struct PlayerCondition
// NPC gossip text id
typedef UNORDERED_MAP<uint32, uint32> CacheNpcTextIdMap;
typedef std::list<GossipOption> CacheNpcOptionList;
typedef UNORDERED_MAP<uint32, VendorItemData> CacheVendorItemMap;
typedef UNORDERED_MAP<uint32, TrainerSpellData> CacheTrainerSpellMap;
@ -539,6 +582,7 @@ class ObjectMgr
void LoadQuestStartScripts();
void LoadEventScripts();
void LoadSpellScripts();
void LoadGossipScripts();
bool LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value);
bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase,"mangos_string",MIN_MANGOS_STRING_ID,MAX_MANGOS_STRING_ID); }
@ -559,7 +603,7 @@ class ObjectMgr
void LoadQuestLocales();
void LoadNpcTextLocales();
void LoadPageTextLocales();
void LoadNpcOptionLocales();
void LoadGossipMenuItemsLocales();
void LoadPointOfInterestLocales();
void LoadInstanceTemplate();
void LoadMailLevelRewards();
@ -592,8 +636,11 @@ class ObjectMgr
void LoadWeatherZoneChances();
void LoadGameTele();
void LoadNpcOptions();
void LoadNpcTextId();
void LoadGossipMenu();
void LoadGossipMenuItems();
void LoadVendors();
void LoadTrainerSpell();
@ -704,10 +751,10 @@ class ObjectMgr
if(itr==mPageTextLocaleMap.end()) return NULL;
return &itr->second;
}
NpcOptionLocale const* GetNpcOptionLocale(uint32 entry) const
GossipMenuItemsLocale const* GetGossipMenuItemsLocale(uint32 entry) const
{
NpcOptionLocaleMap::const_iterator itr = mNpcOptionLocaleMap.find(entry);
if(itr==mNpcOptionLocaleMap.end()) return NULL;
GossipMenuItemsLocaleMap::const_iterator itr = mGossipMenuItemsLocaleMap.find(entry);
if(itr==mGossipMenuItemsLocaleMap.end()) return NULL;
return &itr->second;
}
PointOfInterestLocale const* GetPointOfInterestLocale(uint32 poi_id) const
@ -786,8 +833,6 @@ class ObjectMgr
bool AddGameTele(GameTele& data);
bool DeleteGameTele(const std::string& name);
CacheNpcOptionList const& GetNpcOptions() const { return m_mCacheNpcOptionList; }
uint32 GetNpcGossip(uint32 entry) const
{
CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry);
@ -835,6 +880,16 @@ class ObjectMgr
return ItemRequiredTargetMapBounds(m_ItemRequiredTarget.lower_bound(uiItemEntry),m_ItemRequiredTarget.upper_bound(uiItemEntry));
}
GossipMenusMapBounds GetGossipMenusMapBounds(uint32 uiMenuId) const
{
return GossipMenusMapBounds(m_mGossipMenusMap.lower_bound(uiMenuId),m_mGossipMenusMap.upper_bound(uiMenuId));
}
GossipMenuItemsMapBounds GetGossipMenuItemsMapBounds(uint32 uiMenuId) const
{
return GossipMenuItemsMapBounds(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId));
}
protected:
// first free id for selected id type
@ -876,7 +931,9 @@ class ObjectMgr
RepOnKillMap mRepOnKill;
PointOfInterestMap mPointsOfInterest;
GossipMenusMap m_mGossipMenusMap;
GossipMenuItemsMap m_mGossipMenuItemsMap;
PointOfInterestMap mPointsOfInterest;
QuestPOIMap mQuestPOIMap;
@ -942,7 +999,7 @@ class ObjectMgr
NpcTextLocaleMap mNpcTextLocaleMap;
PageTextLocaleMap mPageTextLocaleMap;
MangosStringLocaleMap mMangosStringLocaleMap;
NpcOptionLocaleMap mNpcOptionLocaleMap;
GossipMenuItemsLocaleMap mGossipMenuItemsLocaleMap;
PointOfInterestLocaleMap mPointOfInterestLocaleMap;
RespawnTimes mCreatureRespawnTimes;
RespawnTimes mGORespawnTimes;
@ -951,7 +1008,6 @@ class ObjectMgr
typedef std::vector<PlayerCondition> ConditionStore;
ConditionStore mConditions;
CacheNpcOptionList m_mCacheNpcOptionList;
CacheNpcTextIdMap m_mCacheNpcTextIdMap;
CacheVendorItemMap m_mCacheVendorItemMap;
CacheTrainerSpellMap m_mCacheTrainerSpellMap;

View file

@ -2117,14 +2117,14 @@ Creature* Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask)
return unit;
}
GameObject* Player::GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes type) const
GameObject* Player::GetGameObjectIfCanInteractWith(uint64 guid, uint32 gameobject_type) const
{
if(GameObject *go = GetMap()->GetGameObject(guid))
if (GameObject *go = GetMap()->GetGameObject(guid))
{
if(go->GetGoType() == type)
if (uint32(go->GetGoType()) == gameobject_type || gameobject_type == MAX_GAMEOBJECT_TYPE)
{
float maxdist;
switch(type)
switch(go->GetGoType())
{
// TODO: find out how the client calculates the maximal usage distance to spellless working
// gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number
@ -2140,10 +2140,10 @@ GameObject* Player::GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes
break;
}
if (go->IsWithinDistInMap(this, maxdist))
if (go->IsWithinDistInMap(this, maxdist) && go->isSpawned())
return go;
sLog.outError("IsGameObjectOfTypeInRange: GameObject '%s' [GUID: %u] is too far away from player %s [GUID: %u] to be used by him (distance=%f, maximal 10 is allowed)", go->GetGOInfo()->name,
sLog.outError("GetGameObjectIfCanInteractWith: GameObject '%s' [GUID: %u] is too far away from player %s [GUID: %u] to be used by him (distance=%f, maximal 10 is allowed)", go->GetGOInfo()->name,
go->GetGUIDLow(), GetName(), GetGUIDLow(), go->GetDistance(this));
}
}
@ -12178,126 +12178,151 @@ void Player::SendNewItem(Item *item, uint32 count, bool received, bool created,
/*** GOSSIP SYSTEM ***/
/*********************************************************/
void Player::PrepareGossipMenu(WorldObject *pSource, uint32 gossipid)
void Player::PrepareGossipMenu(WorldObject *pSource, uint32 menuId)
{
PlayerMenu* pMenu = PlayerTalkClass;
pMenu->ClearMenus();
if (pSource->GetTypeId() != TYPEID_UNIT)
return;
pMenu->GetGossipMenu().SetMenuId(menuId);
Creature *pCreature = (Creature*)pSource;
GossipMenuItemsMapBounds pMenuItemBounds = sObjectMgr.GetGossipMenuItemsMapBounds(menuId);
// lazy loading single time at use
pCreature->LoadGossipOptions();
// if default menuId and no menu options exist for this, use options from default options
if (pMenuItemBounds.first == pMenuItemBounds.second && menuId == GetDefaultGossipMenuForSource(pSource))
pMenuItemBounds = sObjectMgr.GetGossipMenuItemsMapBounds(0);
GossipOptionList &iOptList = pCreature->GetGossipOptionList();
for(GossipOptionList::iterator i = iOptList.begin( ); i != iOptList.end( ); ++i)
for(GossipMenuItemsMap::const_iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr)
{
GossipOption* gso = &*i;
bool bCanTalk = true;
if (gso->GossipId == gossipid)
if (itr->second.cond_1 && !sObjectMgr.IsPlayerMeetToCondition(this, itr->second.cond_1))
continue;
if (itr->second.cond_2 && !sObjectMgr.IsPlayerMeetToCondition(this, itr->second.cond_2))
continue;
if (itr->second.cond_3 && !sObjectMgr.IsPlayerMeetToCondition(this, itr->second.cond_3))
continue;
if (pSource->GetTypeId() == TYPEID_UNIT)
{
bool cantalking = true;
Creature *pCreature = (Creature*)pSource;
if (gso->Id == 1)
uint32 npcflags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS);
if (!(itr->second.npc_option_npcflag & npcflags))
continue;
switch(itr->second.option_id)
{
uint32 textid = GetGossipTextId(pSource);
GossipText const* gossiptext = sObjectMgr.GetGossipText(textid);
if (!gossiptext)
cantalking = false;
}
else
{
switch(gso->Action)
case GOSSIP_OPTION_QUESTGIVER:
PrepareQuestMenu(pSource->GetGUID());
bCanTalk = false;
break;
case GOSSIP_OPTION_ARMORER:
bCanTalk = false; // added in special mode
break;
case GOSSIP_OPTION_SPIRITHEALER:
if (!isDead())
bCanTalk = false;
break;
case GOSSIP_OPTION_VENDOR:
{
case GOSSIP_OPTION_QUESTGIVER:
VendorItemData const* vItems = pCreature->GetVendorItems();
if (!vItems || vItems->Empty())
{
sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", pCreature->GetGUIDLow(), pCreature->GetEntry());
bCanTalk = false;
}
break;
}
case GOSSIP_OPTION_TRAINER:
if (!pCreature->isCanTrainingOf(this, false))
bCanTalk = false;
break;
case GOSSIP_OPTION_UNLEARNTALENTS:
if (!pCreature->isCanTrainingAndResetTalentsOf(this))
bCanTalk = false;
break;
case GOSSIP_OPTION_UNLEARNPETSKILLS:
if (!GetPet() || GetPet()->getPetType() != HUNTER_PET || GetPet()->m_spells.size() <= 1 || pCreature->GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->trainer_class != CLASS_HUNTER)
bCanTalk = false;
break;
case GOSSIP_OPTION_TAXIVENDOR:
if (GetSession()->SendLearnNewTaxiNode(pCreature))
return;
break;
case GOSSIP_OPTION_BATTLEFIELD:
if (!pCreature->isCanInteractWithBattleMaster(this, false))
bCanTalk = false;
break;
case GOSSIP_OPTION_STABLEPET:
if (getClass() != CLASS_HUNTER)
bCanTalk = false;
break;
case GOSSIP_OPTION_GOSSIP:
case GOSSIP_OPTION_SPIRITGUIDE:
case GOSSIP_OPTION_INNKEEPER:
case GOSSIP_OPTION_BANKER:
case GOSSIP_OPTION_PETITIONER:
case GOSSIP_OPTION_TABARDDESIGNER:
case GOSSIP_OPTION_AUCTIONEER:
break; // no checks
default:
sLog.outErrorDb("Creature entry %u have unknown gossip option %u for menu %u", pCreature->GetEntry(), itr->second.option_id, itr->second.menu_id);
bCanTalk = false;
break;
}
}
else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
{
GameObject *pGo = (GameObject*)pSource;
switch(itr->second.option_id)
{
case GOSSIP_OPTION_QUESTGIVER:
if (pGo->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
PrepareQuestMenu(pSource->GetGUID());
//if (pm->GetQuestMenu()->MenuItemCount() == 0)
cantalking = false;
//pm->GetQuestMenu()->ClearMenu();
break;
case GOSSIP_OPTION_ARMORER:
cantalking = false; // added in special mode
break;
case GOSSIP_OPTION_SPIRITHEALER:
if (!isDead())
cantalking = false;
break;
case GOSSIP_OPTION_VENDOR:
{
VendorItemData const* vItems = pCreature->GetVendorItems();
if (!vItems || vItems->Empty())
{
sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.",
pCreature->GetGUIDLow(), pCreature->GetEntry());
cantalking = false;
}
break;
}
case GOSSIP_OPTION_TRAINER:
if (!pCreature->isCanTrainingOf(this, false))
cantalking = false;
break;
case GOSSIP_OPTION_UNLEARNTALENTS:
if (!pCreature->isCanTrainingAndResetTalentsOf(this))
cantalking = false;
break;
case GOSSIP_OPTION_UNLEARNPETSKILLS:
if(!GetPet() || GetPet()->getPetType() != HUNTER_PET || GetPet()->m_spells.size() <= 1 || pCreature->GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->trainer_class != CLASS_HUNTER)
cantalking = false;
break;
case GOSSIP_OPTION_TAXIVENDOR:
if (GetSession()->SendLearnNewTaxiNode(pCreature))
return;
break;
case GOSSIP_OPTION_BATTLEFIELD:
if (!pCreature->isCanInteractWithBattleMaster(this, false))
cantalking = false;
break;
case GOSSIP_OPTION_SPIRITGUIDE:
case GOSSIP_OPTION_INNKEEPER:
case GOSSIP_OPTION_BANKER:
case GOSSIP_OPTION_PETITIONER:
case GOSSIP_OPTION_STABLEPET:
case GOSSIP_OPTION_TABARDDESIGNER:
case GOSSIP_OPTION_AUCTIONEER:
break; // no checks
default:
sLog.outErrorDb("Creature %u (entry: %u) have unknown gossip option %u", pCreature->GetDBTableGUIDLow(), pCreature->GetEntry(), gso->Action);
break;
}
bCanTalk = false;
break;
case GOSSIP_OPTION_GOSSIP:
if (pGo->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER && pGo->GetGoType() != GAMEOBJECT_TYPE_GOOBER)
bCanTalk = false;
break;
default:
bCanTalk = false;
break;
}
}
//note for future dev: should have database fields for BoxMessage & BoxMoney
if (!gso->OptionText.empty() && cantalking)
if (bCanTalk)
{
std::string strOptionText = itr->second.option_text;
std::string strBoxText = itr->second.box_text;
int loc_idx = GetSession()->GetSessionDbLocaleIndex();
if (loc_idx >= 0)
{
std::string OptionText = gso->OptionText;
std::string BoxText = gso->BoxText;
int loc_idx = GetSession()->GetSessionDbLocaleIndex();
uint32 idxEntry = MAKE_PAIR32(menuId, itr->second.id);
if (loc_idx >= 0)
if (GossipMenuItemsLocale const *no = sObjectMgr.GetGossipMenuItemsLocale(idxEntry))
{
if (NpcOptionLocale const *no = sObjectMgr.GetNpcOptionLocale(gso->Id))
{
if (no->OptionText.size() > (size_t)loc_idx && !no->OptionText[loc_idx].empty())
OptionText = no->OptionText[loc_idx];
if (no->OptionText.size() > (size_t)loc_idx && !no->OptionText[loc_idx].empty())
strOptionText = no->OptionText[loc_idx];
if (no->BoxText.size() > (size_t)loc_idx && !no->BoxText[loc_idx].empty())
BoxText = no->BoxText[loc_idx];
}
if (no->BoxText.size() > (size_t)loc_idx && !no->BoxText[loc_idx].empty())
strBoxText = no->BoxText[loc_idx];
}
pMenu->GetGossipMenu().AddMenuItem((uint8)gso->Icon,OptionText, gossipid,gso->Action,BoxText,gso->BoxMoney,gso->Coded);
}
pMenu->GetGossipMenu().AddMenuItem(itr->second.option_icon, strOptionText, 0, itr->second.option_id, strBoxText, itr->second.box_money, itr->second.box_coded);
pMenu->GetGossipMenu().AddGossipMenuItemData(itr->second.action_menu_id, itr->second.action_poi_id, itr->second.action_script_id);
}
}
///some gossips aren't handled in normal way ... so we need to do it this way .. TODO: handle it in normal way ;-)
if (pMenu->Empty())
// some gossips aren't handled in normal way ... so we need to do it this way .. TODO: handle it in normal way ;-)
/*if (pMenu->Empty())
{
if (pCreature->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_TRAINER))
{
@ -12310,59 +12335,90 @@ void Player::PrepareGossipMenu(WorldObject *pSource, uint32 gossipid)
// output error message if need
pCreature->isCanInteractWithBattleMaster(this, true);
}
}
}*/
}
void Player::SendPreparedGossip(WorldObject *pSource)
{
if (!pSource || pSource->GetTypeId() != TYPEID_UNIT)
if (!pSource)
return;
// in case no gossip flag and quest menu not empty, open quest menu (client expect gossip menu with this flag)
if (!((Creature*)pSource)->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_GOSSIP) && !PlayerTalkClass->GetQuestMenu().Empty())
if (pSource->GetTypeId() == TYPEID_UNIT)
{
SendPreparedQuest(pSource->GetGUID());
return;
// in case no gossip flag and quest menu not empty, open quest menu (client expect gossip menu with this flag)
if (!((Creature*)pSource)->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_GOSSIP) && !PlayerTalkClass->GetQuestMenu().Empty())
{
SendPreparedQuest(pSource->GetGUID());
return;
}
}
else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
{
// probably need to find a better way here
if (!PlayerTalkClass->GetGossipMenu().GetMenuId() && !PlayerTalkClass->GetQuestMenu().Empty())
{
SendPreparedQuest(pSource->GetGUID());
return;
}
}
// in case non empty gossip menu (that not included quests list size) show it
// (quest entries from quest menu will be included in list)
PlayerTalkClass->SendGossipMenu(GetGossipTextId(pSource), pSource->GetGUID());
uint32 textId = GetGossipTextId(pSource);
if (uint32 menuId = PlayerTalkClass->GetGossipMenu().GetMenuId())
textId = GetGossipTextId(menuId);
PlayerTalkClass->SendGossipMenu(textId, pSource->GetGUID());
}
void Player::OnGossipSelect(WorldObject* pSource, uint32 option)
void Player::OnGossipSelect(WorldObject* pSource, uint32 gossipListId, uint32 menuId)
{
GossipMenu& gossipmenu = PlayerTalkClass->GetGossipMenu();
if (option >= gossipmenu.MenuItemCount())
if (gossipListId >= gossipmenu.MenuItemCount())
return;
uint32 action = gossipmenu.GetItem(option).m_gAction;
uint32 zoneid = GetZoneId();
// if not same, then something funky is going on
if (menuId != gossipmenu.GetMenuId())
return;
uint32 gossipOptionId = gossipmenu.GetItem(gossipListId).m_gOptionId;
uint64 guid = pSource->GetGUID();
GossipOption const *gossip = GetGossipOption(pSource, action);
if (!gossip)
if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
{
zoneid = 0;
gossip = GetGossipOption(pSource, action);
if (!gossip)
if (gossipOptionId > GOSSIP_OPTION_QUESTGIVER)
{
sLog.outError("Player guid %u request invalid gossip option for GameObject entry %u", GetGUIDLow(), pSource->GetEntry());
return;
}
}
switch(gossip->Action)
GossipMenuItemData pMenuData = gossipmenu.GetItemData(gossipListId);
switch(gossipOptionId)
{
case GOSSIP_OPTION_GOSSIP:
{
uint32 textid = GetGossipTextId(action, zoneid);
if (pMenuData.m_gAction_menu)
{
PrepareGossipMenu(pSource, pMenuData.m_gAction_menu);
SendPreparedGossip(pSource);
}
if (textid == 0)
textid = GetGossipTextId(pSource);
if (pMenuData.m_gAction_poi)
PlayerTalkClass->SendPointOfInterest(pMenuData.m_gAction_poi);
if (pMenuData.m_gAction_script)
{
if (pSource->GetTypeId() == TYPEID_UNIT)
GetMap()->ScriptsStart(sGossipScripts, pMenuData.m_gAction_script, this, pSource);
else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
GetMap()->ScriptsStart(sGossipScripts, pMenuData.m_gAction_script, pSource, this);
}
PlayerTalkClass->CloseGossip();
PlayerTalkClass->SendTalking(textid);
break;
}
case GOSSIP_OPTION_SPIRITHEALER:
@ -12413,9 +12469,7 @@ void Player::OnGossipSelect(WorldObject* pSource, uint32 option)
GetSession()->SendAuctionHello(guid, ((Creature*)pSource));
break;
case GOSSIP_OPTION_SPIRITGUIDE:
case GOSSIP_GUARD_SPELLTRAINER:
case GOSSIP_GUARD_SKILLTRAINER:
PrepareGossipMenu(pSource, gossip->Id);
PrepareGossipMenu(pSource);
SendPreparedGossip(pSource);
break;
case GOSSIP_OPTION_BATTLEFIELD:
@ -12431,59 +12485,13 @@ void Player::OnGossipSelect(WorldObject* pSource, uint32 option)
GetSession()->SendBattlegGroundList(guid, bgTypeId);
break;
}
default:
OnPoiSelect(pSource, gossip);
break;
}
}
void Player::OnPoiSelect(WorldObject *pSource, GossipOption const *gossip)
{
if(gossip->GossipId==GOSSIP_GUARD_SPELLTRAINER || gossip->GossipId==GOSSIP_GUARD_SKILLTRAINER)
{
Poi_Icon icon = ICON_POI_BLANK;
//need add more case.
switch(gossip->Action)
{
case GOSSIP_GUARD_BANK:
icon=ICON_POI_SMALL_HOUSE;
break;
case GOSSIP_GUARD_RIDE:
icon=ICON_POI_RWHORSE;
break;
case GOSSIP_GUARD_GUILD:
icon=ICON_POI_BLUETOWER;
break;
default:
icon=ICON_POI_GREYTOWER;
break;
}
uint32 textid = GetGossipTextId(gossip->Action, GetZoneId());
PlayerTalkClass->SendTalking(textid);
// std::string areaname= gossip->OptionText;
// how this could worked player->PlayerTalkClass->SendPointOfInterest( x, y, icon, 2, 15, areaname.c_str() );
}
}
uint32 Player::GetGossipTextId(uint32 action, uint32 zoneid)
{
QueryResult *result= WorldDatabase.PQuery("SELECT textid FROM npc_gossip_textid WHERE action = '%u' AND zoneid ='%u'", action, zoneid );
if (!result)
return 0;
Field *fields = result->Fetch();
uint32 id = fields[0].GetUInt32();
delete result;
return id;
}
uint32 Player::GetGossipTextId(WorldObject *pSource)
{
if (!pSource || pSource->GetTypeId() != TYPEID_UNIT || !((Creature*)pSource)->GetDBTableGUIDLow())
return DEFAULT_GOSSIP_MESSAGE;
return 0;
if (uint32 pos = sObjectMgr.GetNpcGossip(((Creature*)pSource)->GetDBTableGUIDLow()))
return pos;
@ -12491,19 +12499,32 @@ uint32 Player::GetGossipTextId(WorldObject *pSource)
return DEFAULT_GOSSIP_MESSAGE;
}
GossipOption const* Player::GetGossipOption(WorldObject *pSource, uint32 id) const
uint32 Player::GetGossipTextId(uint32 menuId)
{
uint32 textId = DEFAULT_GOSSIP_MESSAGE;
if (!menuId)
return textId;
GossipMenusMapBounds pMenuBounds = sObjectMgr.GetGossipMenusMapBounds(menuId);
for(GossipMenusMap::const_iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr)
{
if (sObjectMgr.IsPlayerMeetToCondition(this, itr->second.cond_1) && sObjectMgr.IsPlayerMeetToCondition(this, itr->second.cond_2))
textId = itr->second.text_id;
}
return textId;
}
uint32 Player::GetDefaultGossipMenuForSource(WorldObject *pSource)
{
if (pSource->GetTypeId() == TYPEID_UNIT)
{
GossipOptionList &iOptlist = ((Creature*)pSource)->GetGossipOptionList();
return ((Creature*)pSource)->GetCreatureInfo()->GossipMenuId;
else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
return((GameObject*)pSource)->GetGOInfo()->GetGossipMenuId();
for(GossipOptionList::const_iterator i = iOptlist.begin( ); i != iOptlist.end( ); ++i)
{
if (i->Action == id)
return &*i;
}
}
return NULL;
return 0;
}
/*********************************************************/
@ -19119,7 +19140,7 @@ BGQueueIdBasedOnLevel Player::GetBattleGroundQueueIdFromLevel() const
uint32 queue_id = ( getLevel() / 10) - 1;
if( queue_id >= MAX_BATTLEGROUND_QUEUES )
{
sLog.outError("BattleGround: too high queue_id %u this shouldn't happen", queue_id);
sLog.outError("BattleGround: too high queue_id %u for player %u (acc: %u) with level %u", queue_id, GetGUIDLow(), GetSession()->GetAccountId(), getLevel());
return QUEUE_ID_MAX_LEVEL_80;
}
return BGQueueIdBasedOnLevel(queue_id);
@ -21229,3 +21250,35 @@ void Player::SendDuelCountdown(uint32 counter)
data << uint32(counter); // seconds
GetSession()->SendPacket(&data);
}
bool Player::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
{
switch(spellInfo->Effect[index])
{
case SPELL_EFFECT_ATTACK_ME:
return true;
default:
break;
}
switch(spellInfo->EffectApplyAuraName[index])
{
case SPELL_AURA_MOD_TAUNT:
return true;
default:
break;
}
return Unit::IsImmunedToSpellEffect(spellInfo, index);
}
void Player::SetHomebindToCurrentPos()
{
m_homebindMapId = GetMapId();
m_homebindZoneId = GetZoneId();
m_homebindX = GetPositionX();
m_homebindY = GetPositionY();
m_homebindZ = GetPositionZ();
// update sql homebind
CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'",
m_homebindMapId, m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ, GetGUIDLow());
}

View file

@ -1067,7 +1067,7 @@ class MANGOS_DLL_SPEC Player : public Unit
void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time);
Creature* GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask);
GameObject* GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes type) const;
GameObject* GetGameObjectIfCanInteractWith(uint64 guid, uint32 gameobject_type = MAX_GAMEOBJECT_TYPE) const;
void UpdateVisibilityForPlayer();
@ -1300,14 +1300,13 @@ class MANGOS_DLL_SPEC Player : public Unit
/*** GOSSIP SYSTEM ***/
/*********************************************************/
void PrepareGossipMenu(WorldObject *pSource, uint32 gossipid = 0);
void PrepareGossipMenu(WorldObject *pSource, uint32 menuId = 0);
void SendPreparedGossip(WorldObject *pSource);
void OnGossipSelect(WorldObject *pSource, uint32 option);
void OnPoiSelect(WorldObject *pSource, GossipOption const *gossip);
void OnGossipSelect(WorldObject *pSource, uint32 gossipListId, uint32 menuId);
uint32 GetGossipTextId(uint32 action, uint32 zoneid);
uint32 GetGossipTextId(uint32 menuId);
uint32 GetGossipTextId(WorldObject *pSource);
GossipOption const* GetGossipOption(WorldObject *pSource, uint32 id) const;
uint32 GetDefaultGossipMenuForSource(WorldObject *pSource);
/*********************************************************/
/*** QUEST SYSTEM ***/
@ -1556,6 +1555,7 @@ class MANGOS_DLL_SPEC Player : public Unit
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;
bool IsSpellFitByClassAndRace( uint32 spell_id ) const;
bool IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const;
bool IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const;
void SendProficiency(uint8 pr1, uint32 pr2);
void SendInitialSpells();
@ -2172,13 +2172,9 @@ class MANGOS_DLL_SPEC Player : public Unit
float m_recallO;
void SaveRecallPosition();
// Homebind coordinates
uint32 m_homebindMapId;
uint16 m_homebindZoneId;
float m_homebindX;
float m_homebindY;
float m_homebindZ;
void SetHomebindToCurrentPos();
void RelocateToHomebind() { SetLocationMapId(m_homebindMapId); Relocate(m_homebindX,m_homebindY,m_homebindZ); }
bool TeleportToHomebind(uint32 options = 0) { return TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation(),options); }
// currently visible objects at player client
typedef std::set<uint64> ClientGUIDs;
@ -2537,6 +2533,13 @@ class MANGOS_DLL_SPEC Player : public Unit
GridReference<Player> m_gridRef;
MapReference m_mapRef;
// Homebind coordinates
uint32 m_homebindMapId;
uint16 m_homebindZoneId;
float m_homebindX;
float m_homebindY;
float m_homebindZ;
uint32 m_lastFallTime;
float m_lastFallZ;

View file

@ -102,7 +102,7 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket & recv_data)
if (Script->GossipHello(_player, pCreature))
return;
_player->PrepareGossipMenu(pCreature);
_player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId);
_player->SendPreparedGossip(pCreature);
}

View file

@ -2442,38 +2442,6 @@ enum DiminishingGroup
DIMINISHING_LIMITONLY
};
enum SummonType
{
SUMMON_TYPE_CRITTER = 41,
SUMMON_TYPE_GUARDIAN = 61,
SUMMON_TYPE_TOTEM_SLOT1 = 63,
SUMMON_TYPE_WILD = 64,
SUMMON_TYPE_POSESSED = 65,
SUMMON_TYPE_DEMON = 66,
SUMMON_TYPE_SUMMON = 67,
SUMMON_TYPE_TOTEM_SLOT2 = 81,
SUMMON_TYPE_TOTEM_SLOT3 = 82,
SUMMON_TYPE_TOTEM_SLOT4 = 83,
SUMMON_TYPE_TOTEM = 121,
SUMMON_TYPE_UNKNOWN3 = 181,
SUMMON_TYPE_UNKNOWN4 = 187,
SUMMON_TYPE_UNKNOWN1 = 247,
SUMMON_TYPE_CRITTER2 = 407,
SUMMON_TYPE_CRITTER3 = 307,
SUMMON_TYPE_UNKNOWN5 = 409,
SUMMON_TYPE_UNKNOWN2 = 427,
SUMMON_TYPE_POSESSED2 = 428,
SUMMON_TYPE_QUEST_CRITTER = 487,
SUMMON_TYPE_QUEST_WILD = 587,
SUMMON_TYPE_INFERNO = 711,
SUMMON_TYPE_GUARDIAN2 = 713,
SUMMON_TYPE_LIGHTWELL = 1141,
SUMMON_TYPE_GUARDIAN3 = 1161,
SUMMON_TYPE_CREATURE = 1302,
SUMMON_TYPE_ELEMENTAL = 1561,
SUMMON_TYPE_FORCE_OF_NATURE = 1562
};
enum ResponseCodes
{
RESPONSE_SUCCESS = 0x00,

View file

@ -691,8 +691,8 @@ void Spell::prepareDataForTriggerSystem()
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000800000000060))
m_canTrigger = true;
break;
case SPELLFAMILY_PRIEST: // For Penance heal/damage triggers need do it
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0001800000000000))
case SPELLFAMILY_PRIEST: // For Penance,Mind Sear,Mind Flay heal/damage triggers need do it
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0001800000800000) || (m_spellInfo->SpellFamilyFlags2 & 0x00000040))
m_canTrigger = true;
break;
case SPELLFAMILY_ROGUE: // For poisons need do it
@ -1685,8 +1685,16 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap)
}
break;
case TARGET_ALL_FRIENDLY_UNITS_IN_AREA:
// Death Pact (in fact selection by player selection)
if (m_spellInfo->Id == 48743)
{
// checked in Spell::CheckCast
if (m_caster->GetTypeId()==TYPEID_PLAYER)
if (Unit* target = m_caster->GetMap()->GetPet(((Player*)m_caster)->GetSelection()))
TagUnitMap.push_back(target);
}
// Wild Growth
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellIconID == 2864)
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellIconID == 2864)
{
Unit* target = m_targets.getUnitTarget();
if(!target)
@ -2217,13 +2225,6 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap)
}
break;
case SPELL_EFFECT_SUMMON:
if (m_spellInfo->EffectMiscValueB[effIndex] == SUMMON_TYPE_POSESSED ||
m_spellInfo->EffectMiscValueB[effIndex] == SUMMON_TYPE_POSESSED2)
{
if (m_targets.getUnitTarget())
TagUnitMap.push_back(m_targets.getUnitTarget());
}
else
TagUnitMap.push_back(m_caster);
break;
case SPELL_EFFECT_SUMMON_CHANGE_ITEM:
@ -4299,6 +4300,34 @@ SpellCastResult Spell::CheckCast(bool strict)
// for effects of spells that have only one target
switch(m_spellInfo->Effect[i])
{
case SPELL_EFFECT_INSTAKILL:
// Death Pact
if(m_spellInfo->Id == 48743)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_ERROR;
if (!((Player*)m_caster)->GetSelection())
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
Pet* target = m_caster->GetMap()->GetPet(((Player*)m_caster)->GetSelection());
// alive
if (!target || target->isDead())
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
// undead
if (target->GetCreatureType() != CREATURE_TYPE_UNDEAD)
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
// owned
if (target->GetOwnerGUID() != m_caster->GetGUID())
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
float dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
if (!target->IsWithinDistInMap(m_caster,dist))
return SPELL_FAILED_OUT_OF_RANGE;
// will set in target selection code
}
break;
case SPELL_EFFECT_DUMMY:
{
if(m_spellInfo->SpellIconID == 1648) // Execute
@ -4567,24 +4596,17 @@ SpellCastResult Spell::CheckCast(bool strict)
// This is generic summon effect
case SPELL_EFFECT_SUMMON:
{
switch(m_spellInfo->EffectMiscValueB[i])
if(SummonPropertiesEntry const *summon_prop = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]))
{
case SUMMON_TYPE_POSESSED:
case SUMMON_TYPE_POSESSED2:
case SUMMON_TYPE_DEMON:
case SUMMON_TYPE_SUMMON:
case SUMMON_TYPE_ELEMENTAL:
case SUMMON_TYPE_INFERNO:
if(summon_prop->Group == SUMMON_PROP_GROUP_PETS)
{
if(m_caster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
if(m_caster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
break;
}
}
break;
}
// Not used for summon?
case SPELL_EFFECT_SUMMON_PHANTASM:
@ -4950,6 +4972,18 @@ SpellCastResult Spell::CheckCasterAuras() const
prevented_reason = SPELL_FAILED_SILENCED;
else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY)
prevented_reason = SPELL_FAILED_PACIFIED;
else if(m_caster->HasAuraType(SPELL_AURA_ALLOW_ONLY_ABILITY))
{
Unit::AuraList const& casingLimit = m_caster->GetAurasByType(SPELL_AURA_ALLOW_ONLY_ABILITY);
for(Unit::AuraList::const_iterator itr = casingLimit.begin(); itr != casingLimit.end(); ++itr)
{
if(!IsAffectedByAura(*itr))
{
prevented_reason = SPELL_FAILED_CASTER_AURASTATE;
break;
}
}
}
// Attr must make flag drop spell totally immune from all effects
if (prevented_reason != SPELL_CAST_OK)
@ -5704,7 +5738,7 @@ void Spell::UpdatePointers()
m_targets.Update(m_caster);
}
bool Spell::IsAffectedByAura(Aura *aura)
bool Spell::IsAffectedByAura(Aura *aura) const
{
return sSpellMgr.IsAffectedByMod(m_spellInfo, aura->getAuraSpellMod());
}

View file

@ -248,8 +248,8 @@ class Spell
void EffectDualWield(uint32 i);
void EffectPickPocket(uint32 i);
void EffectAddFarsight(uint32 i);
void EffectSummonWild(uint32 i);
void EffectSummonGuardian(uint32 i);
void EffectSummonWild(uint32 i, uint32 forceFaction = 0);
void EffectSummonGuardian(uint32 i, uint32 forceFaction = 0);
void EffectHealMechanical(uint32 i);
void EffectJump(uint32 i);
void EffectTeleUnitsFaceCaster(uint32 i);
@ -277,7 +277,7 @@ class Spell
void EffectSummonPlayer(uint32 i);
void EffectActivateObject(uint32 i);
void EffectApplyGlyph(uint32 i);
void EffectSummonTotem(uint32 i);
void EffectSummonTotem(uint32 i, uint8 slot = 0);
void EffectEnchantHeldItem(uint32 i);
void EffectSummonObject(uint32 i);
void EffectResurrect(uint32 i);
@ -299,7 +299,7 @@ class Spell
void EffectMilling(uint32 i);
void EffectRenamePet(uint32 i);
void EffectSendTaxi(uint32 i);
void EffectSummonCritter(uint32 i);
void EffectSummonCritter(uint32 i, uint32 forceFaction = 0);
void EffectKnockBack(uint32 i);
void EffectPlayerPull(uint32 i);
void EffectDispelMechanic(uint32 i);
@ -314,7 +314,6 @@ class Spell
void EffectAddExtraAttacks(uint32 i);
void EffectSpiritHeal(uint32 i);
void EffectSkinPlayerCorpse(uint32 i);
void EffectSummonDemon(uint32 i);
void EffectStealBeneficialBuff(uint32 i);
void EffectUnlearnSpecialization(uint32 i);
void EffectHealPct(uint32 i);
@ -442,7 +441,7 @@ class Spell
void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc)
bool IsAffectedByAura(Aura *aura);
bool IsAffectedByAura(Aura *aura) const;
bool CheckTargetCreatureType(Unit* target) const;

View file

@ -314,7 +314,7 @@ enum AuraType
SPELL_AURA_MOD_IGNORE_DAMAGE_REDUCTION_SCHOOL = 269,
SPELL_AURA_MOD_IGNORE_TARGET_RESIST = 270, // Possibly need swap vs 195 aura used only in 1 spell Chaos Bolt Passive
SPELL_AURA_MOD_DAMAGE_FROM_CASTER = 271,
SPELL_AURA_272 = 272,
SPELL_AURA_MAELSTROM_WEAPON = 272,
SPELL_AURA_X_RAY = 273,
SPELL_AURA_274 = 274,
SPELL_AURA_MOD_IGNORE_SHAPESHIFT = 275,
@ -347,7 +347,7 @@ enum AuraType
SPELL_AURA_302 = 302,
SPELL_AURA_303 = 303,
SPELL_AURA_304 = 304,
SPELL_AURA_305 = 305,
SPELL_AURA_MOD_MINIMUM_SPEED = 305,
SPELL_AURA_306 = 306,
TOTAL_AURAS = 307
};

View file

@ -295,7 +295,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING (only 2 test spels in 3.2.2a)
&Aura::HandleNULL, //243 faction reaction override spells
&Aura::HandleComprehendLanguage, //244 SPELL_AURA_COMPREHEND_LANGUAGE
&Aura::HandleNULL, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS
&Aura::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS implemented in Unit::CalculateSpellDuration
&Aura::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL implemented in Unit::CalculateSpellDuration
&Aura::HandleNULL, //247 target to become a clone of the caster
&Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
@ -313,7 +313,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code
&Aura::HandlePhase, //261 SPELL_AURA_PHASE undetectable invisibility? implemented in Unit::isVisibleForOrDetect
&Aura::HandleNULL, //262 ignore combat/aura state?
&Aura::HandleNULL, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask
&Aura::HandleAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask
&Aura::HandleUnused, //264 unused (3.0.8a-3.2.2a)
&Aura::HandleUnused, //265 unused (3.0.8a-3.2.2a)
&Aura::HandleUnused, //266 unused (3.0.8a-3.2.2a)
@ -322,7 +322,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //269 SPELL_AURA_MOD_IGNORE_DAMAGE_REDUCTION_SCHOOL implemented in Unit::CalcNotIgnoreDamageRedunction
&Aura::HandleUnused, //270 SPELL_AURA_MOD_IGNORE_TARGET_RESIST (unused in 3.2.2a)
&Aura::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonus
&Aura::HandleNULL, //272 reduce spell cast time?
&Aura::HandleNoImmediateEffect, //272 SPELL_AURA_MAELSTROM_WEAPON (unclear use for aura, it used in (3.2.2a...3.3.0) in single spell 53817 that spellmode stacked and charged spell expected to be drop as stack
&Aura::HandleNoImmediateEffect, //273 SPELL_AURA_X_RAY (client side implementation)
&Aura::HandleNULL, //274 proc free shot?
&Aura::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select
@ -355,7 +355,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleUnused, //302 unused (3.2.2a)
&Aura::HandleNULL, //303 17 spells
&Aura::HandleNULL, //304 2 spells (alcohol effect?)
&Aura::HandleNULL, //305 2 spells
&Aura::HandleAuraModIncreaseSpeed, //305 SPELL_AURA_MOD_MINIMUM_SPEED
&Aura::HandleNULL //306 1 spell
};
@ -1333,26 +1333,42 @@ bool Aura::isAffectedOnSpell(SpellEntry const *spell) const
void Aura::ReapplyAffectedPassiveAuras( Unit* target )
{
std::set<uint32> affectedPassives;
std::set<uint32> affectedSelf;
std::set<uint32> affectedAuraCaster;
for(Unit::AuraMap::const_iterator itr = target->GetAuras().begin(); itr != target->GetAuras().end(); ++itr)
{
// permanent passive
if (itr->second->IsPassive() && itr->second->IsPermanent() &&
// permanent passive or permanent area aura
if (itr->second->IsPermanent() && (itr->second->IsPassive() || itr->second->IsAreaAura()) &&
// non deleted and not same aura (any with same spell id)
!itr->second->IsDeleted() && itr->second->GetId() != GetId() &&
// only applied by self and affected by aura
itr->second->GetCasterGUID() == target->GetGUID() && isAffectedOnSpell(itr->second->GetSpellProto()))
// and affected by aura
isAffectedOnSpell(itr->second->GetSpellProto()))
{
affectedPassives.insert(itr->second->GetId());
// only applied by self or aura caster
if(itr->second->GetCasterGUID() == target->GetGUID())
affectedSelf.insert(itr->second->GetId());
else if(itr->second->GetCasterGUID() == GetCasterGUID())
affectedAuraCaster.insert(itr->second->GetId());
}
}
for(std::set<uint32>::const_iterator set_itr = affectedPassives.begin(); set_itr != affectedPassives.end(); ++set_itr)
for(std::set<uint32>::const_iterator set_itr = affectedSelf.begin(); set_itr != affectedSelf.end(); ++set_itr)
{
target->RemoveAurasDueToSpell(*set_itr);
target->CastSpell(m_target, *set_itr, true);
}
if (!affectedAuraCaster.empty())
{
Unit* caster = GetCaster();
for(std::set<uint32>::const_iterator set_itr = affectedAuraCaster.begin(); set_itr != affectedAuraCaster.end(); ++set_itr)
{
target->RemoveAurasDueToSpell(*set_itr);
if (caster)
caster->CastSpell(m_target, *set_itr, true);
}
}
}
/*********************************************************/
@ -1402,7 +1418,10 @@ void Aura::HandleAddModifier(bool apply, bool Real)
mod->mask = (uint64)ptr[0] | (uint64)ptr[1]<<32;
mod->mask2= (uint64)ptr[2];
mod->charges = m_procCharges;
// prevent expire spell mods with (charges > 0 && m_stackAmount > 1)
// all this spell expected expire not at use but at spell proc event check
mod->charges = m_spellProto->StackAmount > 1 ? 0 : m_procCharges;
m_spellmod = mod;
}
@ -1412,14 +1431,22 @@ void Aura::HandleAddModifier(bool apply, bool Real)
// reapply talents to own passive persistent auras
ReapplyAffectedPassiveAuras(m_target);
// re-aplly talents and passives applied to pet (it affected by player spellmods)
// re-apply talents/passives/area auras applied to pet (it affected by player spellmods)
if(Pet* pet = m_target->GetPet())
ReapplyAffectedPassiveAuras(pet);
// re-apply talents/passives/area auras applied to totems (it affected by player spellmods)
for(int i = 0; i < MAX_TOTEM; ++i)
if(m_target->m_TotemSlot[i])
if(Creature* totem = m_target->GetMap()->GetCreature(m_target->m_TotemSlot[i]))
ReapplyAffectedPassiveAuras(totem);
// re-apply talents/passives/area auras applied to group members (it affected by player spellmods)
if (Group* group = ((Player*)m_target)->GetGroup())
for(GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
if (Player* member = itr->getSource())
if (member != m_target && member->IsInMap(m_target))
ReapplyAffectedPassiveAuras(member);
}
void Aura::HandleAddTargetTrigger(bool apply, bool /*Real*/)
{
@ -2212,56 +2239,107 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
// AT APPLY
if(apply)
{
switch(GetId())
switch(m_spellProto->SpellFamilyName)
{
case 1515: // Tame beast
// FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness
if (m_target->CanHaveThreatList())
if (Unit* caster = GetCaster())
m_target->AddThreat(caster, 10.0f, false, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
return;
case 13139: // net-o-matic
// root to self part of (root_target->charge->root_self sequence
if (Unit* caster = GetCaster())
caster->CastSpell(caster, 13138, true, NULL, this);
return;
case 39850: // Rocket Blast
if(roll_chance_i(20)) // backfire stun
m_target->CastSpell(m_target, 51581, true, NULL, this);
return;
case 43873: // Headless Horseman Laugh
m_target->PlayDistanceSound(11965);
return;
case 46354: // Blood Elf Illusion
if (Unit* caster = GetCaster())
case SPELLFAMILY_GENERIC:
switch(GetId())
{
switch(caster->getGender())
{
case GENDER_FEMALE:
caster->CastSpell(m_target, 46356, true, NULL, this);
break;
case GENDER_MALE:
caster->CastSpell(m_target, 46355, true, NULL, this);
break;
default:
break;
}
case 1515: // Tame beast
// FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness
if (m_target->CanHaveThreatList())
if (Unit* caster = GetCaster())
m_target->AddThreat(caster, 10.0f, false, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
return;
case 13139: // net-o-matic
// root to self part of (root_target->charge->root_self sequence
if (Unit* caster = GetCaster())
caster->CastSpell(caster, 13138, true, NULL, this);
return;
case 39850: // Rocket Blast
if(roll_chance_i(20)) // backfire stun
m_target->CastSpell(m_target, 51581, true, NULL, this);
return;
case 43873: // Headless Horseman Laugh
m_target->PlayDistanceSound(11965);
return;
case 46354: // Blood Elf Illusion
if (Unit* caster = GetCaster())
{
switch(caster->getGender())
{
case GENDER_FEMALE:
caster->CastSpell(m_target, 46356, true, NULL, this);
break;
case GENDER_MALE:
caster->CastSpell(m_target, 46355, true, NULL, this);
break;
default:
break;
}
}
return;
case 46699: // Requires No Ammo
if(m_target->GetTypeId() == TYPEID_PLAYER)
((Player*)m_target)->RemoveAmmo(); // not use ammo and not allow use
return;
}
return;
case 46699: // Requires No Ammo
if(m_target->GetTypeId() == TYPEID_PLAYER)
((Player*)m_target)->RemoveAmmo(); // not use ammo and not allow use
return;
}
break;
case SPELLFAMILY_WARRIOR:
// Overpower
if(m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000004))
{
// Must be casting target
if (!m_target->IsNonMeleeSpellCasted(false))
return;
// Earth Shield
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN && (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x40000000000)))
{
// prevent double apply bonuses
if(m_target->GetTypeId() != TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
if (Unit* caster = GetCaster())
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
return;
Unit* caster = GetCaster();
if (!caster)
return;
Unit::AuraList const& modifierAuras = caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
for(Unit::AuraList::const_iterator itr = modifierAuras.begin(); itr != modifierAuras.end(); ++itr)
{
// Unrelenting Assault
if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARRIOR && (*itr)->GetSpellProto()->SpellIconID == 2775)
{
switch ((*itr)->GetSpellProto()->Id)
{
case 46859: // Unrelenting Assault, rank 1
m_target->CastSpell(m_target,64849,true,NULL,(*itr));
break;
case 46860: // Unrelenting Assault, rank 2
m_target->CastSpell(m_target,64850,true,NULL,(*itr));
break;
default:
break;
}
break;
}
}
return;
}
break;
case SPELLFAMILY_SHAMAN:
// Tidal Force
if (GetId() == 55198)
{
// apply max stack bufs
SpellEntry const* buffEntry = sSpellStore.LookupEntry(55166);
if (!buffEntry)
return;
for(int k = 0; k < buffEntry->StackAmount; ++k)
m_target->CastSpell(m_target, buffEntry, true, NULL, this);
}
// Earth Shield
else if ((GetSpellProto()->SpellFamilyFlags & UI64LIT(0x40000000000)))
{
// prevent double apply bonuses
if(m_target->GetTypeId() != TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
if (Unit* caster = GetCaster())
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
return;
}
break;
}
}
// AT REMOVE
@ -2668,6 +2746,18 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
case SPELLFAMILY_HUNTER:
break;
case SPELLFAMILY_PALADIN:
switch(GetId())
{
case 20911: // Blessing of Sanctuary
case 25899: // Greater Blessing of Sanctuary
{
if (apply)
m_target->CastSpell(m_target, 67480, true, NULL, this);
else
m_target->RemoveAurasDueToSpell(67480);
return;
}
}
break;
case SPELLFAMILY_SHAMAN:
{
@ -3148,6 +3238,22 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
}
// Murloc costume
case 42365: m_target->SetDisplayId(21723); break;
// Honor the Dead
case 65386:
case 65495:
{
switch(m_target->getGender())
{
case GENDER_MALE:
m_target->SetDisplayId(29203); // Chapman
break;
case GENDER_FEMALE:
case GENDER_NONE:
m_target->SetDisplayId(29204); // Catrina
break;
}
break;
}
default: break;
}
}
@ -5662,6 +5768,8 @@ void Aura::HandleShapeshiftBoosts(bool apply)
((Player*)m_target)->RemoveSpellCooldown(49868);
break;
case FORM_GHOSTWOLF:
spellId1 = 67116;
break;
case FORM_AMBIENT:
case FORM_GHOUL:
case FORM_STEALTH:
@ -5789,6 +5897,7 @@ void Aura::HandleShapeshiftBoosts(bool apply)
void Aura::HandleSpellSpecificBoosts(bool apply)
{
bool cast_at_remove = false; // if spell must be casted at aura remove
uint32 spellId1 = 0;
uint32 spellId2 = 0;
uint32 spellId3 = 0;
@ -5796,6 +5905,33 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_MAGE:
{
// Ice Barrier
if (m_spellProto->SpellIconID == 32)
{
if (!apply && (m_removeMode == AURA_REMOVE_BY_DISPEL || (m_removeMode == AURA_REMOVE_BY_DEFAULT && !GetModifier()->m_amount)))
{
Unit::AuraList const& dummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
// Shattered Barrier
if ((*itr)->GetSpellProto()->SpellIconID == 2945)
{
cast_at_remove = true;
// first rank have 50% chance
if ((*itr)->GetId() != 44745 || roll_chance_i(50))
spellId1 = 55080;
break;
}
}
}
else
return;
}
else
return;
}
case SPELLFAMILY_WARRIOR:
{
if(!apply)
@ -5817,14 +5953,72 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
}
break;
}
case SPELLFAMILY_WARLOCK:
// Fear
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000040000000000))
{
if(!apply)
{
Unit* caster = GetCaster();
if(!caster)
return;
Unit::AuraList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
SpellEntry const* dummyEntry = (*itr)->GetSpellProto();
// Improved Fear
if (dummyEntry->SpellFamilyName == SPELLFAMILY_WARLOCK && dummyEntry->SpellIconID == 98)
{
cast_at_remove = true;
switch((*itr)->GetModifier()->m_amount)
{
// Rank 1
case 0: spellId1 = 60946; break;
// Rank 1
case 1: spellId1 = 60947; break;
}
break;
}
}
}
else
return;
}
else
return;
break;
case SPELLFAMILY_PRIEST:
{
// Shadow Word: Pain (need visual check fro skip improvement talent) or Vampiric Touch
if (m_spellProto->SpellIconID == 234 && m_spellProto->SpellVisual[0] || m_spellProto->SpellIconID == 2213)
{
if (!apply && m_removeMode == AURA_REMOVE_BY_DISPEL)
{
Unit* caster = GetCaster();
if(!caster)
return;
Unit::AuraList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
// Shadow Affinity
if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST
&& (*itr)->GetSpellProto()->SpellIconID == 178)
{
// custom cast code
int32 basepoints0 = (*itr)->GetModifier()->m_amount * caster->GetCreateMana() / 100;
caster->CastCustomSpell(caster, 64103, &basepoints0, NULL, NULL, true, NULL, this);
return;
}
}
}
else
return;
}
switch(GetId())
{
// Dispersion mana reg and immunity
case 47585:
spellId1 = 60069; // Dispersion
spellId2 = 63230; // Dispersion
break;
// Abolish Disease (remove 1 more poison effect with Body and Soul)
case 552:
{
@ -5851,10 +6045,16 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
spellId1 = 64134; // Body and Soul (periodic dispel effect)
break;
}
// Dispersion mana reg and immunity
case 47585:
spellId1 = 60069; // Dispersion
spellId2 = 63230; // Dispersion
break;
default:
return;
}
break;
}
case SPELLFAMILY_ROGUE:
// Sprint (skip non player casted spells by category)
if (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000000040) && GetSpellProto()->Category == 44)
@ -5963,7 +6163,7 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
// prevent aura deletion, specially in multi-boost case
SetInUse(true);
if (apply)
if (apply || cast_at_remove)
{
if (spellId1)
m_target->CastSpell(m_target, spellId1, true, NULL, this);
@ -6259,47 +6459,10 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real)
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
m_modifier.m_amount += (int32)DoneActualBenefit;
// now that the correct amount is computed, apply caster aura, if any
switch(m_spellProto->SpellFamilyName)
{
case SPELLFAMILY_PRIEST:
// Power Word: Shield
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001))
{
// Glyph of Power Word: Shield
if(Aura* glyph = caster->GetAura(55672,0))
{
// instant heal glyph m_amount% of the absorbed amount
int32 heal = (glyph->GetModifier()->m_amount * m_modifier.m_amount)/100;
caster->CastCustomSpell(m_target, 56160, &heal, NULL, NULL, true, 0, this);
}
}
break;
default:
break;
}
}
}
else
{
// Ice Barrier (remove effect from Shattered Barrier)
if (m_spellProto->SpellIconID == 32 && m_spellProto->SpellFamilyName == SPELLFAMILY_MAGE)
{
if (!((m_removeMode == AURA_REMOVE_BY_DEFAULT && !m_modifier.m_amount) || m_removeMode == AURA_REMOVE_BY_DISPEL))
return;
if (m_target->HasAura(44745,0)) // Shattered Barrier, rank 1
{
if(roll_chance_i(50))
m_target->CastSpell(m_target, 55080, true, NULL, this);
}
else if (m_target->HasAura(54787,0)) // Shattered Barrier, rank 2
{
m_target->CastSpell(m_target, 55080, true, NULL, this);
}
}
if (caster &&
// Power Word: Shield
m_spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellProto->Mechanic == MECHANIC_SHIELD &&
@ -7539,3 +7702,26 @@ void Aura::HandleAuraModAllCritChance(bool apply, bool Real)
// included in Player::UpdateSpellCritChance calculation
((Player*)m_target)->UpdateAllSpellCritChances();
}
void Aura::HandleAllowOnlyAbility(bool apply, bool Real)
{
if(!Real)
return;
if(apply)
{
m_target->setAttackTimer(BASE_ATTACK,m_duration);
m_target->setAttackTimer(RANGED_ATTACK,m_duration);
m_target->setAttackTimer(OFF_ATTACK,m_duration);
}
else
{
m_target->resetAttackTimer(BASE_ATTACK);
m_target->resetAttackTimer(RANGED_ATTACK);
m_target->resetAttackTimer(OFF_ATTACK);
}
m_target->UpdateDamagePhysical(BASE_ATTACK);
m_target->UpdateDamagePhysical(RANGED_ATTACK);
m_target->UpdateDamagePhysical(OFF_ATTACK);
}

View file

@ -214,6 +214,7 @@ class MANGOS_DLL_SPEC Aura
void HandlePhase(bool Apply, bool Real);
void HandleModTargetArmorPct(bool Apply, bool Real);
void HandleAuraModAllCritChance(bool Apply, bool Real);
void HandleAllowOnlyAbility(bool Apply, bool Real);
virtual ~Aura();
@ -268,6 +269,13 @@ class MANGOS_DLL_SPEC Aura
{
if (m_procCharges == 0)
return false;
// exist spells that have maxStack > 1 and m_procCharges > 0 (==1 in fact)
// all like stacks have 1 value in one from this fields
// so return true for allow remove one aura from stacks as expired
if (GetStackAmount() > 1)
return true;
m_procCharges--;
SendAuraUpdate(false);
return m_procCharges == 0;

View file

@ -515,12 +515,14 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
// Ferocious Bite
if (m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & UI64LIT(0x000800000)) && m_spellInfo->SpellVisual[0]==6587)
{
// converts each extra point of energy into ($f1+$AP/410) additional damage
// converts up to 30 points of energy into ($f1+$AP/410) additional damage
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
m_caster->SetPower(POWER_ENERGY,0);
uint32 energy = m_caster->GetPower(POWER_ENERGY);
uint32 used_energy = energy > 30 ? 30 : energy;
damage += int32(used_energy * multiple);
m_caster->SetPower(POWER_ENERGY,energy-used_energy);
}
// Rake
else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000001000) && m_spellInfo->Effect[2]==SPELL_EFFECT_ADD_COMBO_POINTS)
@ -1441,14 +1443,14 @@ void Spell::EffectDummy(uint32 i)
uint32 rage = m_caster->GetPower(POWER_RAGE);
// up to max 30 rage cost
if(rage > 30)
rage = 30;
if(rage > 300)
rage = 300;
// Glyph of Execution bonus
uint32 rage_modified = rage;
if (Aura *aura = m_caster->GetDummyAura(58367))
rage_modified += aura->GetModifier()->m_amount;
rage_modified += aura->GetModifier()->m_amount*10;
int32 basePoints0 = damage+int32(rage_modified * m_spellInfo->DmgMultiplier[i] +
m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
@ -1465,7 +1467,7 @@ void Spell::EffectDummy(uint32 i)
if ((*itr)->GetSpellProto()->SpellIconID == 1989)
{
// saved rage top stored in next affect
uint32 lastrage = (*itr)->GetSpellProto()->CalculateSimpleValue(1);
uint32 lastrage = (*itr)->GetSpellProto()->CalculateSimpleValue(1)*10;
if(lastrage < rage)
rage -= lastrage;
break;
@ -1491,6 +1493,7 @@ void Spell::EffectDummy(uint32 i)
m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
return;
}
switch(m_spellInfo->Id)
{
// Warrior's Wrath
@ -2337,7 +2340,7 @@ void Spell::EffectTeleportUnits(uint32 i)
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)unitTarget)->TeleportTo(((Player*)unitTarget)->m_homebindMapId,((Player*)unitTarget)->m_homebindX,((Player*)unitTarget)->m_homebindY,((Player*)unitTarget)->m_homebindZ,unitTarget->GetOrientation(),unitTarget==m_caster ? TELE_TO_SPELL : 0);
((Player*)unitTarget)->TeleportToHomebind(unitTarget==m_caster ? TELE_TO_SPELL : 0);
return;
}
case TARGET_AREAEFFECT_INSTANT: // in all cases first TARGET_TABLE_X_Y_Z_COORDINATES
@ -2675,6 +2678,9 @@ void Spell::EffectHeal( uint32 /*i*/ )
addhealth += damageAmount;
}
// Death Pact (percent heal)
else if (m_spellInfo->Id==48743)
addhealth = addhealth * unitTarget->GetMaxHealth() / 100;
// Swiftmend - consumes Regrowth or Rejuvenation
else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
{
@ -2770,21 +2776,21 @@ void Spell::EffectHealthLeech(uint32 i)
sLog.outDebug("HealthLeech :%i", damage);
uint32 curHealth = unitTarget->GetHealth();
damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage );
if (curHealth < damage)
damage = curHealth;
float multiplier = m_spellInfo->EffectMultipleValue[i];
if (Player *modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
int32 new_damage = int32(damage*multiplier);
uint32 curHealth = unitTarget->GetHealth();
new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage );
if (curHealth < new_damage)
new_damage = curHealth;
uint32 heal = uint32(damage*multiplier);
if (m_caster->isAlive())
{
new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
m_caster->DealHeal(m_caster, uint32(new_damage), m_spellInfo);
heal = m_caster->SpellHealingBonus(m_caster, m_spellInfo, heal, HEAL);
m_caster->DealHeal(m_caster, heal, m_spellInfo);
}
}
@ -3392,54 +3398,99 @@ void Spell::EffectApplyAreaAura(uint32 i)
void Spell::EffectSummonType(uint32 i)
{
switch(m_spellInfo->EffectMiscValueB[i])
uint32 prop_id = m_spellInfo->EffectMiscValueB[i];
SummonPropertiesEntry const *summon_prop = sSummonPropertiesStore.LookupEntry(prop_id);
if(!summon_prop)
{
case SUMMON_TYPE_GUARDIAN:
case SUMMON_TYPE_POSESSED:
case SUMMON_TYPE_POSESSED2:
case SUMMON_TYPE_FORCE_OF_NATURE:
case SUMMON_TYPE_GUARDIAN2:
case SUMMON_TYPE_GUARDIAN3:
// Jewelery statue case (totem like)
if(m_spellInfo->SpellIconID == 2056)
EffectSummonTotem(i);
sLog.outError("EffectSummonType: Unhandled summon type %u", prop_id);
return;
}
switch(summon_prop->Group)
{
// faction handled later on, or loaded from template
case SUMMON_PROP_GROUP_WILD:
case SUMMON_PROP_GROUP_FRIENDLY:
{
switch(summon_prop->Type)
{
case SUMMON_PROP_TYPE_SIEGE_VEH:
case SUMMON_PROP_TYPE_DRAKE_VEH:
{
// TODO
// EffectSummonVehicle(i);
break;
}
case SUMMON_PROP_TYPE_TOTEM:
{
EffectSummonTotem(i, summon_prop->Slot);
break;
}
case SUMMON_PROP_TYPE_SUMMON:
case SUMMON_PROP_TYPE_GUARDIAN:
case SUMMON_PROP_TYPE_ARMY:
case SUMMON_PROP_TYPE_DK:
case SUMMON_PROP_TYPE_CONSTRUCT:
{
// JC golems - 32804, etc -- fits much better totem AI
if(m_spellInfo->SpellIconID == 2056)
EffectSummonTotem(i);
if(prop_id == 832) // scrapbot
EffectSummonWild(i, summon_prop->FactionId);
else
EffectSummonGuardian(i, summon_prop->FactionId);
break;
}
case SUMMON_PROP_TYPE_CRITTER:
{
EffectSummonCritter(i, summon_prop->FactionId);
break;
}
case SUMMON_PROP_TYPE_OTHER:
case SUMMON_PROP_TYPE_PHASING:
case SUMMON_PROP_TYPE_LIGHTWELL:
{
// those are classical totems - effectbasepoints is their hp and not summon ammount!
//SUMMON_TYPE_TOTEM = 121: 23035, battlestands
//SUMMON_TYPE_TOTEM2 = 647: 52893, Anti-Magic Zone (npc used)
if(prop_id == 121 || prop_id == 647)
EffectSummonTotem(i);
else
EffectSummonWild(i, summon_prop->FactionId);
break;
}
default:
sLog.outError("EffectSummonType: Unhandled summon type %u", summon_prop->Type);
break;
}
break;
}
case SUMMON_PROP_GROUP_PETS:
{
// FIXME : multiple summons - not yet supported as pet
//1562 - force of nature - sid 33831
//1161 - feral spirit - sid 51533
if(prop_id == 1562) // 3 uncontrolable instead of one controllable :/
EffectSummonGuardian(i, summon_prop->FactionId);
else
EffectSummonGuardian(i);
EffectSummon(i);
break;
case SUMMON_TYPE_WILD:
case SUMMON_TYPE_QUEST_WILD:
case SUMMON_TYPE_CREATURE:
EffectSummonWild(i);
}
case SUMMON_PROP_GROUP_CONTROLLABLE:
{
// no type here
// maybe wrong - but thats the handler currently used for those
EffectSummonGuardian(i, summon_prop->FactionId);
break;
case SUMMON_TYPE_DEMON:
case SUMMON_TYPE_INFERNO:
EffectSummonDemon(i);
break;
case SUMMON_TYPE_SUMMON:
case SUMMON_TYPE_ELEMENTAL:
EffectSummon(i);
break;
case SUMMON_TYPE_CRITTER:
case SUMMON_TYPE_CRITTER2:
case SUMMON_TYPE_CRITTER3:
case SUMMON_TYPE_QUEST_CRITTER:
EffectSummonCritter(i);
break;
case SUMMON_TYPE_TOTEM_SLOT1:
case SUMMON_TYPE_TOTEM_SLOT2:
case SUMMON_TYPE_TOTEM_SLOT3:
case SUMMON_TYPE_TOTEM_SLOT4:
case SUMMON_TYPE_TOTEM:
EffectSummonTotem(i);
break;
case SUMMON_TYPE_UNKNOWN1:
case SUMMON_TYPE_UNKNOWN2:
case SUMMON_TYPE_UNKNOWN3:
case SUMMON_TYPE_UNKNOWN4:
case SUMMON_TYPE_UNKNOWN5:
}
case SUMMON_PROP_GROUP_VEHICLE:
{
// TODO
// EffectSummonVehicle(i);
break;
}
default:
sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
sLog.outError("EffectSummonType: Unhandled summon group type %u", summon_prop->Group);
break;
}
}
@ -3457,6 +3508,10 @@ void Spell::EffectSummon(uint32 i)
uint32 level = m_caster->getLevel();
Pet* spawnCreature = new Pet(SUMMON_PET);
int32 duration = GetSpellDuration(m_spellInfo);
if(Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
if (m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
{
// Summon in dest location
@ -3470,7 +3525,6 @@ void Spell::EffectSummon(uint32 i)
}
// set timer for unsummon
int32 duration = GetSpellDuration(m_spellInfo);
if (duration > 0)
spawnCreature->SetDuration(duration);
@ -3509,7 +3563,6 @@ void Spell::EffectSummon(uint32 i)
}
// set timer for unsummon
int32 duration = GetSpellDuration(m_spellInfo);
if (duration > 0)
spawnCreature->SetDuration(duration);
@ -3780,7 +3833,7 @@ void Spell::EffectAddFarsight(uint32 i)
((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID());
}
void Spell::EffectSummonWild(uint32 i)
void Spell::EffectSummonWild(uint32 i, uint32 forceFaction)
{
uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
if (!creature_entry)
@ -3796,9 +3849,7 @@ void Spell::EffectSummonWild(uint32 i)
{
uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
if (skill202)
{
level = skill202/5;
}
}
}
@ -3808,6 +3859,8 @@ void Spell::EffectSummonWild(uint32 i)
float center_z = m_targets.m_destZ;
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
int32 duration = GetSpellDuration(m_spellInfo);
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
int32 amount = damage > 0 ? damage : 1;
@ -3832,30 +3885,23 @@ void Spell::EffectSummonWild(uint32 i)
else
m_caster->GetClosePoint(px, py, pz, 3.0f);
int32 duration = GetSpellDuration(m_spellInfo);
if(Creature *summon = m_caster->SummonCreature(creature_entry, px, py, pz, m_caster->GetOrientation(), summonType, duration))
{
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
summon->SetCreatorGUID(m_caster->GetGUID());
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
m_caster->SummonCreature(creature_entry, px, py, pz, m_caster->GetOrientation(), summonType, duration);
if(forceFaction)
summon->setFaction(forceFaction);
}
}
}
void Spell::EffectSummonGuardian(uint32 i)
void Spell::EffectSummonGuardian(uint32 i, uint32 forceFaction)
{
uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
if (!pet_entry)
return;
// set timer for unsummon
int32 duration = GetSpellDuration(m_spellInfo);
// Search old Guardian only for players (if casted spell not have duration or cooldown)
// FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
// so this code hack in fact
if (m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo) == 0))
if(m_caster->FindGuardianWithEntry(pet_entry))
return; // find old guardian, ignore summon
// in another case summon new
uint32 level = m_caster->getLevel();
@ -3879,6 +3925,9 @@ void Spell::EffectSummonGuardian(uint32 i)
float center_z = m_targets.m_destZ;
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
int32 duration = GetSpellDuration(m_spellInfo);
if(Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
int32 amount = damage > 0 ? damage : 1;
@ -3930,8 +3979,8 @@ void Spell::EffectSummonGuardian(uint32 i)
spawnCreature->SetOwnerGUID(m_caster->GetGUID());
spawnCreature->setPowerType(POWER_MANA);
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
spawnCreature->setFaction(m_caster->getFaction());
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->npcflag);
spawnCreature->setFaction(forceFaction ? forceFaction : m_caster->getFaction());
spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
@ -5350,6 +5399,14 @@ void Spell::EffectScriptEffect(uint32 effIndex)
}
return;
}
// Guarded by The Light (Paladin spell with SPELLFAMILY_WARLOCK)
case 63521:
{
// Divine Plea, refresh on target (3 aura slots)
if (Aura* aura = unitTarget->GetAura(54428,0))
aura->RefreshAura();
return;
}
}
break;
}
@ -5745,7 +5802,7 @@ void Spell::EffectStuck(uint32 /*i*/)
return;
// homebind location is loaded always
pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
pTarget->TeleportToHomebind(unitTarget==m_caster ? TELE_TO_SPELL : 0);
// Stuck spell trigger Hearthstone cooldown
SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
@ -5833,21 +5890,9 @@ void Spell::EffectApplyGlyph(uint32 i)
}
}
void Spell::EffectSummonTotem(uint32 i)
void Spell::EffectSummonTotem(uint32 i, uint8 slot)
{
uint8 slot = 0;
switch(m_spellInfo->EffectMiscValueB[i])
{
case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
// Battle standard case
case SUMMON_TYPE_TOTEM: slot = 254; break;
// jewelery statue case, like totem without slot
case SUMMON_TYPE_GUARDIAN: slot = 255; break;
default: return;
}
slot = slot ? (slot - 1): 255;
if(slot < MAX_TOTEM)
{
@ -6339,7 +6384,7 @@ void Spell::EffectCharge2(uint32 /*i*/)
m_caster->Attack(unitTarget,true);
}
void Spell::EffectSummonCritter(uint32 i)
void Spell::EffectSummonCritter(uint32 i, uint32 forceFaction)
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return;
@ -6399,9 +6444,9 @@ void Spell::EffectSummonCritter(uint32 i)
critter->SetOwnerGUID(m_caster->GetGUID());
critter->SetCreatorGUID(m_caster->GetGUID());
critter->setFaction(m_caster->getFaction());
critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
critter->setFaction(forceFaction ? forceFaction : m_caster->getFaction());
critter->AIM_Initialize();
critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
//critter->InitLevelupSpellsForLevel(); // none?
@ -6764,65 +6809,6 @@ void Spell::EffectSkill(uint32 /*i*/)
sLog.outDebug("WORLD: SkillEFFECT");
}
void Spell::EffectSummonDemon(uint32 i)
{
// select center of summon position
float center_x = m_targets.m_destX;
float center_y = m_targets.m_destY;
float center_z = m_targets.m_destZ;
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
int32 amount = damage > 0 ? damage : 1;
if (m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_INFERNO)
amount = 1;
for(int32 count = 0; count < amount; ++count)
{
float px, py, pz;
// If dest location if present
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
{
// Summon 1 unit in dest location
if (count == 0)
{
px = m_targets.m_destX;
py = m_targets.m_destY;
pz = m_targets.m_destZ;
}
// Summon in random point all other units if location present
else
m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
}
// Summon if dest location not present near caster
else
m_caster->GetClosePoint(px,py,pz,3.0f);
int32 duration = GetSpellDuration(m_spellInfo);
Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,duration);
if (!Charmed) // something fatal, not attempt more
return;
// might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
Charmed->SetLevel(m_caster->getLevel());
// TODO: Add damage/mana/hp according to level
// Enslave demon effect, without mana cost and cooldown
if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
{
// Enslave demon effect, without mana cost and cooldown
m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
// Inferno effect for non player calls
if (m_spellInfo->EffectMiscValueB[i]!=SUMMON_TYPE_INFERNO)
Charmed->CastSpell(Charmed, 22703, true, 0);
}
}
}
void Spell::EffectSpiritHeal(uint32 /*i*/)
{
// TODO player can't see the heal-animation - he should respawn some ticks later

View file

@ -1329,10 +1329,8 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
spellInfo_2->SpellVisual[0] == 99 && spellInfo_1->SpellVisual[0] == 0 ) )
return false;
// Heart of the Wild and (Primal Instinct (Idol of Terror) triggering spell or Agility)
if( spellInfo_1->SpellIconID == 240 && spellInfo_2->SpellIconID == 240 && (
spellInfo_1->SpellVisual[0] == 0 && spellInfo_2->SpellVisual[0] == 78 ||
spellInfo_2->SpellVisual[0] == 0 && spellInfo_1->SpellVisual[0] == 78 ) )
// Heart of the Wild, Agility and various Idol Triggers
if(spellInfo_1->SpellIconID == 240 && spellInfo_2->SpellIconID == 240)
return false;
// Personalized Weather (thunder effect should overwrite rainy aura)
@ -1414,6 +1412,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if( spellId_1 == 35081 && spellInfo_2->SpellIconID==561 && spellInfo_2->SpellVisual[0]==7992)
return false;
// Blessing of Sanctuary (multi-family check, some from 16 spell icon spells)
if (spellInfo_1->Id == 67480 && spellInfo_2->Id == 20911)
return false;
break;
}
}
@ -1642,8 +1644,13 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
// Concentration Aura and Improved Concentration Aura and Aura Mastery
if ((spellInfo_1->SpellIconID == 1487) && (spellInfo_2->SpellIconID == 1487))
return false;
}
// Blessing of Sanctuary (multi-family check, some from 16 spell icon spells)
if (spellInfo_2->Id == 67480 && spellInfo_1->Id == 20911)
return false;
// Combustion and Fire Protection Aura (multi-family check)
if( spellInfo_2->Id == 11129 && spellInfo_1->SpellIconID == 33 && spellInfo_1->SpellVisual[0] == 321 )
return false;
@ -1663,6 +1670,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if( spellInfo_1->SpellIconID==220 && spellInfo_2->SpellIconID==220 &&
spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags )
return false;
// Ghost Wolf
if (spellInfo_1->SpellIconID == 67 && spellInfo_2->SpellIconID == 67)
return false;
}
// Bloodlust and Bloodthirst (multi-family check)
if( spellInfo_1->Id == 2825 && spellInfo_2->SpellIconID == 38 && spellInfo_2->SpellVisual[0] == 0 )
@ -1711,13 +1722,22 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if (spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
return false;
bool dummy_only = true;
for (int i = 0; i < 3; ++i)
{
if (spellInfo_1->Effect[i] != spellInfo_2->Effect[i] ||
spellInfo_1->EffectItemType[i] != spellInfo_2->EffectItemType[i] ||
spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i] ||
spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i])
return false;
// ignore dummy only spells
if(spellInfo_1->Effect[i] && spellInfo_1->Effect[i] != SPELL_EFFECT_DUMMY && spellInfo_1->EffectApplyAuraName[i] != SPELL_AURA_DUMMY)
dummy_only = false;
}
if (dummy_only)
return false;
return true;
}

View file

@ -160,12 +160,20 @@ void Totem::SetTypeBySummonSpell(SpellEntry const * spellProto)
bool Totem::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
{
// TODO: possibly all negative auras immune?
switch(spellInfo->Effect[index])
{
case SPELL_EFFECT_ATTACK_ME:
return true;
default:
break;
}
switch(spellInfo->EffectApplyAuraName[index])
{
case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_MOD_FEAR:
case SPELL_AURA_TRANSFORM:
case SPELL_AURA_MOD_TAUNT:
return true;
default:
break;

View file

@ -1693,8 +1693,47 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
// Death Prevention Aura
SpellEntry const* preventDeathSpell = NULL;
int32 preventDeathAmount = 0;
// full absorb cases (by chance)
AuraList const& vAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
for(AuraList::const_iterator i = vAbsorb.begin(); i != vAbsorb.end() && RemainingDamage > 0; ++i)
{
// only work with proper school mask damage
Modifier* i_mod = (*i)->GetModifier();
if (!(i_mod->m_miscvalue & schoolMask))
continue;
SpellEntry const* i_spellProto = (*i)->GetSpellProto();
// Fire Ward or Frost Ward
if(i_spellProto->SpellFamilyName == SPELLFAMILY_MAGE && i_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000108))
{
int chance = 0;
Unit::AuraList const& auras = pVictim->GetAurasByType(SPELL_AURA_ADD_PCT_MODIFIER);
for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
SpellEntry const* itr_spellProto = (*itr)->GetSpellProto();
// Frost Warding (chance full absorb)
if (itr_spellProto->SpellFamilyName == SPELLFAMILY_MAGE && itr_spellProto->SpellIconID == 501)
{
// chance stored in next dummy effect
chance = itr_spellProto->CalculateSimpleValue(1);
break;
}
}
if(roll_chance_i(chance))
{
int32 amount = RemainingDamage;
RemainingDamage = 0;
// Frost Warding (mana regen)
pVictim->CastCustomSpell(pVictim, 57776, &amount, NULL, NULL, true, NULL, *i);
break;
}
}
}
// Need remove expired auras after
bool existExpired = false;
// absorb without mana cost
AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
for(AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end() && RemainingDamage > 0; ++i)
@ -1802,7 +1841,17 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
preventDeathAmount = (*i)->GetModifier()->m_amount;
continue;
}
// Power Word: Shield
if (spellProto->SpellFamilyFlags & UI64LIT(00000001) && spellProto->Mechanic == MECHANIC_SHIELD)
{
// Glyph of Power Word: Shield
if (Aura *glyph = pVictim->GetAura(55672,0))
{
int32 heal = int32(glyph->GetModifier()->m_amount *
(RemainingDamage >= currentAbsorb ? currentAbsorb : RemainingDamage) / 100);
pVictim->CastCustomSpell(pVictim, 56160, &heal, NULL, NULL, true, 0, *i);
}
}
// Reflective Shield
if (spellProto->SpellFamilyFlags == 0x1 && canReflect)
{
@ -1945,13 +1994,18 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
else
currentAbsorb = RemainingDamage;
float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
if(Player *modOwner = pVictim->GetSpellModOwner())
modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
if (float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()])
{
if(Player *modOwner = pVictim->GetSpellModOwner())
modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
if (currentAbsorb > maxAbsorb)
currentAbsorb = maxAbsorb;
int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
if (currentAbsorb > maxAbsorb)
currentAbsorb = maxAbsorb;
int32 manaReduction = int32(currentAbsorb * manaMultiplier);
pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
}
(*i)->GetModifier()->m_amount -= currentAbsorb;
if((*i)->GetModifier()->m_amount <= 0)
@ -1960,12 +2014,40 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
next = vManaShield.begin();
}
int32 manaReduction = int32(currentAbsorb * manaMultiplier);
pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
RemainingDamage -= currentAbsorb;
}
// effects dependent from full absorb amount
if (int32 full_absorb = damage - RemainingDamage - *resist)
{
Unit::AuraList const& auras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
SpellEntry const* itr_spellProto = (*itr)->GetSpellProto();
// Incanter's Absorption
if (itr_spellProto->SpellFamilyName == SPELLFAMILY_GENERIC &&
itr_spellProto->SpellIconID == 2941)
{
int32 amount = int32(full_absorb * (*itr)->GetModifier()->m_amount / 100);
// apply normalized part of already accumulated amount in aura
if (Aura* spdAura = pVictim->GetAura(44413,0))
amount += spdAura->GetModifier()->m_amount * spdAura->GetAuraDuration() / spdAura->GetAuraMaxDuration();
// limit 5 health percents
int32 health_5percent = pVictim->GetMaxHealth()*5/100;
if(amount > health_5percent)
amount = health_5percent;
// Incanter's Absorption (triggered absorb based spell power, will replace existed if any)
pVictim->CastCustomSpell(pVictim, 44413, &amount, NULL, NULL, true);
break;
}
}
}
// only split damage if not damaging yourself
if(pVictim != this)
{
@ -3867,7 +3949,7 @@ void Unit::RemoveSingleAuraDueToSpellByDispel(uint32 spellId, uint64 casterGUID,
{
SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId);
// Custom dispel case
// Custom dispel cases
// Unstable Affliction
if(spellEntry->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellEntry->SpellFamilyFlags & UI64LIT(0x010000000000)))
{
@ -3881,9 +3963,43 @@ void Unit::RemoveSingleAuraDueToSpellByDispel(uint32 spellId, uint64 casterGUID,
// backfire damage and silence
dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL,casterGUID);
}
return;
}
else
// Flame Shock
if (spellEntry->SpellFamilyName == SPELLFAMILY_SHAMAN && (spellEntry->SpellFamilyFlags & UI64LIT(0x10000000)))
{
Unit* caster = NULL;
uint32 triggeredSpell = 0;
if (Aura* dotAura = GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, UI64LIT(0x10000000), 0x00000000, casterGUID))
caster = dotAura->GetCaster();
if (caster && !caster->isDead())
{
Unit::AuraList const& auras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i)
{
switch((*i)->GetId())
{
case 51480: triggeredSpell=64694; break;// Lava Flows, Rank 1
case 51481: triggeredSpell=65263; break;// Lava Flows, Rank 2
case 51482: triggeredSpell=65264; break;// Lava Flows, Rank 3
default: continue;
}
break;
}
}
// Remove spell auras from stack
RemoveSingleSpellAurasByCasterSpell(spellId, casterGUID, AURA_REMOVE_BY_DISPEL);
// Haste
if (triggeredSpell)
caster->CastSpell(caster, triggeredSpell, true);
return;
}
RemoveSingleSpellAurasByCasterSpell(spellId, casterGUID, AURA_REMOVE_BY_DISPEL);
}
void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer)
@ -5600,6 +5716,34 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
{
switch(dummySpell->Id)
{
// Leader of the Pack
case 24932:
{
// dummy m_amount store health percent (!=0 if Improved Leader of the Pack applied)
int32 heal_percent = triggeredByAura->GetModifier()->m_amount;
if (!heal_percent)
return false;
// check explicitly only to prevent mana cast when halth cast cooldown
if (cooldown && ((Player*)this)->HasSpellCooldown(34299))
return false;
// health
triggered_spell_id = 34299;
basepoints0 = GetMaxHealth() * heal_percent / 100;
target = this;
// mana to caster
if (triggeredByAura->GetCasterGUID() == GetGUID())
{
if (SpellEntry const* manaCastEntry = sSpellStore.LookupEntry(60889))
{
int32 mana_percent = manaCastEntry->CalculateSimpleValue(0) * heal_percent;
CastCustomSpell(this, manaCastEntry, &mana_percent, NULL, NULL, true, castItem, triggeredByAura);
}
}
break;
}
// Healing Touch (Dreamwalker Raiment set)
case 28719:
{
@ -5825,13 +5969,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
basepoints0 = GetAttackTime(BASE_ATTACK) * int32(ap*0.022f + 0.044f * holy) / 1000;
break;
}
// Sacred Shield
if (dummySpell->SpellFamilyFlags & UI64LIT(0x0008000000000000))
{
triggered_spell_id = 58597;
target = this;
break;
}
// Righteous Vengeance
if (dummySpell->SpellIconID == 3025)
{
@ -5853,14 +5990,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
// Judgement of Light
case 20185:
{
// Get judgement caster
Unit *caster = triggeredByAura->GetCaster();
if (!caster)
return false;
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = caster->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
caster->SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, this);
basepoints0 = int32(ap*0.10f + 0.10f*holy);
basepoints0 = int32( pVictim->GetMaxHealth() * triggeredByAura->GetModifier()->m_amount / 100 );
pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
return true;
}
@ -5932,6 +6062,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
}
break;
}
// Spiritual Attunement
case 31785:
case 33776:
{
// if healed by another unit (pVictim)
if(this == pVictim)
return false;
// heal amount
basepoints0 = triggerAmount*damage/100;
target = this;
triggered_spell_id = 31786;
break;
}
// Seal of Vengeance (damage calc on apply aura)
case 31801:
{
@ -5969,20 +6113,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
// Replenishment
CastSpell(this, 57669, true, NULL, triggeredByAura);
break;
// Spiritual Attunement
case 31785:
case 33776:
{
// if healed by another unit (pVictim)
if(this == pVictim)
return false;
// heal amount
basepoints0 = triggerAmount*damage/100;
target = this;
triggered_spell_id = 31786;
break;
}
// Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
case 40470:
{
@ -6011,29 +6141,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
break;
}
// Seal of Corruption (damage calc on apply aura)
case 53736:
{
if(effIndex != 0) // effect 1,2 used by seal unleashing code
return false;
triggered_spell_id = 53742;
// Add 5-stack effect
int8 stacks = 0;
AuraList const& auras = target->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
{
if( ((*itr)->GetId() == 53742) && (*itr)->GetCasterGUID()==GetGUID())
{
stacks = (*itr)->GetStackAmount();
break;
}
}
if(stacks >= 5)
CastSpell(target,53739,true,NULL,triggeredByAura);
break;
}
// Light's Beacon (heal target area aura)
case 53651:
{
@ -6069,6 +6176,43 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
beacon->CastCustomSpell(beacon,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura,pVictim->GetGUID());
return true;
}
// Seal of Corruption (damage calc on apply aura)
case 53736:
{
if(effIndex != 0) // effect 1,2 used by seal unleashing code
return false;
triggered_spell_id = 53742;
// Add 5-stack effect
int8 stacks = 0;
AuraList const& auras = target->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
{
if( ((*itr)->GetId() == 53742) && (*itr)->GetCasterGUID()==GetGUID())
{
stacks = (*itr)->GetStackAmount();
break;
}
}
if(stacks >= 5)
CastSpell(target,53739,true,NULL,triggeredByAura);
break;
}
// Glyph of Flash of Light
case 54936:
{
triggered_spell_id = 54957;
basepoints0 = triggerAmount*damage/100;
break;
}
// Glyph of Holy Light
case 54937:
{
triggered_spell_id = 54968;
basepoints0 = triggerAmount*damage/100;
break;
}
// Glyph of Divinity
case 54939:
{
@ -6082,18 +6226,23 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
}
return true;
}
// Glyph of Flash of Light
case 54936:
// Sacred Shield (buff)
case 58597:
{
triggered_spell_id = 54957;
basepoints0 = triggerAmount*damage/100;
triggered_spell_id = 66922;
SpellEntry const* triggeredEntry = sSpellStore.LookupEntry(triggered_spell_id);
if (!triggeredEntry)
return false;
basepoints0 = int32(damage / (GetSpellDuration(triggeredEntry) / triggeredEntry->EffectAmplitude[0]));
target = this;
break;
}
// Glyph of Holy Light
case 54937:
// Sacred Shield (talent rank)
case 53601:
{
triggered_spell_id = 54968;
basepoints0 = triggerAmount*damage/100;
triggered_spell_id = 58597;
target = this;
break;
}
}
@ -6324,7 +6473,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
uint32 spell = (*itr)->GetSpellProto()->EffectTriggerSpell[(*itr)->GetEffIndex()];
CastSpell(this, spell, true, castItem, triggeredByAura);
if ((*itr)->DropAuraCharge())
RemoveAurasDueToSpell((*itr)->GetId());
RemoveSingleSpellAurasFromStack((*itr)->GetId());
return true;
}
}
@ -6426,7 +6575,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
}
CastSpell(target, spell, true, castItem, triggeredByAura);
if ((*itr)->DropAuraCharge())
RemoveAurasDueToSpell((*itr)->GetId());
RemoveSingleSpellAurasFromStack((*itr)->GetId());
return true;
}
}
@ -6919,16 +7068,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
}
case SPELLFAMILY_DRUID:
{
// Leader of the Pack
if (auraSpellInfo->Id == 24932)
{
if (triggerAmount == 0)
return false;
basepoints[0] = triggerAmount * GetMaxHealth() / 100;
trigger_spell_id = 34299;
}
// Druid Forms Trinket
else if (auraSpellInfo->Id==37336)
if (auraSpellInfo->Id==37336)
{
switch(m_form)
{
@ -7152,7 +7293,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
case SPELL_SCHOOL_NATURE: trigger_spell_id = 50488; break;
case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break;
case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; break;
case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break;
case SPELL_SCHOOL_ARCANE: trigger_spell_id = 50486; break;
default:
return false;
}
@ -7525,6 +7666,9 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, Aura
case 5497: // Improved Mana Gems (Serpent-Coil Braid)
triggered_spell_id = 37445; // Mana Surge
break;
case 6953: // Warbringer
RemoveAurasAtMechanicImmunity(IMMUNE_TO_ROOT_AND_SNARE_MASK,0,true);
return true;
case 8152: // Serendipity
{
// if heal your target over maximum health
@ -8904,10 +9048,9 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
case SPELL_DAMAGE_CLASS_RANGED:
{
if (pVictim)
{
crit_chance = GetUnitCriticalChance(attackType, pVictim);
crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
}
crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
break;
}
default:
@ -10252,7 +10395,12 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
// Apply strongest slow aura mod to speed
int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED);
if (slow)
{
speed *=(100.0f + slow)/100.0f;
float min_speed = (float)GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MINIMUM_SPEED) / 100.0f;
if (speed < min_speed)
speed = min_speed;
}
SetSpeed(mtype, speed, forced);
}
@ -10710,6 +10858,9 @@ int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_in
durationMod_always+=target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->Dispel);
// Find max mod (negative bonus)
int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic);
if (!IsPositiveSpell(spellProto->Id))
durationMod_always += target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS, spellProto->DmgClass);
int32 durationMod = 0;
// Select strongest negative mod
@ -11578,6 +11729,7 @@ bool InitTriggerAuraData()
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true;
isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
isTriggerAura[SPELL_AURA_MAELSTROM_WEAPON] = true;
isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN]=true;
isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK]=true;
@ -11868,6 +12020,13 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
continue;
}
break;
case SPELL_AURA_MAELSTROM_WEAPON:
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s maelstrom aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
// remove all stack;
RemoveSpellsCausingAura(SPELL_AURA_MAELSTROM_WEAPON);
triggeredByAura->SetInUse(false); // this safe, aura locked
continue; // avoid re-remove attempts
default:
// nothing do, just charges counter
break;
@ -11890,7 +12049,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
removedSpells.unique();
// Remove auras from removedAuras
for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();++i)
RemoveAurasDueToSpell(*i);
RemoveSingleSpellAurasFromStack(*i);
}
}

View file

@ -1176,7 +1176,7 @@ void World::SetInitialWorldSettings()
sObjectMgr.LoadQuestLocales();
sObjectMgr.LoadNpcTextLocales();
sObjectMgr.LoadPageTextLocales();
sObjectMgr.LoadNpcOptionLocales();
sObjectMgr.LoadGossipMenuItemsLocales();
sObjectMgr.LoadPointOfInterestLocales();
sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts)
sLog.outString( ">>> Localization strings loaded" );
@ -1405,8 +1405,14 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Npc Text Id..." );
sObjectMgr.LoadNpcTextId(); // must be after load Creature and NpcText
sLog.outString( "Loading Npc Options..." );
sObjectMgr.LoadNpcOptions();
sLog.outString( "Loading Gossip scripts..." );
sObjectMgr.LoadGossipScripts(); // must be before gossip menu options
sLog.outString( "Loading Gossip menus..." );
sObjectMgr.LoadGossipMenu();
sLog.outString( "Loading Gossip menu options..." );
sObjectMgr.LoadGossipMenuItems();
sLog.outString( "Loading Vendors..." );
sObjectMgr.LoadVendors(); // must be after load CreatureTemplate and ItemTemplate

View file

@ -355,7 +355,7 @@ void WorldSession::LogoutPlayer(bool Save)
///- Teleport to home if the player is in an invalid instance
if(!_player->m_InstanceValid && !_player->isGameMaster())
{
_player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation());
_player->TeleportToHomebind();
//this is a bad place to call for far teleport because we need player to be in world for successful logout
//maybe we should implement delayed far teleport logout?
}

View file

@ -152,6 +152,14 @@ bool ChatHandler::HandleCharacterDeleteCommand(const char* args)
return true;
}
/// Close RA connection
bool ChatHandler::HandleQuitCommand(const char* /*args*/)
{
// processed in RASocket
SendSysMessage(LANG_QUIT_WRONG_USE_ERROR);
return true;
}
/// Exit the realm
bool ChatHandler::HandleServerExitCommand(const char* /*args*/)
{

View file

@ -225,7 +225,10 @@ void RASocket::OnRead()
if (strlen(buff))
{
sLog.outRALog("Got '%s' cmd.\n",buff);
sWorld.QueueCliCommand(&RASocket::zprint , buff);
if (strncmp(buff,"quit",4)==0)
SetCloseAndDelete();
else
sWorld.QueueCliCommand(&RASocket::zprint, buff);
}
else
Sendf("mangos>");

View file

@ -25,8 +25,8 @@ extern DatabasePostgre WorldDatabase;
extern DatabaseMysql WorldDatabase;
#endif
const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis";
const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii";
const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis";
const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii";
const char CreatureDataAddonInfofmt[]="iiiiiis";
const char CreatureModelfmt[]="iffbi";
const char CreatureInfoAddonInfofmt[]="iiiiiis";

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "8913"
#define REVISION_NR "8971"
#endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_8874_01_characters_character_skills"
#define REVISION_DB_MANGOS "required_8912_01_mangos_spell_proc_event"
#define REVISION_DB_MANGOS "required_8965_02_mangos_command"
#define REVISION_DB_REALMD "required_8728_01_realmd_account"
#endif // __REVISION_SQL_H__