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, `version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0', `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'; ) 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 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 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.'), ('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.'), ('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',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.'), ('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', `name` char(100) NOT NULL default '0',
`subname` char(100) default NULL, `subname` char(100) default NULL,
`IconName` 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', `minlevel` tinyint(3) unsigned NOT NULL default '1',
`maxlevel` tinyint(3) unsigned NOT NULL default '1', `maxlevel` tinyint(3) unsigned NOT NULL default '1',
`minhealth` int(10) unsigned NOT NULL default '0', `minhealth` int(10) unsigned NOT NULL default '0',
@ -1155,7 +1157,7 @@ CREATE TABLE `creature_template` (
LOCK TABLES `creature_template` WRITE; LOCK TABLES `creature_template` WRITE;
/*!40000 ALTER TABLE `creature_template` DISABLE KEYS */; /*!40000 ALTER TABLE `creature_template` DISABLE KEYS */;
INSERT INTO `creature_template` VALUES 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 */; /*!40000 ALTER TABLE `creature_template` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
@ -1899,6 +1901,115 @@ LOCK TABLES `gameobject_template` WRITE;
/*!40000 ALTER TABLE `gameobject_template` ENABLE KEYS */; /*!40000 ALTER TABLE `gameobject_template` ENABLE KEYS */;
UNLOCK TABLES; 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` -- Table structure for table `instance_template`
-- --
@ -2344,6 +2455,42 @@ LOCK TABLES `locales_gameobject` WRITE;
/*!40000 ALTER TABLE `locales_gameobject` ENABLE KEYS */; /*!40000 ALTER TABLE `locales_gameobject` ENABLE KEYS */;
UNLOCK TABLES; 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` -- Table structure for table `locales_item`
-- --
@ -2379,42 +2526,6 @@ LOCK TABLES `locales_item` WRITE;
/*!40000 ALTER TABLE `locales_item` ENABLE KEYS */; /*!40000 ALTER TABLE `locales_item` ENABLE KEYS */;
UNLOCK TABLES; 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` -- 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), (1012,'===========================================================================',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1013,'|%15s| %20s | %15s |%4d| %9d |',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), (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), (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), (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), (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 */; /*!40000 ALTER TABLE `npc_gossip` ENABLE KEYS */;
UNLOCK TABLES; 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` -- 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'), (3606, 0.1667, 0, 0, 'Shaman - Searing Totem Attack'),
/* Warlock */ /* Warlock */
(17962, 0, 0, 0, 'Warlock - Conflagrate'), (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'), (980, 0, 0.1, 0, 'Warlock - Curse of Agony'),
(603, 0, 2, 0, 'Warlock - Curse of Doom'), (603, 0, 2, 0, 'Warlock - Curse of Doom'),
(18220, 0.96, 0, 0, 'Warlock - Dark Pact'), (18220, 0.96, 0, 0, 'Warlock - Dark Pact'),
@ -15283,6 +15347,18 @@ INSERT INTO spell_chain VALUES
(26801,12180,3908,5,0), (26801,12180,3908,5,0),
(51309,26790,3908,6,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 --(203)Pet-Spider
--(208)Pet-Wolf --(208)Pet-Wolf
--(212)Pet-Crocolisk --(212)Pet-Crocolisk
@ -15304,18 +15380,6 @@ INSERT INTO spell_chain VALUES
(52473,27050,17253,10,0), (52473,27050,17253,10,0),
(52474,52473,17253,11,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 -- (204) Pet - Voidwalker
------------------*/ ------------------*/
/*Consume Shadows*/ /*Consume Shadows*/
@ -15376,6 +15440,16 @@ INSERT INTO spell_chain VALUES
(11785,11784,6360,4,0), (11785,11784,6360,4,0),
(27275,11785,6360,5,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 -- (209) Pet - Cat
------------------*/ ------------------*/
/*Prowl*/ /*Prowl*/
@ -17033,6 +17107,16 @@ INSERT INTO spell_chain VALUES
(53597,53596,50274,5,0), (53597,53596,50274,5,0),
(53598,53597,50274,6,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 --(768)Pet-Serpent
------------------*/ ------------------*/
/*PoisonSpit*/ /*PoisonSpit*/
@ -18168,6 +18252,7 @@ INSERT INTO `spell_proc_event` VALUES
(49622, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 60), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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), (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); (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 \ 8908_01_mangos_spell_chain.sql \
8909_01_mangos_spell_proc_event.sql \ 8909_01_mangos_spell_proc_event.sql \
8912_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 README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -356,4 +368,16 @@ EXTRA_DIST = \
8908_01_mangos_spell_chain.sql \ 8908_01_mangos_spell_chain.sql \
8909_01_mangos_spell_proc_event.sql \ 8909_01_mangos_spell_proc_event.sql \
8912_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 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) for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first); Player *plr = sObjectMgr.GetPlayer(itr->first);
if (plr) if (plr)
plr->GetSession()->SendPacket(packet); plr->GetSession()->SendPacket(packet);
else 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) for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first); Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr) 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; 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) for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first); Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr) 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; 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) for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first); Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr) 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; 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) for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first); Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr) 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; 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) for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
if (itr->second.OfflineRemoveTime)
continue;
Player *plr = sObjectMgr.GetPlayer(itr->first); Player *plr = sObjectMgr.GetPlayer(itr->first);
if (!plr) 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; continue;
} }
@ -721,10 +732,9 @@ void BattleGround::EndBattleGround(uint32 winner)
for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
Player *plr = sObjectMgr.GetPlayer(itr->first);
uint32 team = itr->second.Team; uint32 team = itr->second.Team;
if (!plr) if (itr->second.OfflineRemoveTime)
{ {
//if rated arena match - make member lost! //if rated arena match - make member lost!
if (isArena() && isRated() && winner_arena_team && loser_arena_team) if (isArena() && isRated() && winner_arena_team && loser_arena_team)
@ -734,7 +744,12 @@ void BattleGround::EndBattleGround(uint32 winner)
else else
loser_arena_team->OfflineMemberLost(itr->first, winner_rating); 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; continue;
} }
@ -1285,14 +1300,13 @@ void BattleGround::EventPlayerLoggedOut(Player* player)
m_Players[player->GetGUID()].OfflineRemoveTime = sWorld.GetGameTime() + MAX_OFFLINE_TIME; m_Players[player->GetGUID()].OfflineRemoveTime = sWorld.GetGameTime() + MAX_OFFLINE_TIME;
if (GetStatus() == STATUS_IN_PROGRESS) if (GetStatus() == STATUS_IN_PROGRESS)
{ {
if (isBattleGround()) // drop flag and handle other cleanups
EventPlayerDroppedFlag(player); RemovePlayer(player, player->GetGUID());
else
{ // 1 player is logging out, if it is the last, then end arena!
//1 player is logging out, if it is the last, then end arena! if (isArena())
if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam()))) if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())))
EndBattleGround(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]); Player *plr = sObjectMgr.GetPlayer(m_PlayersNearPoint[BG_EY_NODES_MAX][j]);
if (!plr) 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; ++j;
continue; continue;
} }
@ -170,7 +170,7 @@ void BattleGroundEY::CheckSomeoneLeftPoint()
Player *plr = sObjectMgr.GetPlayer(m_PlayersNearPoint[i][j]); Player *plr = sObjectMgr.GetPlayer(m_PlayersNearPoint[i][j]);
if (!plr) 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 //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[BG_EY_NODES_MAX].push_back(m_PlayersNearPoint[i][j]);
m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + 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 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()) 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; action = 0;
} }
} }

View file

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

View file

@ -423,6 +423,8 @@ ChatCommand * ChatHandler::getCommandTable()
{ "gameobject_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGOQuestRelationsCommand, "", NULL }, { "gameobject_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGOQuestRelationsCommand, "", NULL },
{ "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL }, { "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL },
{ "gameobject_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", 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_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL },
{ "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, { "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL },
{ "item_required_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemRequiredTragetCommand, "", 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 }, { "mangos_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadMangosStringCommand, "", NULL },
{ "milling_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesMillingCommand, "", NULL }, { "milling_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesMillingCommand, "", NULL },
{ "npc_gossip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcGossipCommand, "", 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_spellclick_spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellClickSpellsCommand, "",NULL},
{ "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL }, { "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL },
{ "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL }, { "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL },
@ -666,6 +667,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "flusharenapoints",SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL }, { "flusharenapoints",SEC_ADMINISTRATOR, false, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL },
{ "repairitems", SEC_GAMEMASTER, true, &ChatHandler::HandleRepairitemsCommand, "", NULL }, { "repairitems", SEC_GAMEMASTER, true, &ChatHandler::HandleRepairitemsCommand, "", NULL },
{ "waterwalk", SEC_GAMEMASTER, false, &ChatHandler::HandleWaterwalkCommand, "", NULL }, { "waterwalk", SEC_GAMEMASTER, false, &ChatHandler::HandleWaterwalkCommand, "", NULL },
{ "quit", SEC_CONSOLE, true, &ChatHandler::HandleQuitCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL } { NULL, 0, false, NULL, "", NULL }
}; };

View file

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

View file

@ -110,7 +110,7 @@ Unit(), i_AI(NULL),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0), lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0),
m_lootMoney(0), m_lootRecipient(0), m_lootMoney(0), m_lootRecipient(0),
m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f), 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_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0),
m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false),
m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), 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; && 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) void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, MonsterMovementFlags flags, uint8 type)
{ {
/* uint32 timeElap = getMSTime(); /* uint32 timeElap = getMSTime();

View file

@ -36,102 +36,6 @@ class Quest;
class Player; class Player;
class WorldSession; 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 enum CreatureFlagsExtra
{ {
CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group 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* Name;
char* SubName; char* SubName;
char* IconName; char* IconName;
uint32 GossipMenuId;
uint32 minlevel; uint32 minlevel;
uint32 maxlevel; uint32 maxlevel;
uint32 minhealth; uint32 minhealth;
@ -259,7 +164,7 @@ struct CreatureLocale
std::vector<std::string> SubName; std::vector<std::string> SubName;
}; };
struct NpcOptionLocale struct GossipMenuItemsLocale
{ {
std::vector<std::string> OptionText; std::vector<std::string> OptionText;
std::vector<std::string> BoxText; std::vector<std::string> BoxText;
@ -449,8 +354,6 @@ struct TrainerSpellData
void Clear() { spellList.clear(); } void Clear() { spellList.clear(); }
}; };
typedef std::list<GossipOption> GossipOptionList;
typedef std::map<uint32,time_t> CreatureSpellCooldowns; typedef std::map<uint32,time_t> CreatureSpellCooldowns;
// max different by z coordinate for creature aggro reaction // max different by z coordinate for creature aggro reaction
@ -576,10 +479,6 @@ class MANGOS_DLL_SPEC Creature : public Unit
std::string GetScriptName() const; std::string GetScriptName() const;
uint32 GetScriptId() 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 Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(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); } 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 uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
float m_respawnradius; float m_respawnradius;
bool m_gossipOptionLoaded;
GossipOptionList m_goptions;
bool m_isPet; // set only in Pet::Pet bool m_isPet; // set only in Pet::Pet
bool m_isVehicle; // set only in Vehicle::Vehicle bool m_isVehicle; // set only in Vehicle::Vehicle
bool m_isTotem; // set only in Totem::Totem bool m_isTotem; // set only in Totem::Totem

View file

@ -327,26 +327,26 @@ enum TotemCategoryType
// SummonProperties.dbc, col 1 // SummonProperties.dbc, col 1
enum SummonPropGroup enum SummonPropGroup
{ {
SUMMON_PROP_GROUP_UNKNOWN1 = 0, // 1160 spells in 3.0.3 SUMMON_PROP_GROUP_WILD = 0,
SUMMON_PROP_GROUP_UNKNOWN2 = 1, // 861 spells in 3.0.3 SUMMON_PROP_GROUP_FRIENDLY = 1,
SUMMON_PROP_GROUP_PETS = 2, // 52 spells in 3.0.3, pets mostly SUMMON_PROP_GROUP_PETS = 2,
SUMMON_PROP_GROUP_CONTROLLABLE = 3, // 13 spells in 3.0.3, mostly controllable SUMMON_PROP_GROUP_CONTROLLABLE = 3,
SUMMON_PROP_GROUP_UNKNOWN3 = 4 // 86 spells in 3.0.3, taxi/mounts SUMMON_PROP_GROUP_VEHICLE = 4
}; };
// SummonProperties.dbc, col 3 // SummonProperties.dbc, col 3
enum SummonPropType 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_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_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_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_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_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_DK = 6, // summon DRW/Ghoul, 2 spells in 3.0.3 "%s's Runeblade"
SUMMON_PROP_TYPE_BOMB = 7, // summon bot/bomb, 4 spells in 3.0.3 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 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 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_DRAKE_VEH = 10, // summon drake (vehicle), 3 spells
SUMMON_PROP_TYPE_LIGHTWELL = 11 // summon lightwell, 6 spells in 3.0.3 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 <SpellRuneCostEntry> sSpellRuneCostStore(SpellRuneCostfmt);
DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt); DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt);
DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt); DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
//DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt); DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt); DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
TalentSpellPosMap sTalentSpellPosMap; TalentSpellPosMap sTalentSpellPosMap;
DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt); DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt);
@ -206,7 +206,7 @@ void LoadDBCStores(const std::string& dataPath)
{ {
std::string dbcPath = dataPath+"dbc/"; std::string dbcPath = dataPath+"dbc/";
const uint32 DBCFilesCount = 80; const uint32 DBCFilesCount = 81;
barGoLink bar( DBCFilesCount ); 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,sSpellRuneCostStore, dbcPath,"SpellRuneCost.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellShapeshiftStore, dbcPath,"SpellShapeshiftForm.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,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"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentStore, dbcPath,"Talent.dbc");
// create talent spells set // create talent spells set

View file

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

View file

@ -1540,17 +1540,15 @@ struct StableSlotPricesEntry
uint32 Price; uint32 Price;
}; };
/* unused currently
struct SummonPropertiesEntry struct SummonPropertiesEntry
{ {
uint32 Id; // 0 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 FactionId; // 2, 14 rows > 0
uint32 Type; // 3, enum SummonPropType 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 uint32 Flags; // 5, enum SummonPropFlags
}; };
*/
#define MAX_TALENT_RANK 5 #define MAX_TALENT_RANK 5
#define MAX_PET_TALENT_RANK 3 // use in calculations, expected <= MAX_TALENT_RANK #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 SpellRuneCostfmt[]="niiii";
const char SpellShapeshiftfmt[]="nxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxx"; const char SpellShapeshiftfmt[]="nxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxx";
const char StableSlotPricesfmt[] = "ni"; const char StableSlotPricesfmt[] = "ni";
//const char SummonPropertiesfmt[] = "niiiii"; const char SummonPropertiesfmt[] = "niiiii";
const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxxxx"; const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxxxx";
const char TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiiix"; const char TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiiix";
const char TaxiNodesEntryfmt[]="nifffssssssssssssssssxii"; const char TaxiNodesEntryfmt[]="nifffssssssssssssssssxii";

View file

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

View file

@ -489,6 +489,16 @@ struct GameObjectInfo
default: return 0; 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 // 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() GossipMenu::GossipMenu()
{ {
m_gItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use 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() GossipMenu::~GossipMenu()
@ -44,13 +45,24 @@ void GossipMenu::AddMenuItem(uint8 Icon, const std::string& Message, uint32 dtSe
gItem.m_gMessage = Message; gItem.m_gMessage = Message;
gItem.m_gCoded = Coded; gItem.m_gCoded = Coded;
gItem.m_gSender = dtSender; gItem.m_gSender = dtSender;
gItem.m_gAction = dtAction; gItem.m_gOptionId = dtAction;
gItem.m_gBoxMessage = BoxMessage; gItem.m_gBoxMessage = BoxMessage;
gItem.m_gBoxMoney = BoxMoney; gItem.m_gBoxMoney = BoxMoney;
m_gItems.push_back(gItem); 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) void GossipMenu::AddMenuItem(uint8 Icon, const std::string& Message, bool Coded)
{ {
AddMenuItem( Icon, Message, 0, 0, "", 0, 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; 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 ) bool GossipMenu::MenuItemCoded( unsigned int ItemId )
@ -90,6 +102,8 @@ bool GossipMenu::MenuItemCoded( unsigned int ItemId )
void GossipMenu::ClearMenu() void GossipMenu::ClearMenu()
{ {
m_gItems.clear(); m_gItems.clear();
m_gItemsData.clear();
m_gMenuId = 0;
} }
PlayerMenu::PlayerMenu( WorldSession *session ) : pSession(session) PlayerMenu::PlayerMenu( WorldSession *session ) : pSession(session)
@ -122,13 +136,13 @@ bool PlayerMenu::GossipOptionCoded( unsigned int Selection )
return mGossipMenu.MenuItemCoded( 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 WorldPacket data(SMSG_GOSSIP_MESSAGE, (100)); // guess size
data << uint64(npcGUID); data << uint64(objectGUID);
data << uint32(0); // new 2.4.0 data << uint32(mGossipMenu.GetMenuId()); // new 2.4.0
data << uint32( TitleTextId ); data << uint32(TitleTextId);
data << uint32( mGossipMenu.MenuItemCount() ); // max count 0x10 data << uint32(mGossipMenu.MenuItemCount()); // max count 0x10
for (uint32 iI = 0; iI < mGossipMenu.MenuItemCount(); ++iI ) 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 GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough
#define DEFAULT_GOSSIP_MESSAGE 0xffffff #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. //POI icons. Many more exist, list not complete.
enum Poi_Icon enum Poi_Icon
{ {
@ -80,13 +119,22 @@ struct GossipMenuItem
bool m_gCoded; bool m_gCoded;
std::string m_gMessage; std::string m_gMessage;
uint32 m_gSender; uint32 m_gSender;
uint32 m_gAction; uint32 m_gOptionId;
std::string m_gBoxMessage; std::string m_gBoxMessage;
uint32 m_gBoxMoney; uint32 m_gBoxMoney;
}; };
typedef std::vector<GossipMenuItem> GossipMenuItemList; 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 struct QuestMenuItem
{ {
uint32 m_qId; 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, bool Coded = false);
void AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, 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 unsigned int MenuItemCount() const
{ {
return m_gItems.size(); return m_gItems.size();
@ -123,6 +176,11 @@ class MANGOS_DLL_SPEC GossipMenu
return m_gItems[ Id ]; return m_gItems[ Id ];
} }
GossipMenuItemData const& GetItemData(unsigned int indexId)
{
return m_gItemsData[indexId];
}
uint32 MenuItemSender( unsigned int ItemId ); uint32 MenuItemSender( unsigned int ItemId );
uint32 MenuItemAction( unsigned int ItemId ); uint32 MenuItemAction( unsigned int ItemId );
bool MenuItemCoded( unsigned int ItemId ); bool MenuItemCoded( unsigned int ItemId );
@ -130,7 +188,10 @@ class MANGOS_DLL_SPEC GossipMenu
void ClearMenu(); void ClearMenu();
protected: protected:
GossipMenuItemList m_gItems; GossipMenuItemList m_gItems;
GossipMenuItemDataList m_gItemsData;
uint32 m_gMenuId;
}; };
class QuestMenu class QuestMenu

View file

@ -780,7 +780,8 @@ enum MangosStrings
LANG_ACCOUNT_LIST_BAR = 1012, LANG_ACCOUNT_LIST_BAR = 1012,
LANG_ACCOUNT_LIST_LINE = 1013, LANG_ACCOUNT_LIST_LINE = 1013,
LANG_ACCOUNT_LIST_EMPTY = 1014, 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) // Level 3 (continue)
LANG_ACCOUNT_SETADDON = 1100, LANG_ACCOUNT_SETADDON = 1100,

View file

@ -102,7 +102,6 @@ bool ChatHandler::HandleReloadAllLootCommand(const char*)
bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/) bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/)
{ {
HandleReloadNpcGossipCommand("a"); HandleReloadNpcGossipCommand("a");
HandleReloadNpcOptionCommand("a");
HandleReloadNpcTrainerCommand("a"); HandleReloadNpcTrainerCommand("a");
HandleReloadNpcVendorCommand("a"); HandleReloadNpcVendorCommand("a");
HandleReloadPointsOfInterestCommand("a"); HandleReloadPointsOfInterestCommand("a");
@ -252,6 +251,22 @@ bool ChatHandler::HandleReloadCreatureQuestInvRelationsCommand(const char*)
return true; 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*) bool ChatHandler::HandleReloadGOQuestRelationsCommand(const char*)
{ {
sLog.outString( "Loading Quests Relations... (`gameobject_questrelation`)" ); sLog.outString( "Loading Quests Relations... (`gameobject_questrelation`)" );
@ -404,14 +419,6 @@ bool ChatHandler::HandleReloadMangosStringCommand(const char*)
return true; 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*) bool ChatHandler::HandleReloadNpcGossipCommand(const char*)
{ {
sLog.outString( "Re-Loading `npc_gossip` Table!" ); 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) for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
{ {
Player* plr = itr->getSource(); 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 // possible errors in the coordinate validity check
if(!MapManager::IsValidMapCoord(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation)) 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); sLog.outError("WorldSession::HandleMoveWorldportAckOpcode: player %s (%d) was teleported far to a not valid location. (map:%u, x:%f, y:%f, "
// stop teleportation else we would try this again in the beginning of WorldSession::LogoutPlayer... "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); GetPlayer()->SetSemaphoreTeleportFar(false);
// player don't gets saved - so his coords will stay at the point where // and teleport the player to a valid place
// he was last saved GetPlayer()->TeleportToHomebind();
LogoutPlayer(false);
return; return;
} }
@ -81,14 +81,10 @@ void WorldSession::HandleMoveWorldportAckOpcode()
//if player wasn't added to map, reset his map pointer! //if player wasn't added to map, reset his map pointer!
GetPlayer()->ResetMap(); 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 // teleport the player home
if(!GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation())) GetPlayer()->TeleportToHomebind();
{
// 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);
}
return; return;
} }
@ -242,7 +238,6 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
ReadMovementInfo(recv_data, &movementInfo); ReadMovementInfo(recv_data, &movementInfo);
/*----------------*/ /*----------------*/
recv_data.rpos(recv_data.wpos()); // prevent warnings spam
if (!MaNGOS::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) if (!MaNGOS::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o))
{ {
recv_data.rpos(recv_data.wpos()); // prevent warnings spam 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)) if (!Script->GossipHello(_player, pCreature))
{ {
_player->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID()); _player->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID());
_player->PrepareGossipMenu(pCreature); _player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId);
_player->SendPreparedGossip(pCreature); _player->SendPreparedGossip(pCreature);
} }
} }
@ -286,41 +286,58 @@ void WorldSession::HandleGossipSelectOptionOpcode( WorldPacket & recv_data )
{ {
sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION"); sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION");
uint32 option; uint32 gossipListId;
uint32 menuId; uint32 menuId;
uint64 guid; uint64 guid;
std::string code = ""; 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"); sLog.outBasic("reading string");
recv_data >> code; recv_data >> code;
sLog.outBasic("string read: %s", code.c_str()); 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 // remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); 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())) Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
_player->OnGossipSelect(pCreature, option);
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))) GameObject *pGo = GetPlayer()->GetGameObjectIfCanInteractWith(guid);
_player->OnGossipSelect(pCreature, option);
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 bindspell = 3286;
uint32 zone_id = _player->GetZoneId(); uint32 zone_id = _player->GetZoneId();
// update sql homebind _player->SetHomebindToCurrentPos();
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();
// send spell for bind 3286 bind magic // send spell for bind 3286 bind magic
npc->CastSpell(_player, bindspell, true); npc->CastSpell(_player, bindspell, true);

View file

@ -43,6 +43,7 @@
#include "SpellAuras.h" #include "SpellAuras.h"
#include "Util.h" #include "Util.h"
#include "WaypointManager.h" #include "WaypointManager.h"
#include "GossipDef.h"
INSTANTIATE_SINGLETON_1(ObjectMgr); INSTANTIATE_SINGLETON_1(ObjectMgr);
@ -51,6 +52,7 @@ ScriptMapMap sQuestStartScripts;
ScriptMapMap sSpellScripts; ScriptMapMap sSpellScripts;
ScriptMapMap sGameObjectScripts; ScriptMapMap sGameObjectScripts;
ScriptMapMap sEventScripts; ScriptMapMap sEventScripts;
ScriptMapMap sGossipScripts;
bool normalizePlayerName(std::string& name) bool normalizePlayerName(std::string& name)
{ {
@ -338,16 +340,16 @@ void ObjectMgr::LoadCreatureLocales()
sLog.outString( ">> Loaded %lu creature locale strings", (unsigned long)mCreatureLocaleMap.size() ); 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_loc1,box_text_loc1,option_text_loc2,box_text_loc2,"
"option_text_loc3,box_text_loc3,option_text_loc4,box_text_loc4," "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_loc5,box_text_loc5,option_text_loc6,box_text_loc6,"
"option_text_loc7,box_text_loc7,option_text_loc8,box_text_loc8 " "option_text_loc7,box_text_loc7,option_text_loc8,box_text_loc8 "
"FROM locales_npc_option"); "FROM locales_gossip_menu_option");
if(!result) if(!result)
{ {
@ -356,7 +358,7 @@ void ObjectMgr::LoadNpcOptionLocales()
bar.step(); bar.step();
sLog.outString(); 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; return;
} }
@ -367,13 +369,14 @@ void ObjectMgr::LoadNpcOptionLocales()
Field *fields = result->Fetch(); Field *fields = result->Fetch();
bar.step(); 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) 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()) if(!str.empty())
{ {
int idx = GetOrNewIndexForLocale(LocaleConstant(i)); int idx = GetOrNewIndexForLocale(LocaleConstant(i));
@ -385,7 +388,7 @@ void ObjectMgr::LoadNpcOptionLocales()
data.OptionText[idx] = str; data.OptionText[idx] = str;
} }
} }
str = fields[1+2*(i-1)+1].GetCppString(); str = fields[2+2*(i-1)+1].GetCppString();
if(!str.empty()) if(!str.empty())
{ {
int idx = GetOrNewIndexForLocale(LocaleConstant(i)); int idx = GetOrNewIndexForLocale(LocaleConstant(i));
@ -403,7 +406,7 @@ void ObjectMgr::LoadNpcOptionLocales()
delete result; delete result;
sLog.outString(); 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() 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() void ObjectMgr::LoadItemTexts()
{ {
QueryResult *result = CharacterDatabase.Query("SELECT id, text FROM item_text"); 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); return !player->HasAura(value1, value2);
case CONDITION_ACTIVE_EVENT: case CONDITION_ACTIVE_EVENT:
return sGameEventMgr.IsActiveEvent(value1); 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: default:
return false; return false;
} }
@ -7440,6 +7459,15 @@ bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 val
} }
break; 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: case CONDITION_NONE:
break; break;
} }
@ -7887,23 +7915,21 @@ void ObjectMgr::LoadNpcTextId()
sLog.outString( ">> Loaded %d NpcTextId ", count ); 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( QueryResult* result = WorldDatabase.Query("SELECT entry, text_id, "
// 0 1 2 3 4 5 6 7 8 "cond_1, cond_1_val_1, cond_1_val_2, cond_2, cond_2_val_1, cond_2_val_2 FROM gossip_menu");
"SELECT id,gossip_id,npcflag,icon,action,box_money,coded,option_text,box_text "
"FROM npc_option");
if( !result ) if (!result)
{ {
barGoLink bar( 1 ); barGoLink bar(1);
bar.step(); bar.step();
sLog.outString(); sLog.outString();
sLog.outErrorDb(">> Loaded `npc_option`, table is empty!"); sLog.outErrorDb(">> Loaded gossip_menu, table is empty!");
return; return;
} }
@ -7917,26 +7943,186 @@ void ObjectMgr::LoadNpcOptions()
Field* fields = result->Fetch(); Field* fields = result->Fetch();
GossipOption go; GossipMenus gMenu;
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();
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; ++count;
}
while(result->NextRow());
} while (result->NextRow());
delete result; delete result;
sLog.outString(); 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 ) 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 sSpellScripts;
extern ScriptMapMap sGameObjectScripts; extern ScriptMapMap sGameObjectScripts;
extern ScriptMapMap sEventScripts; extern ScriptMapMap sEventScripts;
extern ScriptMapMap sGossipScripts;
struct SpellClickInfo struct SpellClickInfo
{ {
@ -162,7 +163,7 @@ typedef UNORDERED_MAP<uint32,QuestLocale> QuestLocaleMap;
typedef UNORDERED_MAP<uint32,NpcTextLocale> NpcTextLocaleMap; typedef UNORDERED_MAP<uint32,NpcTextLocale> NpcTextLocaleMap;
typedef UNORDERED_MAP<uint32,PageTextLocale> PageTextLocaleMap; typedef UNORDERED_MAP<uint32,PageTextLocale> PageTextLocaleMap;
typedef UNORDERED_MAP<int32,MangosStringLocale> MangosStringLocaleMap; 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 UNORDERED_MAP<uint32,PointOfInterestLocale> PointOfInterestLocaleMap;
typedef std::multimap<uint32,uint32> QuestRelations; typedef std::multimap<uint32,uint32> QuestRelations;
@ -216,6 +217,38 @@ struct PointOfInterest
std::string icon_name; 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 struct QuestPOIPoint
{ {
int32 x; int32 x;
@ -223,6 +256,16 @@ struct QuestPOIPoint
QuestPOIPoint() : x(0), y(0) {} QuestPOIPoint() : x(0), y(0) {}
QuestPOIPoint(int32 _x, int32 _y) : x(_x), y(_y) {} 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 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_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD commission aura active
CONDITION_NO_AURA = 11, // spell_id effindex CONDITION_NO_AURA = 11, // spell_id effindex
CONDITION_ACTIVE_EVENT = 12, // event_id 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 struct PlayerCondition
{ {
@ -301,7 +345,6 @@ struct PlayerCondition
// NPC gossip text id // NPC gossip text id
typedef UNORDERED_MAP<uint32, uint32> CacheNpcTextIdMap; typedef UNORDERED_MAP<uint32, uint32> CacheNpcTextIdMap;
typedef std::list<GossipOption> CacheNpcOptionList;
typedef UNORDERED_MAP<uint32, VendorItemData> CacheVendorItemMap; typedef UNORDERED_MAP<uint32, VendorItemData> CacheVendorItemMap;
typedef UNORDERED_MAP<uint32, TrainerSpellData> CacheTrainerSpellMap; typedef UNORDERED_MAP<uint32, TrainerSpellData> CacheTrainerSpellMap;
@ -539,6 +582,7 @@ class ObjectMgr
void LoadQuestStartScripts(); void LoadQuestStartScripts();
void LoadEventScripts(); void LoadEventScripts();
void LoadSpellScripts(); void LoadSpellScripts();
void LoadGossipScripts();
bool LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); 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); } bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase,"mangos_string",MIN_MANGOS_STRING_ID,MAX_MANGOS_STRING_ID); }
@ -559,7 +603,7 @@ class ObjectMgr
void LoadQuestLocales(); void LoadQuestLocales();
void LoadNpcTextLocales(); void LoadNpcTextLocales();
void LoadPageTextLocales(); void LoadPageTextLocales();
void LoadNpcOptionLocales(); void LoadGossipMenuItemsLocales();
void LoadPointOfInterestLocales(); void LoadPointOfInterestLocales();
void LoadInstanceTemplate(); void LoadInstanceTemplate();
void LoadMailLevelRewards(); void LoadMailLevelRewards();
@ -592,8 +636,11 @@ class ObjectMgr
void LoadWeatherZoneChances(); void LoadWeatherZoneChances();
void LoadGameTele(); void LoadGameTele();
void LoadNpcOptions();
void LoadNpcTextId(); void LoadNpcTextId();
void LoadGossipMenu();
void LoadGossipMenuItems();
void LoadVendors(); void LoadVendors();
void LoadTrainerSpell(); void LoadTrainerSpell();
@ -704,10 +751,10 @@ class ObjectMgr
if(itr==mPageTextLocaleMap.end()) return NULL; if(itr==mPageTextLocaleMap.end()) return NULL;
return &itr->second; return &itr->second;
} }
NpcOptionLocale const* GetNpcOptionLocale(uint32 entry) const GossipMenuItemsLocale const* GetGossipMenuItemsLocale(uint32 entry) const
{ {
NpcOptionLocaleMap::const_iterator itr = mNpcOptionLocaleMap.find(entry); GossipMenuItemsLocaleMap::const_iterator itr = mGossipMenuItemsLocaleMap.find(entry);
if(itr==mNpcOptionLocaleMap.end()) return NULL; if(itr==mGossipMenuItemsLocaleMap.end()) return NULL;
return &itr->second; return &itr->second;
} }
PointOfInterestLocale const* GetPointOfInterestLocale(uint32 poi_id) const PointOfInterestLocale const* GetPointOfInterestLocale(uint32 poi_id) const
@ -786,8 +833,6 @@ class ObjectMgr
bool AddGameTele(GameTele& data); bool AddGameTele(GameTele& data);
bool DeleteGameTele(const std::string& name); bool DeleteGameTele(const std::string& name);
CacheNpcOptionList const& GetNpcOptions() const { return m_mCacheNpcOptionList; }
uint32 GetNpcGossip(uint32 entry) const uint32 GetNpcGossip(uint32 entry) const
{ {
CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry); 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)); 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: protected:
// first free id for selected id type // first free id for selected id type
@ -876,7 +931,9 @@ class ObjectMgr
RepOnKillMap mRepOnKill; RepOnKillMap mRepOnKill;
PointOfInterestMap mPointsOfInterest; GossipMenusMap m_mGossipMenusMap;
GossipMenuItemsMap m_mGossipMenuItemsMap;
PointOfInterestMap mPointsOfInterest;
QuestPOIMap mQuestPOIMap; QuestPOIMap mQuestPOIMap;
@ -942,7 +999,7 @@ class ObjectMgr
NpcTextLocaleMap mNpcTextLocaleMap; NpcTextLocaleMap mNpcTextLocaleMap;
PageTextLocaleMap mPageTextLocaleMap; PageTextLocaleMap mPageTextLocaleMap;
MangosStringLocaleMap mMangosStringLocaleMap; MangosStringLocaleMap mMangosStringLocaleMap;
NpcOptionLocaleMap mNpcOptionLocaleMap; GossipMenuItemsLocaleMap mGossipMenuItemsLocaleMap;
PointOfInterestLocaleMap mPointOfInterestLocaleMap; PointOfInterestLocaleMap mPointOfInterestLocaleMap;
RespawnTimes mCreatureRespawnTimes; RespawnTimes mCreatureRespawnTimes;
RespawnTimes mGORespawnTimes; RespawnTimes mGORespawnTimes;
@ -951,7 +1008,6 @@ class ObjectMgr
typedef std::vector<PlayerCondition> ConditionStore; typedef std::vector<PlayerCondition> ConditionStore;
ConditionStore mConditions; ConditionStore mConditions;
CacheNpcOptionList m_mCacheNpcOptionList;
CacheNpcTextIdMap m_mCacheNpcTextIdMap; CacheNpcTextIdMap m_mCacheNpcTextIdMap;
CacheVendorItemMap m_mCacheVendorItemMap; CacheVendorItemMap m_mCacheVendorItemMap;
CacheTrainerSpellMap m_mCacheTrainerSpellMap; CacheTrainerSpellMap m_mCacheTrainerSpellMap;

View file

@ -2117,14 +2117,14 @@ Creature* Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask)
return unit; 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; float maxdist;
switch(type) switch(go->GetGoType())
{ {
// TODO: find out how the client calculates the maximal usage distance to spellless working // 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 // 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; break;
} }
if (go->IsWithinDistInMap(this, maxdist)) if (go->IsWithinDistInMap(this, maxdist) && go->isSpawned())
return go; 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)); go->GetGUIDLow(), GetName(), GetGUIDLow(), go->GetDistance(this));
} }
} }
@ -12178,126 +12178,151 @@ void Player::SendNewItem(Item *item, uint32 count, bool received, bool created,
/*** GOSSIP SYSTEM ***/ /*** GOSSIP SYSTEM ***/
/*********************************************************/ /*********************************************************/
void Player::PrepareGossipMenu(WorldObject *pSource, uint32 gossipid) void Player::PrepareGossipMenu(WorldObject *pSource, uint32 menuId)
{ {
PlayerMenu* pMenu = PlayerTalkClass; PlayerMenu* pMenu = PlayerTalkClass;
pMenu->ClearMenus(); pMenu->ClearMenus();
if (pSource->GetTypeId() != TYPEID_UNIT) pMenu->GetGossipMenu().SetMenuId(menuId);
return;
Creature *pCreature = (Creature*)pSource; GossipMenuItemsMapBounds pMenuItemBounds = sObjectMgr.GetGossipMenuItemsMapBounds(menuId);
// lazy loading single time at use // if default menuId and no menu options exist for this, use options from default options
pCreature->LoadGossipOptions(); if (pMenuItemBounds.first == pMenuItemBounds.second && menuId == GetDefaultGossipMenuForSource(pSource))
pMenuItemBounds = sObjectMgr.GetGossipMenuItemsMapBounds(0);
GossipOptionList &iOptList = pCreature->GetGossipOptionList(); for(GossipMenuItemsMap::const_iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr)
for(GossipOptionList::iterator i = iOptList.begin( ); i != iOptList.end( ); ++i)
{ {
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); case GOSSIP_OPTION_QUESTGIVER:
PrepareQuestMenu(pSource->GetGUID());
GossipText const* gossiptext = sObjectMgr.GetGossipText(textid); bCanTalk = false;
break;
if (!gossiptext) case GOSSIP_OPTION_ARMORER:
cantalking = false; bCanTalk = false; // added in special mode
} break;
else case GOSSIP_OPTION_SPIRITHEALER:
{ if (!isDead())
switch(gso->Action) 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()); PrepareQuestMenu(pSource->GetGUID());
//if (pm->GetQuestMenu()->MenuItemCount() == 0) bCanTalk = false;
cantalking = false; break;
//pm->GetQuestMenu()->ClearMenu(); case GOSSIP_OPTION_GOSSIP:
break; if (pGo->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER && pGo->GetGoType() != GAMEOBJECT_TYPE_GOOBER)
case GOSSIP_OPTION_ARMORER: bCanTalk = false;
cantalking = false; // added in special mode break;
break; default:
case GOSSIP_OPTION_SPIRITHEALER: bCanTalk = false;
if (!isDead()) break;
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;
}
} }
}
//note for future dev: should have database fields for BoxMessage & BoxMoney if (bCanTalk)
if (!gso->OptionText.empty() && cantalking) {
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; uint32 idxEntry = MAKE_PAIR32(menuId, itr->second.id);
std::string BoxText = gso->BoxText;
int loc_idx = GetSession()->GetSessionDbLocaleIndex();
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())
{ strOptionText = no->OptionText[loc_idx];
if (no->OptionText.size() > (size_t)loc_idx && !no->OptionText[loc_idx].empty())
OptionText = no->OptionText[loc_idx];
if (no->BoxText.size() > (size_t)loc_idx && !no->BoxText[loc_idx].empty()) if (no->BoxText.size() > (size_t)loc_idx && !no->BoxText[loc_idx].empty())
BoxText = no->BoxText[loc_idx]; 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 ;-) // 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 (pMenu->Empty())
{ {
if (pCreature->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_TRAINER)) 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 // output error message if need
pCreature->isCanInteractWithBattleMaster(this, true); pCreature->isCanInteractWithBattleMaster(this, true);
} }
} }*/
} }
void Player::SendPreparedGossip(WorldObject *pSource) void Player::SendPreparedGossip(WorldObject *pSource)
{ {
if (!pSource || pSource->GetTypeId() != TYPEID_UNIT) if (!pSource)
return; return;
// in case no gossip flag and quest menu not empty, open quest menu (client expect gossip menu with this flag) if (pSource->GetTypeId() == TYPEID_UNIT)
if (!((Creature*)pSource)->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_GOSSIP) && !PlayerTalkClass->GetQuestMenu().Empty())
{ {
SendPreparedQuest(pSource->GetGUID()); // in case no gossip flag and quest menu not empty, open quest menu (client expect gossip menu with this flag)
return; 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 // in case non empty gossip menu (that not included quests list size) show it
// (quest entries from quest menu will be included in list) // (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(); GossipMenu& gossipmenu = PlayerTalkClass->GetGossipMenu();
if (option >= gossipmenu.MenuItemCount()) if (gossipListId >= gossipmenu.MenuItemCount())
return; return;
uint32 action = gossipmenu.GetItem(option).m_gAction; // if not same, then something funky is going on
uint32 zoneid = GetZoneId(); if (menuId != gossipmenu.GetMenuId())
return;
uint32 gossipOptionId = gossipmenu.GetItem(gossipListId).m_gOptionId;
uint64 guid = pSource->GetGUID(); uint64 guid = pSource->GetGUID();
GossipOption const *gossip = GetGossipOption(pSource, action); if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
if (!gossip)
{ {
zoneid = 0; if (gossipOptionId > GOSSIP_OPTION_QUESTGIVER)
gossip = GetGossipOption(pSource, action); {
sLog.outError("Player guid %u request invalid gossip option for GameObject entry %u", GetGUIDLow(), pSource->GetEntry());
if (!gossip)
return; return;
}
} }
switch(gossip->Action) GossipMenuItemData pMenuData = gossipmenu.GetItemData(gossipListId);
switch(gossipOptionId)
{ {
case GOSSIP_OPTION_GOSSIP: 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) if (pMenuData.m_gAction_poi)
textid = GetGossipTextId(pSource); 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; break;
} }
case GOSSIP_OPTION_SPIRITHEALER: case GOSSIP_OPTION_SPIRITHEALER:
@ -12413,9 +12469,7 @@ void Player::OnGossipSelect(WorldObject* pSource, uint32 option)
GetSession()->SendAuctionHello(guid, ((Creature*)pSource)); GetSession()->SendAuctionHello(guid, ((Creature*)pSource));
break; break;
case GOSSIP_OPTION_SPIRITGUIDE: case GOSSIP_OPTION_SPIRITGUIDE:
case GOSSIP_GUARD_SPELLTRAINER: PrepareGossipMenu(pSource);
case GOSSIP_GUARD_SKILLTRAINER:
PrepareGossipMenu(pSource, gossip->Id);
SendPreparedGossip(pSource); SendPreparedGossip(pSource);
break; break;
case GOSSIP_OPTION_BATTLEFIELD: case GOSSIP_OPTION_BATTLEFIELD:
@ -12431,59 +12485,13 @@ void Player::OnGossipSelect(WorldObject* pSource, uint32 option)
GetSession()->SendBattlegGroundList(guid, bgTypeId); GetSession()->SendBattlegGroundList(guid, bgTypeId);
break; 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) uint32 Player::GetGossipTextId(WorldObject *pSource)
{ {
if (!pSource || pSource->GetTypeId() != TYPEID_UNIT || !((Creature*)pSource)->GetDBTableGUIDLow()) if (!pSource || pSource->GetTypeId() != TYPEID_UNIT || !((Creature*)pSource)->GetDBTableGUIDLow())
return DEFAULT_GOSSIP_MESSAGE; return 0;
if (uint32 pos = sObjectMgr.GetNpcGossip(((Creature*)pSource)->GetDBTableGUIDLow())) if (uint32 pos = sObjectMgr.GetNpcGossip(((Creature*)pSource)->GetDBTableGUIDLow()))
return pos; return pos;
@ -12491,19 +12499,32 @@ uint32 Player::GetGossipTextId(WorldObject *pSource)
return DEFAULT_GOSSIP_MESSAGE; 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) if (pSource->GetTypeId() == TYPEID_UNIT)
{ return ((Creature*)pSource)->GetCreatureInfo()->GossipMenuId;
GossipOptionList &iOptlist = ((Creature*)pSource)->GetGossipOptionList(); else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
return((GameObject*)pSource)->GetGOInfo()->GetGossipMenuId();
for(GossipOptionList::const_iterator i = iOptlist.begin( ); i != iOptlist.end( ); ++i) return 0;
{
if (i->Action == id)
return &*i;
}
}
return NULL;
} }
/*********************************************************/ /*********************************************************/
@ -19119,7 +19140,7 @@ BGQueueIdBasedOnLevel Player::GetBattleGroundQueueIdFromLevel() const
uint32 queue_id = ( getLevel() / 10) - 1; uint32 queue_id = ( getLevel() / 10) - 1;
if( queue_id >= MAX_BATTLEGROUND_QUEUES ) 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 QUEUE_ID_MAX_LEVEL_80;
} }
return BGQueueIdBasedOnLevel(queue_id); return BGQueueIdBasedOnLevel(queue_id);
@ -21229,3 +21250,35 @@ void Player::SendDuelCountdown(uint32 counter)
data << uint32(counter); // seconds data << uint32(counter); // seconds
GetSession()->SendPacket(&data); 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); void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time);
Creature* GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask); 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(); void UpdateVisibilityForPlayer();
@ -1300,14 +1300,13 @@ class MANGOS_DLL_SPEC Player : public Unit
/*** GOSSIP SYSTEM ***/ /*** GOSSIP SYSTEM ***/
/*********************************************************/ /*********************************************************/
void PrepareGossipMenu(WorldObject *pSource, uint32 gossipid = 0); void PrepareGossipMenu(WorldObject *pSource, uint32 menuId = 0);
void SendPreparedGossip(WorldObject *pSource); void SendPreparedGossip(WorldObject *pSource);
void OnGossipSelect(WorldObject *pSource, uint32 option); void OnGossipSelect(WorldObject *pSource, uint32 gossipListId, uint32 menuId);
void OnPoiSelect(WorldObject *pSource, GossipOption const *gossip);
uint32 GetGossipTextId(uint32 action, uint32 zoneid); uint32 GetGossipTextId(uint32 menuId);
uint32 GetGossipTextId(WorldObject *pSource); uint32 GetGossipTextId(WorldObject *pSource);
GossipOption const* GetGossipOption(WorldObject *pSource, uint32 id) const; uint32 GetDefaultGossipMenuForSource(WorldObject *pSource);
/*********************************************************/ /*********************************************************/
/*** QUEST SYSTEM ***/ /*** QUEST SYSTEM ***/
@ -1556,6 +1555,7 @@ class MANGOS_DLL_SPEC Player : public Unit
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const; TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;
bool IsSpellFitByClassAndRace( uint32 spell_id ) const; bool IsSpellFitByClassAndRace( uint32 spell_id ) const;
bool IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const; bool IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const;
bool IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const;
void SendProficiency(uint8 pr1, uint32 pr2); void SendProficiency(uint8 pr1, uint32 pr2);
void SendInitialSpells(); void SendInitialSpells();
@ -2172,13 +2172,9 @@ class MANGOS_DLL_SPEC Player : public Unit
float m_recallO; float m_recallO;
void SaveRecallPosition(); void SaveRecallPosition();
// Homebind coordinates void SetHomebindToCurrentPos();
uint32 m_homebindMapId;
uint16 m_homebindZoneId;
float m_homebindX;
float m_homebindY;
float m_homebindZ;
void RelocateToHomebind() { SetLocationMapId(m_homebindMapId); Relocate(m_homebindX,m_homebindY,m_homebindZ); } 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 // currently visible objects at player client
typedef std::set<uint64> ClientGUIDs; typedef std::set<uint64> ClientGUIDs;
@ -2537,6 +2533,13 @@ class MANGOS_DLL_SPEC Player : public Unit
GridReference<Player> m_gridRef; GridReference<Player> m_gridRef;
MapReference m_mapRef; MapReference m_mapRef;
// Homebind coordinates
uint32 m_homebindMapId;
uint16 m_homebindZoneId;
float m_homebindX;
float m_homebindY;
float m_homebindZ;
uint32 m_lastFallTime; uint32 m_lastFallTime;
float m_lastFallZ; float m_lastFallZ;

View file

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

View file

@ -2442,38 +2442,6 @@ enum DiminishingGroup
DIMINISHING_LIMITONLY 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 enum ResponseCodes
{ {
RESPONSE_SUCCESS = 0x00, RESPONSE_SUCCESS = 0x00,

View file

@ -691,8 +691,8 @@ void Spell::prepareDataForTriggerSystem()
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000800000000060)) if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000800000000060))
m_canTrigger = true; m_canTrigger = true;
break; break;
case SPELLFAMILY_PRIEST: // For Penance heal/damage triggers need do it case SPELLFAMILY_PRIEST: // For Penance,Mind Sear,Mind Flay heal/damage triggers need do it
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0001800000000000)) if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0001800000800000) || (m_spellInfo->SpellFamilyFlags2 & 0x00000040))
m_canTrigger = true; m_canTrigger = true;
break; break;
case SPELLFAMILY_ROGUE: // For poisons need do it case SPELLFAMILY_ROGUE: // For poisons need do it
@ -1685,8 +1685,16 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap)
} }
break; break;
case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: 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 // 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(); Unit* target = m_targets.getUnitTarget();
if(!target) if(!target)
@ -2217,13 +2225,6 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap)
} }
break; break;
case SPELL_EFFECT_SUMMON: 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); TagUnitMap.push_back(m_caster);
break; break;
case SPELL_EFFECT_SUMMON_CHANGE_ITEM: case SPELL_EFFECT_SUMMON_CHANGE_ITEM:
@ -4299,6 +4300,34 @@ SpellCastResult Spell::CheckCast(bool strict)
// for effects of spells that have only one target // for effects of spells that have only one target
switch(m_spellInfo->Effect[i]) 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: case SPELL_EFFECT_DUMMY:
{ {
if(m_spellInfo->SpellIconID == 1648) // Execute if(m_spellInfo->SpellIconID == 1648) // Execute
@ -4567,24 +4596,17 @@ SpellCastResult Spell::CheckCast(bool strict)
// This is generic summon effect // This is generic summon effect
case SPELL_EFFECT_SUMMON: case SPELL_EFFECT_SUMMON:
{ {
switch(m_spellInfo->EffectMiscValueB[i]) if(SummonPropertiesEntry const *summon_prop = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]))
{ {
case SUMMON_TYPE_POSESSED: if(summon_prop->Group == SUMMON_PROP_GROUP_PETS)
case SUMMON_TYPE_POSESSED2:
case SUMMON_TYPE_DEMON:
case SUMMON_TYPE_SUMMON:
case SUMMON_TYPE_ELEMENTAL:
case SUMMON_TYPE_INFERNO:
{ {
if(m_caster->GetPetGUID()) if(m_caster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON; return SPELL_FAILED_ALREADY_HAVE_SUMMON;
if(m_caster->GetCharmGUID()) if(m_caster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM; return SPELL_FAILED_ALREADY_HAVE_CHARM;
break;
} }
} }
break;
} }
// Not used for summon? // Not used for summon?
case SPELL_EFFECT_SUMMON_PHANTASM: case SPELL_EFFECT_SUMMON_PHANTASM:
@ -4950,6 +4972,18 @@ SpellCastResult Spell::CheckCasterAuras() const
prevented_reason = SPELL_FAILED_SILENCED; prevented_reason = SPELL_FAILED_SILENCED;
else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY) else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY)
prevented_reason = SPELL_FAILED_PACIFIED; 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 // Attr must make flag drop spell totally immune from all effects
if (prevented_reason != SPELL_CAST_OK) if (prevented_reason != SPELL_CAST_OK)
@ -5704,7 +5738,7 @@ void Spell::UpdatePointers()
m_targets.Update(m_caster); m_targets.Update(m_caster);
} }
bool Spell::IsAffectedByAura(Aura *aura) bool Spell::IsAffectedByAura(Aura *aura) const
{ {
return sSpellMgr.IsAffectedByMod(m_spellInfo, aura->getAuraSpellMod()); return sSpellMgr.IsAffectedByMod(m_spellInfo, aura->getAuraSpellMod());
} }

View file

@ -248,8 +248,8 @@ class Spell
void EffectDualWield(uint32 i); void EffectDualWield(uint32 i);
void EffectPickPocket(uint32 i); void EffectPickPocket(uint32 i);
void EffectAddFarsight(uint32 i); void EffectAddFarsight(uint32 i);
void EffectSummonWild(uint32 i); void EffectSummonWild(uint32 i, uint32 forceFaction = 0);
void EffectSummonGuardian(uint32 i); void EffectSummonGuardian(uint32 i, uint32 forceFaction = 0);
void EffectHealMechanical(uint32 i); void EffectHealMechanical(uint32 i);
void EffectJump(uint32 i); void EffectJump(uint32 i);
void EffectTeleUnitsFaceCaster(uint32 i); void EffectTeleUnitsFaceCaster(uint32 i);
@ -277,7 +277,7 @@ class Spell
void EffectSummonPlayer(uint32 i); void EffectSummonPlayer(uint32 i);
void EffectActivateObject(uint32 i); void EffectActivateObject(uint32 i);
void EffectApplyGlyph(uint32 i); void EffectApplyGlyph(uint32 i);
void EffectSummonTotem(uint32 i); void EffectSummonTotem(uint32 i, uint8 slot = 0);
void EffectEnchantHeldItem(uint32 i); void EffectEnchantHeldItem(uint32 i);
void EffectSummonObject(uint32 i); void EffectSummonObject(uint32 i);
void EffectResurrect(uint32 i); void EffectResurrect(uint32 i);
@ -299,7 +299,7 @@ class Spell
void EffectMilling(uint32 i); void EffectMilling(uint32 i);
void EffectRenamePet(uint32 i); void EffectRenamePet(uint32 i);
void EffectSendTaxi(uint32 i); void EffectSendTaxi(uint32 i);
void EffectSummonCritter(uint32 i); void EffectSummonCritter(uint32 i, uint32 forceFaction = 0);
void EffectKnockBack(uint32 i); void EffectKnockBack(uint32 i);
void EffectPlayerPull(uint32 i); void EffectPlayerPull(uint32 i);
void EffectDispelMechanic(uint32 i); void EffectDispelMechanic(uint32 i);
@ -314,7 +314,6 @@ class Spell
void EffectAddExtraAttacks(uint32 i); void EffectAddExtraAttacks(uint32 i);
void EffectSpiritHeal(uint32 i); void EffectSpiritHeal(uint32 i);
void EffectSkinPlayerCorpse(uint32 i); void EffectSkinPlayerCorpse(uint32 i);
void EffectSummonDemon(uint32 i);
void EffectStealBeneficialBuff(uint32 i); void EffectStealBeneficialBuff(uint32 i);
void EffectUnlearnSpecialization(uint32 i); void EffectUnlearnSpecialization(uint32 i);
void EffectHealPct(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) 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; 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_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_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_MOD_DAMAGE_FROM_CASTER = 271,
SPELL_AURA_272 = 272, SPELL_AURA_MAELSTROM_WEAPON = 272,
SPELL_AURA_X_RAY = 273, SPELL_AURA_X_RAY = 273,
SPELL_AURA_274 = 274, SPELL_AURA_274 = 274,
SPELL_AURA_MOD_IGNORE_SHAPESHIFT = 275, SPELL_AURA_MOD_IGNORE_SHAPESHIFT = 275,
@ -347,7 +347,7 @@ enum AuraType
SPELL_AURA_302 = 302, SPELL_AURA_302 = 302,
SPELL_AURA_303 = 303, SPELL_AURA_303 = 303,
SPELL_AURA_304 = 304, SPELL_AURA_304 = 304,
SPELL_AURA_305 = 305, SPELL_AURA_MOD_MINIMUM_SPEED = 305,
SPELL_AURA_306 = 306, SPELL_AURA_306 = 306,
TOTAL_AURAS = 307 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::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::HandleNULL, //243 faction reaction override spells
&Aura::HandleComprehendLanguage, //244 SPELL_AURA_COMPREHEND_LANGUAGE &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::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::HandleNULL, //247 target to become a clone of the caster
&Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &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::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::HandlePhase, //261 SPELL_AURA_PHASE undetectable invisibility? implemented in Unit::isVisibleForOrDetect
&Aura::HandleNULL, //262 ignore combat/aura state? &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, //264 unused (3.0.8a-3.2.2a)
&Aura::HandleUnused, //265 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) &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::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::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::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::HandleNoImmediateEffect, //273 SPELL_AURA_X_RAY (client side implementation)
&Aura::HandleNULL, //274 proc free shot? &Aura::HandleNULL, //274 proc free shot?
&Aura::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select &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::HandleUnused, //302 unused (3.2.2a)
&Aura::HandleNULL, //303 17 spells &Aura::HandleNULL, //303 17 spells
&Aura::HandleNULL, //304 2 spells (alcohol effect?) &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 &Aura::HandleNULL //306 1 spell
}; };
@ -1333,26 +1333,42 @@ bool Aura::isAffectedOnSpell(SpellEntry const *spell) const
void Aura::ReapplyAffectedPassiveAuras( Unit* target ) 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) for(Unit::AuraMap::const_iterator itr = target->GetAuras().begin(); itr != target->GetAuras().end(); ++itr)
{ {
// permanent passive // permanent passive or permanent area aura
if (itr->second->IsPassive() && itr->second->IsPermanent() && if (itr->second->IsPermanent() && (itr->second->IsPassive() || itr->second->IsAreaAura()) &&
// non deleted and not same aura (any with same spell id) // non deleted and not same aura (any with same spell id)
!itr->second->IsDeleted() && itr->second->GetId() != GetId() && !itr->second->IsDeleted() && itr->second->GetId() != GetId() &&
// only applied by self and affected by aura // and affected by aura
itr->second->GetCasterGUID() == target->GetGUID() && isAffectedOnSpell(itr->second->GetSpellProto())) 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->RemoveAurasDueToSpell(*set_itr);
target->CastSpell(m_target, *set_itr, true); 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->mask = (uint64)ptr[0] | (uint64)ptr[1]<<32;
mod->mask2= (uint64)ptr[2]; 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; m_spellmod = mod;
} }
@ -1412,14 +1431,22 @@ void Aura::HandleAddModifier(bool apply, bool Real)
// reapply talents to own passive persistent auras // reapply talents to own passive persistent auras
ReapplyAffectedPassiveAuras(m_target); 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()) if(Pet* pet = m_target->GetPet())
ReapplyAffectedPassiveAuras(pet); ReapplyAffectedPassiveAuras(pet);
// re-apply talents/passives/area auras applied to totems (it affected by player spellmods)
for(int i = 0; i < MAX_TOTEM; ++i) for(int i = 0; i < MAX_TOTEM; ++i)
if(m_target->m_TotemSlot[i]) if(m_target->m_TotemSlot[i])
if(Creature* totem = m_target->GetMap()->GetCreature(m_target->m_TotemSlot[i])) if(Creature* totem = m_target->GetMap()->GetCreature(m_target->m_TotemSlot[i]))
ReapplyAffectedPassiveAuras(totem); 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*/) void Aura::HandleAddTargetTrigger(bool apply, bool /*Real*/)
{ {
@ -2212,56 +2239,107 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
// AT APPLY // AT APPLY
if(apply) if(apply)
{ {
switch(GetId()) switch(m_spellProto->SpellFamilyName)
{ {
case 1515: // Tame beast case SPELLFAMILY_GENERIC:
// FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness switch(GetId())
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 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
case GENDER_FEMALE: if (m_target->CanHaveThreatList())
caster->CastSpell(m_target, 46356, true, NULL, this); if (Unit* caster = GetCaster())
break; m_target->AddThreat(caster, 10.0f, false, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
case GENDER_MALE: return;
caster->CastSpell(m_target, 46355, true, NULL, this); case 13139: // net-o-matic
break; // root to self part of (root_target->charge->root_self sequence
default: if (Unit* caster = GetCaster())
break; 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; break;
case 46699: // Requires No Ammo case SPELLFAMILY_WARRIOR:
if(m_target->GetTypeId() == TYPEID_PLAYER) // Overpower
((Player*)m_target)->RemoveAmmo(); // not use ammo and not allow use if(m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000004))
return; {
} // Must be casting target
if (!m_target->IsNonMeleeSpellCasted(false))
return;
// Earth Shield Unit* caster = GetCaster();
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN && (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x40000000000))) if (!caster)
{ return;
// prevent double apply bonuses
if(m_target->GetTypeId() != TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading()) Unit::AuraList const& modifierAuras = caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
if (Unit* caster = GetCaster()) for(Unit::AuraList::const_iterator itr = modifierAuras.begin(); itr != modifierAuras.end(); ++itr)
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE); {
return; // 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 // AT REMOVE
@ -2668,6 +2746,18 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
case SPELLFAMILY_HUNTER: case SPELLFAMILY_HUNTER:
break; break;
case SPELLFAMILY_PALADIN: 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; break;
case SPELLFAMILY_SHAMAN: case SPELLFAMILY_SHAMAN:
{ {
@ -3148,6 +3238,22 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
} }
// Murloc costume // Murloc costume
case 42365: m_target->SetDisplayId(21723); break; 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; default: break;
} }
} }
@ -5662,6 +5768,8 @@ void Aura::HandleShapeshiftBoosts(bool apply)
((Player*)m_target)->RemoveSpellCooldown(49868); ((Player*)m_target)->RemoveSpellCooldown(49868);
break; break;
case FORM_GHOSTWOLF: case FORM_GHOSTWOLF:
spellId1 = 67116;
break;
case FORM_AMBIENT: case FORM_AMBIENT:
case FORM_GHOUL: case FORM_GHOUL:
case FORM_STEALTH: case FORM_STEALTH:
@ -5789,6 +5897,7 @@ void Aura::HandleShapeshiftBoosts(bool apply)
void Aura::HandleSpellSpecificBoosts(bool apply) void Aura::HandleSpellSpecificBoosts(bool apply)
{ {
bool cast_at_remove = false; // if spell must be casted at aura remove
uint32 spellId1 = 0; uint32 spellId1 = 0;
uint32 spellId2 = 0; uint32 spellId2 = 0;
uint32 spellId3 = 0; uint32 spellId3 = 0;
@ -5796,6 +5905,33 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
switch(GetSpellProto()->SpellFamilyName) 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: case SPELLFAMILY_WARRIOR:
{ {
if(!apply) if(!apply)
@ -5817,14 +5953,72 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
} }
break; 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: 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()) 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) // Abolish Disease (remove 1 more poison effect with Body and Soul)
case 552: case 552:
{ {
@ -5851,10 +6045,16 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
spellId1 = 64134; // Body and Soul (periodic dispel effect) spellId1 = 64134; // Body and Soul (periodic dispel effect)
break; break;
} }
// Dispersion mana reg and immunity
case 47585:
spellId1 = 60069; // Dispersion
spellId2 = 63230; // Dispersion
break;
default: default:
return; return;
} }
break; break;
}
case SPELLFAMILY_ROGUE: case SPELLFAMILY_ROGUE:
// Sprint (skip non player casted spells by category) // Sprint (skip non player casted spells by category)
if (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000000040) && GetSpellProto()->Category == 44) 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 // prevent aura deletion, specially in multi-boost case
SetInUse(true); SetInUse(true);
if (apply) if (apply || cast_at_remove)
{ {
if (spellId1) if (spellId1)
m_target->CastSpell(m_target, spellId1, true, NULL, this); m_target->CastSpell(m_target, spellId1, true, NULL, this);
@ -6259,47 +6459,10 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real)
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto()); DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
m_modifier.m_amount += (int32)DoneActualBenefit; 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 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 && if (caster &&
// Power Word: Shield // Power Word: Shield
m_spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellProto->Mechanic == MECHANIC_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 // included in Player::UpdateSpellCritChance calculation
((Player*)m_target)->UpdateAllSpellCritChances(); ((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 HandlePhase(bool Apply, bool Real);
void HandleModTargetArmorPct(bool Apply, bool Real); void HandleModTargetArmorPct(bool Apply, bool Real);
void HandleAuraModAllCritChance(bool Apply, bool Real); void HandleAuraModAllCritChance(bool Apply, bool Real);
void HandleAllowOnlyAbility(bool Apply, bool Real);
virtual ~Aura(); virtual ~Aura();
@ -268,6 +269,13 @@ class MANGOS_DLL_SPEC Aura
{ {
if (m_procCharges == 0) if (m_procCharges == 0)
return false; 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--; m_procCharges--;
SendAuraUpdate(false); SendAuraUpdate(false);
return m_procCharges == 0; return m_procCharges == 0;

View file

@ -515,12 +515,14 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
// Ferocious Bite // Ferocious Bite
if (m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & UI64LIT(0x000800000)) && m_spellInfo->SpellVisual[0]==6587) 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 ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx]; 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); 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 // Rake
else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000001000) && m_spellInfo->Effect[2]==SPELL_EFFECT_ADD_COMBO_POINTS) 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); uint32 rage = m_caster->GetPower(POWER_RAGE);
// up to max 30 rage cost // up to max 30 rage cost
if(rage > 30) if(rage > 300)
rage = 30; rage = 300;
// Glyph of Execution bonus // Glyph of Execution bonus
uint32 rage_modified = rage; uint32 rage_modified = rage;
if (Aura *aura = m_caster->GetDummyAura(58367)) 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] + int32 basePoints0 = damage+int32(rage_modified * m_spellInfo->DmgMultiplier[i] +
m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
@ -1465,7 +1467,7 @@ void Spell::EffectDummy(uint32 i)
if ((*itr)->GetSpellProto()->SpellIconID == 1989) if ((*itr)->GetSpellProto()->SpellIconID == 1989)
{ {
// saved rage top stored in next affect // saved rage top stored in next affect
uint32 lastrage = (*itr)->GetSpellProto()->CalculateSimpleValue(1); uint32 lastrage = (*itr)->GetSpellProto()->CalculateSimpleValue(1)*10;
if(lastrage < rage) if(lastrage < rage)
rage -= lastrage; rage -= lastrage;
break; break;
@ -1491,6 +1493,7 @@ void Spell::EffectDummy(uint32 i)
m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
return; return;
} }
switch(m_spellInfo->Id) switch(m_spellInfo->Id)
{ {
// Warrior's Wrath // Warrior's Wrath
@ -2337,7 +2340,7 @@ void Spell::EffectTeleportUnits(uint32 i)
if (unitTarget->GetTypeId() != TYPEID_PLAYER) if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return; 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; return;
} }
case TARGET_AREAEFFECT_INSTANT: // in all cases first TARGET_TABLE_X_Y_Z_COORDINATES 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; addhealth += damageAmount;
} }
// Death Pact (percent heal)
else if (m_spellInfo->Id==48743)
addhealth = addhealth * unitTarget->GetMaxHealth() / 100;
// Swiftmend - consumes Regrowth or Rejuvenation // Swiftmend - consumes Regrowth or Rejuvenation
else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND)) 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); 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]; float multiplier = m_spellInfo->EffectMultipleValue[i];
if (Player *modOwner = m_caster->GetSpellModOwner()) if (Player *modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
int32 new_damage = int32(damage*multiplier); uint32 heal = uint32(damage*multiplier);
uint32 curHealth = unitTarget->GetHealth();
new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage );
if (curHealth < new_damage)
new_damage = curHealth;
if (m_caster->isAlive()) if (m_caster->isAlive())
{ {
new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL); heal = m_caster->SpellHealingBonus(m_caster, m_spellInfo, heal, HEAL);
m_caster->DealHeal(m_caster, uint32(new_damage), m_spellInfo); m_caster->DealHeal(m_caster, heal, m_spellInfo);
} }
} }
@ -3392,54 +3398,99 @@ void Spell::EffectApplyAreaAura(uint32 i)
void Spell::EffectSummonType(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: sLog.outError("EffectSummonType: Unhandled summon type %u", prop_id);
case SUMMON_TYPE_POSESSED: return;
case SUMMON_TYPE_POSESSED2: }
case SUMMON_TYPE_FORCE_OF_NATURE:
case SUMMON_TYPE_GUARDIAN2: switch(summon_prop->Group)
case SUMMON_TYPE_GUARDIAN3: {
// Jewelery statue case (totem like) // faction handled later on, or loaded from template
if(m_spellInfo->SpellIconID == 2056) case SUMMON_PROP_GROUP_WILD:
EffectSummonTotem(i); 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 else
EffectSummonGuardian(i); EffectSummon(i);
break; break;
case SUMMON_TYPE_WILD: }
case SUMMON_TYPE_QUEST_WILD: case SUMMON_PROP_GROUP_CONTROLLABLE:
case SUMMON_TYPE_CREATURE: {
EffectSummonWild(i); // no type here
// maybe wrong - but thats the handler currently used for those
EffectSummonGuardian(i, summon_prop->FactionId);
break; break;
case SUMMON_TYPE_DEMON: }
case SUMMON_TYPE_INFERNO: case SUMMON_PROP_GROUP_VEHICLE:
EffectSummonDemon(i); {
break; // TODO
case SUMMON_TYPE_SUMMON: // EffectSummonVehicle(i);
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:
break; break;
}
default: default:
sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]); sLog.outError("EffectSummonType: Unhandled summon group type %u", summon_prop->Group);
break; break;
} }
} }
@ -3457,6 +3508,10 @@ void Spell::EffectSummon(uint32 i)
uint32 level = m_caster->getLevel(); uint32 level = m_caster->getLevel();
Pet* spawnCreature = new Pet(SUMMON_PET); 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)) if (m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
{ {
// Summon in dest location // Summon in dest location
@ -3470,7 +3525,6 @@ void Spell::EffectSummon(uint32 i)
} }
// set timer for unsummon // set timer for unsummon
int32 duration = GetSpellDuration(m_spellInfo);
if (duration > 0) if (duration > 0)
spawnCreature->SetDuration(duration); spawnCreature->SetDuration(duration);
@ -3509,7 +3563,6 @@ void Spell::EffectSummon(uint32 i)
} }
// set timer for unsummon // set timer for unsummon
int32 duration = GetSpellDuration(m_spellInfo);
if (duration > 0) if (duration > 0)
spawnCreature->SetDuration(duration); spawnCreature->SetDuration(duration);
@ -3780,7 +3833,7 @@ void Spell::EffectAddFarsight(uint32 i)
((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID()); ((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]; uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
if (!creature_entry) if (!creature_entry)
@ -3796,9 +3849,7 @@ void Spell::EffectSummonWild(uint32 i)
{ {
uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING); uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
if (skill202) if (skill202)
{
level = skill202/5; level = skill202/5;
}
} }
} }
@ -3808,6 +3859,8 @@ void Spell::EffectSummonWild(uint32 i)
float center_z = m_targets.m_destZ; float center_z = m_targets.m_destZ;
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); 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; int32 amount = damage > 0 ? damage : 1;
@ -3832,30 +3885,23 @@ void Spell::EffectSummonWild(uint32 i)
else else
m_caster->GetClosePoint(px, py, pz, 3.0f); 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; if(forceFaction)
summon->setFaction(forceFaction);
m_caster->SummonCreature(creature_entry, px, py, pz, m_caster->GetOrientation(), summonType, duration); }
} }
} }
void Spell::EffectSummonGuardian(uint32 i) void Spell::EffectSummonGuardian(uint32 i, uint32 forceFaction)
{ {
uint32 pet_entry = m_spellInfo->EffectMiscValue[i]; uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
if (!pet_entry) if (!pet_entry)
return; 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 // in another case summon new
uint32 level = m_caster->getLevel(); uint32 level = m_caster->getLevel();
@ -3879,6 +3925,9 @@ void Spell::EffectSummonGuardian(uint32 i)
float center_z = m_targets.m_destZ; float center_z = m_targets.m_destZ;
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); 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; int32 amount = damage > 0 ? damage : 1;
@ -3930,8 +3979,8 @@ void Spell::EffectSummonGuardian(uint32 i)
spawnCreature->SetOwnerGUID(m_caster->GetGUID()); spawnCreature->SetOwnerGUID(m_caster->GetGUID());
spawnCreature->setPowerType(POWER_MANA); spawnCreature->setPowerType(POWER_MANA);
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->npcflag);
spawnCreature->setFaction(m_caster->getFaction()); spawnCreature->setFaction(forceFaction ? forceFaction : m_caster->getFaction());
spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0); spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0); spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
@ -5350,6 +5399,14 @@ void Spell::EffectScriptEffect(uint32 effIndex)
} }
return; 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; break;
} }
@ -5745,7 +5802,7 @@ void Spell::EffectStuck(uint32 /*i*/)
return; return;
// homebind location is loaded always // 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 // Stuck spell trigger Hearthstone cooldown
SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690); 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; slot = slot ? (slot - 1): 255;
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;
}
if(slot < MAX_TOTEM) if(slot < MAX_TOTEM)
{ {
@ -6339,7 +6384,7 @@ void Spell::EffectCharge2(uint32 /*i*/)
m_caster->Attack(unitTarget,true); m_caster->Attack(unitTarget,true);
} }
void Spell::EffectSummonCritter(uint32 i) void Spell::EffectSummonCritter(uint32 i, uint32 forceFaction)
{ {
if(m_caster->GetTypeId() != TYPEID_PLAYER) if(m_caster->GetTypeId() != TYPEID_PLAYER)
return; return;
@ -6399,9 +6444,9 @@ void Spell::EffectSummonCritter(uint32 i)
critter->SetOwnerGUID(m_caster->GetGUID()); critter->SetOwnerGUID(m_caster->GetGUID());
critter->SetCreatorGUID(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->AIM_Initialize();
critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter... critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
//critter->InitLevelupSpellsForLevel(); // none? //critter->InitLevelupSpellsForLevel(); // none?
@ -6764,65 +6809,6 @@ void Spell::EffectSkill(uint32 /*i*/)
sLog.outDebug("WORLD: SkillEFFECT"); 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*/) void Spell::EffectSpiritHeal(uint32 /*i*/)
{ {
// TODO player can't see the heal-animation - he should respawn some ticks later // 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 ) ) spellInfo_2->SpellVisual[0] == 99 && spellInfo_1->SpellVisual[0] == 0 ) )
return false; return false;
// Heart of the Wild and (Primal Instinct (Idol of Terror) triggering spell or Agility) // Heart of the Wild, Agility and various Idol Triggers
if( spellInfo_1->SpellIconID == 240 && spellInfo_2->SpellIconID == 240 && ( 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 ) )
return false; return false;
// Personalized Weather (thunder effect should overwrite rainy aura) // 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) if( spellId_1 == 35081 && spellInfo_2->SpellIconID==561 && spellInfo_2->SpellVisual[0]==7992)
return false; 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; break;
} }
} }
@ -1642,8 +1644,13 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
// Concentration Aura and Improved Concentration Aura and Aura Mastery // Concentration Aura and Improved Concentration Aura and Aura Mastery
if ((spellInfo_1->SpellIconID == 1487) && (spellInfo_2->SpellIconID == 1487)) if ((spellInfo_1->SpellIconID == 1487) && (spellInfo_2->SpellIconID == 1487))
return false; 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) // Combustion and Fire Protection Aura (multi-family check)
if( spellInfo_2->Id == 11129 && spellInfo_1->SpellIconID == 33 && spellInfo_1->SpellVisual[0] == 321 ) if( spellInfo_2->Id == 11129 && spellInfo_1->SpellIconID == 33 && spellInfo_1->SpellVisual[0] == 321 )
return false; 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 && if( spellInfo_1->SpellIconID==220 && spellInfo_2->SpellIconID==220 &&
spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags ) spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags )
return false; return false;
// Ghost Wolf
if (spellInfo_1->SpellIconID == 67 && spellInfo_2->SpellIconID == 67)
return false;
} }
// Bloodlust and Bloodthirst (multi-family check) // Bloodlust and Bloodthirst (multi-family check)
if( spellInfo_1->Id == 2825 && spellInfo_2->SpellIconID == 38 && spellInfo_2->SpellVisual[0] == 0 ) 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) if (spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
return false; return false;
bool dummy_only = true;
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
{
if (spellInfo_1->Effect[i] != spellInfo_2->Effect[i] || if (spellInfo_1->Effect[i] != spellInfo_2->Effect[i] ||
spellInfo_1->EffectItemType[i] != spellInfo_2->EffectItemType[i] || spellInfo_1->EffectItemType[i] != spellInfo_2->EffectItemType[i] ||
spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i] || spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i] ||
spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i]) spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i])
return false; 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; return true;
} }

View file

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

View file

@ -1693,8 +1693,47 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
// Death Prevention Aura // Death Prevention Aura
SpellEntry const* preventDeathSpell = NULL; SpellEntry const* preventDeathSpell = NULL;
int32 preventDeathAmount = 0; 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 // Need remove expired auras after
bool existExpired = false; bool existExpired = false;
// absorb without mana cost // absorb without mana cost
AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB); AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
for(AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end() && RemainingDamage > 0; ++i) 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; preventDeathAmount = (*i)->GetModifier()->m_amount;
continue; 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 // Reflective Shield
if (spellProto->SpellFamilyFlags == 0x1 && canReflect) if (spellProto->SpellFamilyFlags == 0x1 && canReflect)
{ {
@ -1945,13 +1994,18 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
else else
currentAbsorb = RemainingDamage; currentAbsorb = RemainingDamage;
float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()]; if (float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()])
if(Player *modOwner = pVictim->GetSpellModOwner()) {
modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier); if(Player *modOwner = pVictim->GetSpellModOwner())
modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier); int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
if (currentAbsorb > maxAbsorb) if (currentAbsorb > maxAbsorb)
currentAbsorb = maxAbsorb; currentAbsorb = maxAbsorb;
int32 manaReduction = int32(currentAbsorb * manaMultiplier);
pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
}
(*i)->GetModifier()->m_amount -= currentAbsorb; (*i)->GetModifier()->m_amount -= currentAbsorb;
if((*i)->GetModifier()->m_amount <= 0) if((*i)->GetModifier()->m_amount <= 0)
@ -1960,12 +2014,40 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
next = vManaShield.begin(); next = vManaShield.begin();
} }
int32 manaReduction = int32(currentAbsorb * manaMultiplier);
pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
RemainingDamage -= currentAbsorb; 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 // only split damage if not damaging yourself
if(pVictim != this) if(pVictim != this)
{ {
@ -3867,7 +3949,7 @@ void Unit::RemoveSingleAuraDueToSpellByDispel(uint32 spellId, uint64 casterGUID,
{ {
SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId);
// Custom dispel case // Custom dispel cases
// Unstable Affliction // Unstable Affliction
if(spellEntry->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellEntry->SpellFamilyFlags & UI64LIT(0x010000000000))) if(spellEntry->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellEntry->SpellFamilyFlags & UI64LIT(0x010000000000)))
{ {
@ -3881,9 +3963,43 @@ void Unit::RemoveSingleAuraDueToSpellByDispel(uint32 spellId, uint64 casterGUID,
// backfire damage and silence // backfire damage and silence
dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL,casterGUID); 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); 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) 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) 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) // Healing Touch (Dreamwalker Raiment set)
case 28719: 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; basepoints0 = GetAttackTime(BASE_ATTACK) * int32(ap*0.022f + 0.044f * holy) / 1000;
break; break;
} }
// Sacred Shield
if (dummySpell->SpellFamilyFlags & UI64LIT(0x0008000000000000))
{
triggered_spell_id = 58597;
target = this;
break;
}
// Righteous Vengeance // Righteous Vengeance
if (dummySpell->SpellIconID == 3025) if (dummySpell->SpellIconID == 3025)
{ {
@ -5853,14 +5990,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
// Judgement of Light // Judgement of Light
case 20185: case 20185:
{ {
// Get judgement caster basepoints0 = int32( pVictim->GetMaxHealth() * triggeredByAura->GetModifier()->m_amount / 100 );
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);
pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, NULL, NULL, true, NULL, triggeredByAura); pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
return true; return true;
} }
@ -5932,6 +6062,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
} }
break; 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) // Seal of Vengeance (damage calc on apply aura)
case 31801: case 31801:
{ {
@ -5969,20 +6113,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
// Replenishment // Replenishment
CastSpell(this, 57669, true, NULL, triggeredByAura); CastSpell(this, 57669, true, NULL, triggeredByAura);
break; 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) // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
case 40470: case 40470:
{ {
@ -6011,29 +6141,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
break; 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) // Light's Beacon (heal target area aura)
case 53651: 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()); beacon->CastCustomSpell(beacon,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura,pVictim->GetGUID());
return true; 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 // Glyph of Divinity
case 54939: case 54939:
{ {
@ -6082,18 +6226,23 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
} }
return true; return true;
} }
// Glyph of Flash of Light // Sacred Shield (buff)
case 54936: case 58597:
{ {
triggered_spell_id = 54957; triggered_spell_id = 66922;
basepoints0 = triggerAmount*damage/100; SpellEntry const* triggeredEntry = sSpellStore.LookupEntry(triggered_spell_id);
if (!triggeredEntry)
return false;
basepoints0 = int32(damage / (GetSpellDuration(triggeredEntry) / triggeredEntry->EffectAmplitude[0]));
target = this;
break; break;
} }
// Glyph of Holy Light // Sacred Shield (talent rank)
case 54937: case 53601:
{ {
triggered_spell_id = 54968; triggered_spell_id = 58597;
basepoints0 = triggerAmount*damage/100; target = this;
break; break;
} }
} }
@ -6324,7 +6473,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
uint32 spell = (*itr)->GetSpellProto()->EffectTriggerSpell[(*itr)->GetEffIndex()]; uint32 spell = (*itr)->GetSpellProto()->EffectTriggerSpell[(*itr)->GetEffIndex()];
CastSpell(this, spell, true, castItem, triggeredByAura); CastSpell(this, spell, true, castItem, triggeredByAura);
if ((*itr)->DropAuraCharge()) if ((*itr)->DropAuraCharge())
RemoveAurasDueToSpell((*itr)->GetId()); RemoveSingleSpellAurasFromStack((*itr)->GetId());
return true; return true;
} }
} }
@ -6426,7 +6575,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
} }
CastSpell(target, spell, true, castItem, triggeredByAura); CastSpell(target, spell, true, castItem, triggeredByAura);
if ((*itr)->DropAuraCharge()) if ((*itr)->DropAuraCharge())
RemoveAurasDueToSpell((*itr)->GetId()); RemoveSingleSpellAurasFromStack((*itr)->GetId());
return true; return true;
} }
} }
@ -6919,16 +7068,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
} }
case SPELLFAMILY_DRUID: 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 // Druid Forms Trinket
else if (auraSpellInfo->Id==37336) if (auraSpellInfo->Id==37336)
{ {
switch(m_form) 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_NATURE: trigger_spell_id = 50488; break;
case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break; case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break;
case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; 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: default:
return false; return false;
} }
@ -7525,6 +7666,9 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, Aura
case 5497: // Improved Mana Gems (Serpent-Coil Braid) case 5497: // Improved Mana Gems (Serpent-Coil Braid)
triggered_spell_id = 37445; // Mana Surge triggered_spell_id = 37445; // Mana Surge
break; break;
case 6953: // Warbringer
RemoveAurasAtMechanicImmunity(IMMUNE_TO_ROOT_AND_SNARE_MASK,0,true);
return true;
case 8152: // Serendipity case 8152: // Serendipity
{ {
// if heal your target over maximum health // 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: case SPELL_DAMAGE_CLASS_RANGED:
{ {
if (pVictim) if (pVictim)
{
crit_chance = GetUnitCriticalChance(attackType, 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; break;
} }
default: default:
@ -10252,7 +10395,12 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
// Apply strongest slow aura mod to speed // Apply strongest slow aura mod to speed
int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED);
if (slow) if (slow)
{
speed *=(100.0f + slow)/100.0f; 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); 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); durationMod_always+=target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->Dispel);
// Find max mod (negative bonus) // Find max mod (negative bonus)
int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic); 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; int32 durationMod = 0;
// Select strongest negative mod // Select strongest negative mod
@ -11578,6 +11729,7 @@ bool InitTriggerAuraData()
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true; isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true; isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true;
isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = 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_MOD_POWER_REGEN]=true;
isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK]=true; isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK]=true;
@ -11868,6 +12020,13 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
continue; continue;
} }
break; 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: default:
// nothing do, just charges counter // nothing do, just charges counter
break; break;
@ -11890,7 +12049,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
removedSpells.unique(); removedSpells.unique();
// Remove auras from removedAuras // Remove auras from removedAuras
for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();++i) 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.LoadQuestLocales();
sObjectMgr.LoadNpcTextLocales(); sObjectMgr.LoadNpcTextLocales();
sObjectMgr.LoadPageTextLocales(); sObjectMgr.LoadPageTextLocales();
sObjectMgr.LoadNpcOptionLocales(); sObjectMgr.LoadGossipMenuItemsLocales();
sObjectMgr.LoadPointOfInterestLocales(); sObjectMgr.LoadPointOfInterestLocales();
sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts)
sLog.outString( ">>> Localization strings loaded" ); sLog.outString( ">>> Localization strings loaded" );
@ -1405,8 +1405,14 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Npc Text Id..." ); sLog.outString( "Loading Npc Text Id..." );
sObjectMgr.LoadNpcTextId(); // must be after load Creature and NpcText sObjectMgr.LoadNpcTextId(); // must be after load Creature and NpcText
sLog.outString( "Loading Npc Options..." ); sLog.outString( "Loading Gossip scripts..." );
sObjectMgr.LoadNpcOptions(); 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..." ); sLog.outString( "Loading Vendors..." );
sObjectMgr.LoadVendors(); // must be after load CreatureTemplate and ItemTemplate 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 ///- Teleport to home if the player is in an invalid instance
if(!_player->m_InstanceValid && !_player->isGameMaster()) 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 //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? //maybe we should implement delayed far teleport logout?
} }

View file

@ -152,6 +152,14 @@ bool ChatHandler::HandleCharacterDeleteCommand(const char* args)
return true; 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 /// Exit the realm
bool ChatHandler::HandleServerExitCommand(const char* /*args*/) bool ChatHandler::HandleServerExitCommand(const char* /*args*/)
{ {

View file

@ -225,7 +225,10 @@ void RASocket::OnRead()
if (strlen(buff)) if (strlen(buff))
{ {
sLog.outRALog("Got '%s' cmd.\n",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 else
Sendf("mangos>"); Sendf("mangos>");

View file

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

View file

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

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__ #ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__ #define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_8874_01_characters_character_skills" #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" #define REVISION_DB_REALMD "required_8728_01_realmd_account"
#endif // __REVISION_SQL_H__ #endif // __REVISION_SQL_H__