Merge commit 'origin/master' into 320

This commit is contained in:
tomrus88 2009-07-26 10:52:21 +04:00
commit 299f40ac0c
39 changed files with 1131 additions and 480 deletions

View file

@ -137,6 +137,7 @@ Each event type has its own specific interpretation of it's params, like every e
39 ACTION_T_CALL_FOR_HELP Radius Call any friendly out-of-combat creatures in a radius (Param1) to attack current creature's target. 39 ACTION_T_CALL_FOR_HELP Radius Call any friendly out-of-combat creatures in a radius (Param1) to attack current creature's target.
40 ACTION_T_SET_SHEATH Sheath Sets sheath state for a creature (0 = no weapon, 1 = melee weapon, 2 = ranged weapon). 40 ACTION_T_SET_SHEATH Sheath Sets sheath state for a creature (0 = no weapon, 1 = melee weapon, 2 = ranged weapon).
41 ACTION_T_FORCE_DESPAWN No Params Despawns the creature 41 ACTION_T_FORCE_DESPAWN No Params Despawns the creature
42 ACTION_T_SET_INVINCIBILITY_HP_LEVEL hp_level, is_percent Set min. health level for creature that can be set at damage as flat value or percent from max health
* = Use -1 where the param is expected to do nothing. Random constant is generated for each event, so if you have a random yell and a random sound, they will be linked up with each other (ie. param2 with param2). * = Use -1 where the param is expected to do nothing. Random constant is generated for each event, so if you have a random yell and a random sound, they will be linked up with each other (ie. param2 with param2).
@ -737,6 +738,14 @@ This possible setup by set ar event AI start (single used EVENT_T_TIMER_OOC set
Despawns the creature (in or out of combat) Despawns the creature (in or out of combat)
No parameters No parameters
-------------------------
42 ACTION_T_SET_INVINCIBILITY_HP_LEVEL
-------------------------
Parameter 1: min. health level for creature that can be set at damage, 0 used as absent min. health value for apply damage.
Parameter 2: format of paramater 1 value
0 paramater 1 used as flat value
1 paramater 1 used as percent (0..100) from creature max health
========================================= =========================================
Target Types Target Types
========================================= =========================================

File diff suppressed because it is too large Load diff

View file

@ -249,6 +249,7 @@ INSERT INTO spell_check (spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMas
(50246,-1, -1, -1, -1, -1, -1, -1, -1,-1,'01001000', 'Spell::EffectDummy'), (50246,-1, -1, -1, -1, -1, -1, -1, -1,-1,'01001000', 'Spell::EffectDummy'),
(50286, 7,0x0000000000000000,0x00000100, -1, -1, -1, 3, -1,-1,'Starfall', 'Spell::EffectDummy'), (50286, 7,0x0000000000000000,0x00000100, -1, -1, -1, 3, -1,-1,'Starfall', 'Spell::EffectDummy'),
(50288,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Starfall', 'Spell::EffectDummy'), (50288,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Starfall', 'Spell::EffectDummy'),
(51209,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Hungering Cold', 'Spell::EffectDummy'),
(51582, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Rocket Boots Engaged', 'Spell::EffectDummy'), (51582, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Rocket Boots Engaged', 'Spell::EffectDummy'),
(51592, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Pickup Primordial Hatchling', 'Spell::EffectDummy'), (51592, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Pickup Primordial Hatchling', 'Spell::EffectDummy'),
(52025,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Cleansing Totem Effect', 'Spell::EffectDummy'), (52025,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Cleansing Totem Effect', 'Spell::EffectDummy'),
@ -318,6 +319,7 @@ INSERT INTO spell_check (spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMas
( 0,11,0x0000000000002000,0x00000000, -1, -1, -1, 3, -1,-1,'Healing Stream Totem', 'Spell::EffectDummy'), ( 0,11,0x0000000000002000,0x00000000, -1, -1, -1, 3, -1,-1,'Healing Stream Totem', 'Spell::EffectDummy'),
( 0, 4,0x0000000100000000,0x00000000, -1, -1, -1, 2, -1,-1,'Heroic Throw', 'Spell::EffectSchoolDMG'), ( 0, 4,0x0000000100000000,0x00000000, -1, -1, -1, 2, -1,-1,'Heroic Throw', 'Spell::EffectSchoolDMG'),
( 0,10, -1, -1, 156, -1, -1, 3, -1,-1,'Holy Shock', 'Spell::EffectDummy'), ( 0,10, -1, -1, 156, -1, -1, 3, -1,-1,'Holy Shock', 'Spell::EffectDummy'),
( 0,15,0x0000100000000000,0x00000000, -1, -1, -1, 3, -1,-1,'Hungering Cold', 'Spell::EffectDummy'),
( 0, 5,0x0000000000000004,0x00000000, -1, -1, -1, -1, 3,-1,'Immolate', 'Spell::EffectSchoolDMG'), ( 0, 5,0x0000000000000004,0x00000000, -1, -1, -1, -1, 3,-1,'Immolate', 'Spell::EffectSchoolDMG'),
(0, 5, -1, -1, 208, -1, -1, -1, 4,-1,'Improved Life Tap', 'Spell::EffectDummy'), (0, 5, -1, -1, 208, -1, -1, -1, 4,-1,'Improved Life Tap', 'Spell::EffectDummy'),
( 0, 5,0x0000004000000000,0x00000000,2128, -1, -1, 2, -1,-1,'Incinerate', 'Spell::EffectSchoolDMG'), ( 0, 5,0x0000004000000000,0x00000000,2128, -1, -1, 2, -1,-1,'Incinerate', 'Spell::EffectSchoolDMG'),

View file

@ -0,0 +1,7 @@
ALTER TABLE db_version CHANGE COLUMN required_8213_01_mangos_spell_bonus_data required_8227_01_mangos_spell_proc_event bit;
DELETE FROM `spell_proc_event` WHERE entry IN (63730,63733,63737);
INSERT INTO `spell_proc_event` VALUES
(63730, 0x00000000, 6, 0x00000800, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(63733, 0x00000000, 6, 0x00000800, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(63737, 0x00000000, 6, 0x00000800, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0);

View file

@ -0,0 +1,4 @@
ALTER TABLE db_version CHANGE COLUMN required_8227_01_mangos_spell_proc_event required_8237_01_mangos_creature_template bit;
UPDATE creature_template
SET mindmg = ROUND(mindmg + attackpower), maxdmg=ROUND(maxdmg+attackpower);

View file

@ -0,0 +1,18 @@
ALTER TABLE db_version CHANGE COLUMN required_8237_01_mangos_creature_template required_8247_01_mangos_spell_bonus_data bit;
DELETE FROM `spell_bonus_data` where entry in (49941, 55078, 50444, 52212, 47632, 47633, 55095, 49184, 45477, 45477, 50842, 47476, 50536, 50401, 56903);
INSERT INTO `spell_bonus_data`(`entry`, `direct_bonus`, `dot_bonus`, `ap_bonus`, `comments`) VALUES
(49941, 0, 0, 0.04, "Death Knight - Blood Boil"),
(55078, 0, 0, 0.055, "Death Knight - Blood Plague Dummy Proc"),
(50444, 0, 0, 0.105, "Death Knight - Corpse Explosion Triggered"),
(52212, 0, 0, 0.0475, "Death Knight - Death and Decay Triggered"),
(47632, 0, 0, 0.15, "Death Knight - Death Coil Damage"),
(47633, 0, 0, 0.15, "Death Knight - Death Coil Heal"),
(55095, 0, 0, 0.055, "Death Knight - Frost Fever"),
(49184, 0, 0, 0.1, "Death Knight - Howling Blast"),
(45477, 0, 0, 0.1, "Death Knight - Icy Touch"),
(50842, 0, 0, 0.04, "Death Knight - Pestilence"),
(47476, 0, 0, 0.06, "Death Knight - Strangulate"),
(50536, 0, 0, 0.013, "Death Knight - Unholy Blight Triggered"),
(50401, 0, 0, 0, "Death Knight - Razor Frost"),
(56903, 0, 0, 0, "Death Knight - Lichflame");

View file

@ -0,0 +1,13 @@
ALTER TABLE db_version CHANGE COLUMN required_8247_01_mangos_spell_bonus_data required_8249_01_mangos_spell_proc_item_enchant bit;
DROP TABLE IF EXISTS `spell_proc_item_enchant`;
CREATE TABLE `spell_proc_item_enchant` (
`entry` mediumint unsigned NOT NULL,
`ppmRate` float NOT NULL default '0',
PRIMARY KEY (`entry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `spell_proc_item_enchant` (`entry`, `ppmRate`) VALUES
(8034, 9), -- Frostbrand Weapon
(8680, 8.5714), -- Instant Poison
(13218, 21.4286); -- Wound Poison

View file

@ -0,0 +1,31 @@
ALTER TABLE db_version CHANGE COLUMN required_8249_01_mangos_spell_proc_item_enchant required_8249_02_mangos_spell_chain bit;
DELETE FROM `spell_chain` WHERE `spell_id` IN
(8034, 8037, 10458, 16352, 16353, 25501, 58797, 58798, 58799, 8680, 8685, 8689, 11335, 11336, 11337, 26890, 57964, 57965, 13218, 13222, 13223, 13224, 27189, 57974, 57975);
INSERT INTO `spell_chain` (`spell_id`, `prev_spell`, `first_spell`, `rank`, `req_spell`) VALUES
(8034,0,8034,1,0), -- Frostbrand Attack
(8037,8034,8034,2,0),
(10458,8037,8034,3,0),
(16352,10458,8034,4,0),
(16353,16352,8034,5,0),
(25501,16353,8034,6,0),
(58797,25501,8034,7,0),
(58798,58797,8034,8,0),
(58799,58798,8034,9,0),
(8680,0,8680,1,0), -- Instant Poison
(8685,8680,8680,2,0),
(8689,8685,8680,3,0),
(11335,8689,8680,4,0),
(11336,11335,8680,5,0),
(11337,11336,8680,6,0),
(26890,11337,8680,7,0),
(57964,26890,8680,8,0),
(57965,57964,8680,9,0),
(13218,0,13218,1,0), -- Wound Poison
(13222,13218,13218,2,0),
(13223,13222,13218,3,0),
(13224,13223,13218,4,0),
(27189,13224,13218,5,0),
(57974,27189,13218,6,0),
(57975,57974,13218,7,0);

View file

@ -0,0 +1,3 @@
ALTER TABLE db_version CHANGE COLUMN required_8249_02_mangos_spell_chain required_8250_01_mangos_spell_threat bit;
DELETE FROM `spell_threat` WHERE `entry` IN (778,9749,9907,14274,15629,15630,15631,15632,17390,17391,17392,26993,27011);

View file

@ -0,0 +1,141 @@
ALTER TABLE db_version CHANGE COLUMN required_8250_01_mangos_spell_threat required_8251_01_mangos_spell_chain bit;
DELETE FROM `spell_chain` WHERE `spell_id` IN (
7268,7269,7270,8419,8418,10273,10274,25346,27076,38700,38703,42844,42845,
42208,42209,42210,42211,42212,42213,42198,42937,42938,
34913,43043,43044,
25912,25911,25902,27176,33073,48822,48823,
25914,25913,25903,27175,33074,48820,48821,
23455,23458,23459,27803,27804,27805,25329,
49821,53022,
8443,8504,8505,11310,11311,25538,25539,61651,61660,
8026,8028,8029,10445,16343,16344,25488,58786,58787,58788,
26364,26365,26366,26367,26369,26370,26363,26371,26372,49278,49279,
8188,10582,10583,10584,25551,58733,58736,
3606,6350,6351,6352,10435,10436,25530,58700,58701,58702,
5857,11681,11682,27214,47822,
42223,42224,42225,42226,42218,47817,47818
);
INSERT INTO `spell_chain` (`spell_id`, `prev_spell`, `first_spell`, `rank`, `req_spell`) VALUES
/* Arcane Missiles Triggered Spell */
(7268,0,7268,1,0),
(7269,7268,7268,2,0),
(7270,7269,7268,3,0),
(8419,7270,7268,4,0),
(8418,8419,7268,5,0),
(10273,8418,7268,6,0),
(10274,10273,7268,7,0),
(25346,10274,7268,8,0),
(27076,25346,7268,9,0),
(38700,27076,7268,10,0),
(38703,38700,7268,11,0),
(42844,38703,7268,12,0),
(42845,42844,7268,13,0),
/* Blizzard Triggered Spell */
(42208,0,42208,1,0),
(42209,42208,42208,2,0),
(42210,42209,42208,3,0),
(42211,42210,42208,4,0),
(42212,42211,42208,5,0),
(42213,42212,42208,6,0),
(42198,42213,42208,7,0),
(42937,42198,42208,8,0),
(42938,42937,42208,9,0),
/* Molten Armor Triggered */
(34913,0,34913,1,0),
(43043,34913,34913,2,0),
(43044,43043,34913,3,0),
/* Holy Shock Triggered Hurt */
(25912,0,25912,1,0),
(25911,25912,25912,2,0),
(25902,25911,25912,3,0),
(27176,25902,25912,4,0),
(33073,27176,25912,5,0),
(48822,33073,25912,6,0),
(48823,48822,25912,7,0),
/* Holy Shock Triggered Heal */
(25914,0,25914,1,0),
(25913,25914,25914,2,0),
(25903,25913,25914,3,0),
(27175,25903,25914,4,0),
(33074,27175,25914,5,0),
(48820,33074,25914,6,0),
(48821,48820,25914,7,0),
/* Holy Nova Heal */
(23455,0,23455,1,0),
(23458,23455,23455,2,0),
(23459,23458,23455,3,0),
(27803,23459,23455,4,0),
(27804,27803,23455,5,0),
(27805,27804,23455,6,0),
(25329,27805,23455,7,0),
/* Mind Sear Trigger */
(49821,0,49821,1,0),
(53022,49821,49821,2,0),
/* Fire Nova Totem Casted by Totem */
(8443,0,8443,1,0),
(8504,8443,8443,2,0),
(8505,8504,8443,3,0),
(11310,8505,8443,4,0),
(11311,11310,8443,5,0),
(25538,11311,8443,6,0),
(25539,25538,8443,7,0),
(61651,25539,8443,8,0),
(61660,61651,8443,9,0),
/* Flametongue Weapon Proc */
(8026,0,8026,1,0),
(8028,8026,8026,2,0),
(8029,8028,8026,3,0),
(10445,8029,8026,4,0),
(16343,10445,8026,5,0),
(16344,16343,8026,6,0),
(25488,16344,8026,7,0),
(58786,25488,8026,8,0),
(58787,58786,8026,9,0),
(58788,58787,8026,10,0),
/* Lightning Shield Proc */
(26364,0,26364,1,0),
(26365,26364,26364,2,0),
(26366,26365,26364,3,0),
(26367,26366,26364,4,0),
(26369,26367,26364,5,0),
(26370,26369,26364,6,0),
(26363,26370,26364,7,0),
(26371,26363,26364,8,0),
(26372,26371,26364,9,0),
(49278,26372,26364,10,0),
(49279,49278,26364,11,0),
/* Magma Totam Passive */
(8188,0,8188,1,0),
(10582,8188,8188,2,0),
(10583,10582,8188,3,0),
(10584,10583,8188,4,0),
(25551,10584,8188,5,0),
(58733,25551,8188,6,0),
(58736,58733,8188,7,0),
/* Searing Totem Attack */
(3606,0,3606,1,0),
(6350,3606,3606,2,0),
(6351,6350,3606,3,0),
(6352,6351,3606,4,0),
(10435,6352,3606,5,0),
(10436,10435,3606,6,0),
(25530,10436,3606,7,0),
(58700,25530,3606,8,0),
(58701,58700,3606,9,0),
(58702,58701,3606,10,0),
/* Hellfire Effect on Enemy */
(5857,0,5857,1,0),
(11681,5857,5857,2,0),
(11682,11681,5857,3,0),
(27214,11682,5857,4,0),
(47822,27214,5857,5,0),
/* Rain of Fire Triggered */
(42223,0,42223,1,0),
(42224,42223,42223,2,0),
(42225,42224,42223,3,0),
(42226,42225,42223,4,0),
(42218,42226,42223,5,0),
(47817,42218,42223,6,0),
(47818,47817,42223,7,0);

View file

@ -0,0 +1,23 @@
ALTER TABLE db_version CHANGE COLUMN required_8251_01_mangos_spell_chain required_8251_02_mangos_spell_bonus_data bit;
DELETE FROM `spell_bonus_data` where entry in (
49941,48721,
8037,10458,16352,16353,25501,58797,58798,58799,18937,18938,27265,59092,49941,
7269,7270,8419,8418,10273,10274,25346,27076,38700,38703,42844,42845,
42209,42210,42211,42212,42213,42198,42937,42938,
43043,43044,
25911,25902,27176,33073,48822,48823,
25913,25903,27175,33074,48820,48821,
23458,23459,27803,27804,27805,25329,
53022,
8504,8505,11310,11311,25538,25539,61651,61660,
8028,8029,10445,16343,16344,25488,58786,58787,58788,
26365,26366,26367,26369,26370,26363,26371,26372,49278,49279,
10582,10583,10584,25551,58733,58736,
6350,6351,6352,10435,10436,25530,58700,58701,58702,
11681,11682,27214,47822,
42224,42225,42226,42218,47817,47818
);
INSERT INTO `spell_bonus_data` VALUES
('48721', '0', '0', '0.04', 'Death Knight - Blood Boil');

View file

@ -0,0 +1,8 @@
ALTER TABLE db_version CHANGE COLUMN required_8251_02_mangos_spell_bonus_data required_8251_03_mangos_spell_proc_event bit;
DELETE FROM `spell_proc_event` WHERE entry IN (
325,905,945,8134,8494,8495,10191,10192,10193,10431,10432,14318,14319,14320,
14321,14322,20927,20928,24398,25296,25469,25472,25899,27044,27131,27179,32593,
32594,33736,33776,34916,34917,43019,43020,63158,48159,48160,48951,48952,49280,
49281,49283,49284,52129,52131,52134,52136,52138,57960,48112,48113,63733,63737
);

View file

@ -249,6 +249,15 @@ pkgdata_DATA = \
8211_01_mangos_spell_proc_event.sql \ 8211_01_mangos_spell_proc_event.sql \
8212_01_mangos_spell_proc_event.sql \ 8212_01_mangos_spell_proc_event.sql \
8213_01_mangos_spell_bonus_data.sql \ 8213_01_mangos_spell_bonus_data.sql \
8227_01_mangos_spell_proc_event.sql \
8237_01_mangos_creature_template.sql \
8247_01_mangos_spell_bonus_data.sql \
8249_01_mangos_spell_proc_item_enchant.sql \
8249_02_mangos_spell_chain.sql \
8250_01_mangos_spell_threat.sql \
8251_01_mangos_spell_chain.sql \
8251_02_mangos_spell_bonus_data.sql \
8251_03_mangos_spell_proc_event.sql \
README README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -478,4 +487,13 @@ EXTRA_DIST = \
8211_01_mangos_spell_proc_event.sql \ 8211_01_mangos_spell_proc_event.sql \
8212_01_mangos_spell_proc_event.sql \ 8212_01_mangos_spell_proc_event.sql \
8213_01_mangos_spell_bonus_data.sql \ 8213_01_mangos_spell_bonus_data.sql \
8227_01_mangos_spell_proc_event.sql \
8237_01_mangos_creature_template.sql \
8247_01_mangos_spell_bonus_data.sql \
8249_01_mangos_spell_proc_item_enchant.sql \
8249_02_mangos_spell_chain.sql \
8250_01_mangos_spell_threat.sql \
8251_01_mangos_spell_chain.sql \
8251_02_mangos_spell_bonus_data.sql \
8251_03_mangos_spell_proc_event.sql \
README README

View file

@ -451,6 +451,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "spell_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSpellCommand, "", NULL }, { "spell_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSpellCommand, "", NULL },
{ "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL }, { "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL },
{ "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL }, { "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL },
{ "spell_proc_item_enchant", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcItemEnchantCommand, "", NULL },
{ "spell_script_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL }, { "spell_script_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL },
{ "spell_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL }, { "spell_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL },
{ "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL }, { "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL },

View file

@ -375,6 +375,7 @@ class ChatHandler
bool HandleReloadSpellElixirCommand(const char* args); bool HandleReloadSpellElixirCommand(const char* args);
bool HandleReloadSpellLearnSpellCommand(const char* args); bool HandleReloadSpellLearnSpellCommand(const char* args);
bool HandleReloadSpellProcEventCommand(const char* args); bool HandleReloadSpellProcEventCommand(const char* args);
bool HandleReloadSpellProcItemEnchantCommand(const char* args);
bool HandleReloadSpellBonusesCommand(const char* args); bool HandleReloadSpellBonusesCommand(const char* args);
bool HandleReloadSpellScriptTargetCommand(const char* args); bool HandleReloadSpellScriptTargetCommand(const char* args);
bool HandleReloadSpellScriptsCommand(const char* args); bool HandleReloadSpellScriptsCommand(const char* args);

View file

@ -93,6 +93,8 @@ CreatureEventAI::CreatureEventAI(Creature *c ) : CreatureAI(c)
AttackDistance = 0.0f; AttackDistance = 0.0f;
AttackAngle = 0.0f; AttackAngle = 0.0f;
InvinceabilityHpLevel = 0;
//Handle Spawned Events //Handle Spawned Events
if (!bEmptyList) if (!bEmptyList)
{ {
@ -780,6 +782,14 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
m_creature->ForcedDespawn(); m_creature->ForcedDespawn();
break; break;
} }
case ACTION_T_SET_INVINCIBILITY_HP_LEVEL:
{
if(action.invincibility_hp_level.is_percent)
InvinceabilityHpLevel = m_creature->GetMaxHealth()*action.invincibility_hp_level.hp_level/100;
else
InvinceabilityHpLevel = action.invincibility_hp_level.hp_level;
break;
}
} }
} }
@ -1380,6 +1390,17 @@ void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
} }
} }
void CreatureEventAI::DamageTaken( Unit* done_by, uint32& damage )
{
if(InvinceabilityHpLevel > 0 && m_creature->GetHealth() < InvinceabilityHpLevel+damage)
{
if(m_creature->GetHealth() <= InvinceabilityHpLevel)
damage = 0;
else
damage = m_creature->GetHealth() - InvinceabilityHpLevel;
}
}
bool CreatureEventAI::SpawnedEventConditionsCheck(CreatureEventAI_Event const& event) bool CreatureEventAI::SpawnedEventConditionsCheck(CreatureEventAI_Event const& event)
{ {
if(event.event_type != EVENT_T_SPAWNED) if(event.event_type != EVENT_T_SPAWNED)

View file

@ -106,6 +106,7 @@ enum EventAI_ActionType
ACTION_T_CALL_FOR_HELP = 39, // Radius ACTION_T_CALL_FOR_HELP = 39, // Radius
ACTION_T_SET_SHEATH = 40, // Sheath (0-passive,1-melee,2-ranged) ACTION_T_SET_SHEATH = 40, // Sheath (0-passive,1-melee,2-ranged)
ACTION_T_FORCE_DESPAWN = 41, // No Params ACTION_T_FORCE_DESPAWN = 41, // No Params
ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat,1-percent from max health)
ACTION_T_END, ACTION_T_END,
}; };
@ -373,6 +374,12 @@ struct CreatureEventAI_Action
{ {
uint32 sheath; uint32 sheath;
} set_sheath; } set_sheath;
// ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42
struct
{
uint32 hp_level;
uint32 is_percent;
} invincibility_hp_level;
// RAW // RAW
struct struct
{ {
@ -575,6 +582,7 @@ class MANGOS_DLL_SPEC CreatureEventAI : public CreatureAI
void AttackStart(Unit *who); void AttackStart(Unit *who);
void MoveInLineOfSight(Unit *who); void MoveInLineOfSight(Unit *who);
void SpellHit(Unit* pUnit, const SpellEntry* pSpell); void SpellHit(Unit* pUnit, const SpellEntry* pSpell);
void DamageTaken(Unit* done_by, uint32& damage);
void UpdateAI(const uint32 diff); void UpdateAI(const uint32 diff);
bool IsVisible(Unit *) const; bool IsVisible(Unit *) const;
void ReceiveEmote(Player* pPlayer, uint32 text_emote); void ReceiveEmote(Player* pPlayer, uint32 text_emote);
@ -604,10 +612,11 @@ class MANGOS_DLL_SPEC CreatureEventAI : public CreatureAI
bool bEmptyList; bool bEmptyList;
//Variables used by Events themselves //Variables used by Events themselves
uint8 Phase; //Current phase, max 32 phases uint8 Phase; // Current phase, max 32 phases
bool CombatMovementEnabled; //If we allow targeted movment gen (movement twoards top threat) bool CombatMovementEnabled; // If we allow targeted movment gen (movement twoards top threat)
bool MeleeEnabled; //If we allow melee auto attack bool MeleeEnabled; // If we allow melee auto attack
float AttackDistance; //Distance to attack from float AttackDistance; // Distance to attack from
float AttackAngle; //Angle of attack float AttackAngle; // Angle of attack
uint32 InvinceabilityHpLevel; // Minimal health level allowed at damage apply
}; };
#endif #endif

View file

@ -661,6 +661,16 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
action.set_sheath.sheath = SHEATH_STATE_UNARMED; action.set_sheath.sheath = SHEATH_STATE_UNARMED;
} }
break; break;
case ACTION_T_SET_INVINCIBILITY_HP_LEVEL:
if(action.invincibility_hp_level.is_percent)
{
if(action.invincibility_hp_level.hp_level > 100)
{
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses wrong percent value %u.", i, j+1, action.invincibility_hp_level.hp_level);
action.invincibility_hp_level.hp_level = 100;
}
}
break;
case ACTION_T_EVADE: //No Params case ACTION_T_EVADE: //No Params
case ACTION_T_FLEE_FOR_ASSIST: //No Params case ACTION_T_FLEE_FOR_ASSIST: //No Params
case ACTION_T_DIE: //No Params case ACTION_T_DIE: //No Params

View file

@ -1441,13 +1441,6 @@ struct SpellFocusObjectEntry
// 16 string flags, unused // 16 string flags, unused
}; };
// stored in SQL table
struct SpellThreatEntry
{
uint32 spellId;
int32 threat;
};
struct SpellRadiusEntry struct SpellRadiusEntry
{ {
uint32 ID; uint32 ID;

View file

@ -861,12 +861,14 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket)
recvPacket >> guid; recvPacket >> guid;
// cheating protection // cheating protection
/* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command.
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER);
if(!pCreature) if(!pCreature)
{ {
sLog.outDebug( "WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); sLog.outDebug( "WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
return; return;
} }
*/
uint32 slot = _player->GetBankBagSlotCount(); uint32 slot = _player->GetBankBagSlotCount();

View file

@ -157,6 +157,7 @@ bool ChatHandler::HandleReloadAllSpellCommand(const char*)
HandleReloadSpellLearnSpellCommand("a"); HandleReloadSpellLearnSpellCommand("a");
HandleReloadSpellProcEventCommand("a"); HandleReloadSpellProcEventCommand("a");
HandleReloadSpellBonusesCommand("a"); HandleReloadSpellBonusesCommand("a");
HandleReloadSpellProcItemEnchantCommand("a");
HandleReloadSpellScriptTargetCommand("a"); HandleReloadSpellScriptTargetCommand("a");
HandleReloadSpellTargetPositionCommand("a"); HandleReloadSpellTargetPositionCommand("a");
HandleReloadSpellThreatsCommand("a"); HandleReloadSpellThreatsCommand("a");
@ -528,6 +529,14 @@ bool ChatHandler::HandleReloadSpellBonusesCommand(const char*)
return true; return true;
} }
bool ChatHandler::HandleReloadSpellProcItemEnchantCommand(const char*)
{
sLog.outString( "Re-Loading Spell Proc Item Enchant..." );
spellmgr.LoadSpellProcItemEnchant();
SendGlobalSysMessage("DB table `spell_proc_item_enchant` (item enchantment ppm) reloaded.");
return true;
}
bool ChatHandler::HandleReloadSpellScriptTargetCommand(const char*) bool ChatHandler::HandleReloadSpellScriptTargetCommand(const char*)
{ {
sLog.outString( "Re-Loading SpellsScriptTarget..." ); sLog.outString( "Re-Loading SpellsScriptTarget..." );

View file

@ -962,10 +962,11 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recv_data)
uint32 size = adata->Data.size(); uint32 size = adata->Data.size();
ByteBuffer dest; uLongf destSize = compressBound(size);
dest.resize(size);
ByteBuffer dest;
dest.resize(destSize);
uLongf destSize = size;
if(size && compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK) if(size && compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK)
{ {
sLog.outDebug("RAD: Failed to compress account data"); sLog.outDebug("RAD: Failed to compress account data");

View file

@ -1918,13 +1918,19 @@ void Pet::CastPetAura(PetAura const* aura)
CastSpell(this, auraId, true); CastSpell(this, auraId, true);
} }
struct DoPetLearnSpell
{
DoPetLearnSpell(Pet& _pet) : pet(_pet) {}
void operator() (uint32 spell_id) { pet.learnSpell(spell_id); }
Pet& pet;
};
void Pet::learnSpellHighRank(uint32 spellid) void Pet::learnSpellHighRank(uint32 spellid)
{ {
learnSpell(spellid); learnSpell(spellid);
SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); DoPetLearnSpell worker(*this);
for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr) spellmgr.doForHighRanks(spellid,worker);
learnSpellHighRank(itr->second);
} }
void Pet::SynchronizeLevelWithOwner() void Pet::SynchronizeLevelWithOwner()

View file

@ -1275,8 +1275,8 @@ void Player::Update( uint32 p_time )
{ {
if (p_time >= m_DetectInvTimer) if (p_time >= m_DetectInvTimer)
{ {
m_DetectInvTimer = 3000;
HandleStealthedUnitsDetection(); HandleStealthedUnitsDetection();
m_DetectInvTimer = 3000;
} }
else else
m_DetectInvTimer -= p_time; m_DetectInvTimer -= p_time;
@ -6999,7 +6999,7 @@ void Player::CastItemCombatSpell(Unit* Target, WeaponAttackType attType)
if(spellData.SpellPPMRate) if(spellData.SpellPPMRate)
{ {
uint32 WeaponSpeed = GetAttackTime(attType); uint32 WeaponSpeed = proto->Delay;
chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate); chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate);
} }
else if(chance > 100.0f) else if(chance > 100.0f)
@ -7029,7 +7029,17 @@ void Player::CastItemCombatSpell(Unit* Target, WeaponAttackType attType)
continue; continue;
} }
float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance(); // Use first rank to access spell item enchant procs
float ppmRate = spellmgr.GetItemEnchantProcChance(spellInfo->Id);
float chance = ppmRate
? GetPPMProcChance(proto->Delay, ppmRate)
: pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
ApplySpellMod(spellInfo->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
ApplySpellMod(spellInfo->Id,SPELLMOD_FREQUENCY_OF_SUCCESS,chance);
if (roll_chance_f(chance)) if (roll_chance_f(chance))
{ {
if(IsPositiveSpell(pEnchant->spellid[s])) if(IsPositiveSpell(pEnchant->spellid[s]))
@ -16892,35 +16902,40 @@ void Player::HandleStealthedUnitsDetection()
cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap()); cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap());
cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap()); cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap());
for (std::list<Unit*>::iterator i = stealthedUnits.begin(); i != stealthedUnits.end();) for (std::list<Unit*>::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i)
{ {
if((*i)==this) if((*i)==this)
{
i = stealthedUnits.erase(i);
continue; continue;
}
if ((*i)->isVisibleForOrDetect(this,true)) bool hasAtClient = HaveAtClient((*i));
bool hasDetected = (*i)->isVisibleForOrDetect(this, true);
if (hasDetected)
{ {
if(!hasAtClient)
{
(*i)->SendUpdateToPlayer(this);
m_clientGUIDs.insert((*i)->GetGUID());
(*i)->SendUpdateToPlayer(this); #ifdef MANGOS_DEBUG
m_clientGUIDs.insert((*i)->GetGUID()); if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i));
#endif
#ifdef MANGOS_DEBUG // target aura duration for caster show only if target exist at caster client
if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) // send data at target visibility change (adding to client)
sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i)); if((*i)!=this && (*i)->isType(TYPEMASK_UNIT))
#endif SendAurasForTarget(*i);
}
// target aura duration for caster show only if target exist at caster client }
// send data at target visibility change (adding to client) else
if((*i)!=this && (*i)->isType(TYPEMASK_UNIT)) {
SendAurasForTarget(*i); if(hasAtClient)
{
i = stealthedUnits.erase(i); (*i)->DestroyForPlayer(this);
continue; m_clientGUIDs.erase((*i)->GetGUID());
}
} }
++i;
} }
} }
@ -19676,13 +19691,19 @@ bool Player::IsAllowUseFlyMountsHere() const
return v_map == 530 || v_map == 571 && HasSpell(54197); return v_map == 530 || v_map == 571 && HasSpell(54197);
} }
struct DoPlayerLearnSpell
{
DoPlayerLearnSpell(Player& _player) : player(_player) {}
void operator() (uint32 spell_id) { player.learnSpell(spell_id,false); }
Player& player;
};
void Player::learnSpellHighRank(uint32 spellid) void Player::learnSpellHighRank(uint32 spellid)
{ {
learnSpell(spellid,false); learnSpell(spellid,false);
SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); DoPlayerLearnSpell worker(*this);
for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr) spellmgr.doForHighRanks(spellid,worker);
learnSpellHighRank(itr->second);
} }
void Player::_LoadSkills() void Player::_LoadSkills()

View file

@ -2121,7 +2121,6 @@ class MANGOS_DLL_SPEC Player : public Unit
void UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow); void UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
// Stealth detection system // Stealth detection system
uint32 m_DetectInvTimer;
void HandleStealthedUnitsDetection(); void HandleStealthedUnitsDetection();
uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; uint8 m_forced_speed_changes[MAX_MOVE_TYPE];
@ -2476,6 +2475,8 @@ class MANGOS_DLL_SPEC Player : public Unit
bool m_bCanDelayTeleport; bool m_bCanDelayTeleport;
bool m_bHasDelayedTeleport; bool m_bHasDelayedTeleport;
uint32 m_DetectInvTimer;
// Temporary removed pet cache // Temporary removed pet cache
uint32 m_temporaryUnsummonedPetNumber; uint32 m_temporaryUnsummonedPetNumber;
uint32 m_oldpetspell; uint32 m_oldpetspell;

View file

@ -104,7 +104,9 @@ void LoadSkillDiscoveryTable()
{ {
if (reportedReqSpells.count(reqSkillOrSpell)==0) if (reportedReqSpells.count(reqSkillOrSpell)==0)
{ {
sLog.outErrorDb("Spell (ID: %u) not have have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc and not 100%% chance random discovery ability but listed for spellId %u (and maybe more) in `skill_discovery_template` table",reqSkillOrSpell,spellId); sLog.outErrorDb("Spell (ID: %u) not have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc"
" and not 100%% chance random discovery ability but listed for spellId %u (and maybe more) in `skill_discovery_template` table",
reqSkillOrSpell,spellId);
reportedReqSpells.insert(reqSkillOrSpell); reportedReqSpells.insert(reqSkillOrSpell);
} }
continue; continue;
@ -143,6 +145,21 @@ void LoadSkillDiscoveryTable()
sLog.outString( ">> Loaded %u skill discovery definitions", count ); sLog.outString( ">> Loaded %u skill discovery definitions", count );
if(!ssNonDiscoverableEntries.str().empty()) if(!ssNonDiscoverableEntries.str().empty())
sLog.outErrorDb("Some items can't be successfully discovered: have in chance field value < 0.000001 in `skill_discovery_template` DB table . List:\n%s",ssNonDiscoverableEntries.str().c_str()); sLog.outErrorDb("Some items can't be successfully discovered: have in chance field value < 0.000001 in `skill_discovery_template` DB table . List:\n%s",ssNonDiscoverableEntries.str().c_str());
// report about empty data for explicit discovery spells
for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
{
SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell_id);
if(!spellEntry)
continue;
// skip not explicit discovery spells
if (!IsExplicitDiscoverySpell(spellEntry))
continue;
if(SkillDiscoveryStore.find(spell_id)==SkillDiscoveryStore.end())
sLog.outErrorDb("Spell (ID: %u) is 100%% chance random discovery ability but not have data in `skill_discovery_template` table",spell_id);
}
} }
uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player) uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player)

View file

@ -1690,16 +1690,16 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,UnitList& TagUnitMap)
case TARGET_ALL_PARTY_AROUND_CASTER: case TARGET_ALL_PARTY_AROUND_CASTER:
case TARGET_ALL_PARTY_AROUND_CASTER_2: case TARGET_ALL_PARTY_AROUND_CASTER_2:
case TARGET_ALL_PARTY: case TARGET_ALL_PARTY:
FillRaidOrPartyTargets(TagUnitMap,m_caster,radius,false,true,true); FillRaidOrPartyTargets(TagUnitMap, m_caster, m_caster, radius, false, true, true);
break; break;
case TARGET_ALL_RAID_AROUND_CASTER: case TARGET_ALL_RAID_AROUND_CASTER:
{ {
if(m_spellInfo->Id == 57669) // Replenishment (special target selection) if(m_spellInfo->Id == 57669) // Replenishment (special target selection)
FillRaidOrPartyManaPriorityTargets(TagUnitMap, m_caster, radius, 10, true, false, false); FillRaidOrPartyManaPriorityTargets(TagUnitMap, m_caster, m_caster, radius, 10, true, false, false);
else if (m_spellInfo->Id==52759) //Ancestral Awakening (special target selection) else if (m_spellInfo->Id==52759) //Ancestral Awakening (special target selection)
FillRaidOrPartyHealthPriorityTargets(TagUnitMap, m_caster, radius, 1, true, false, false); FillRaidOrPartyHealthPriorityTargets(TagUnitMap, m_caster, m_caster, radius, 1, true, false, false);
else else
FillRaidOrPartyTargets(TagUnitMap, m_caster, radius, true, true, true); FillRaidOrPartyTargets(TagUnitMap, m_caster, m_caster, radius, true, true, true);
break; break;
} }
case TARGET_SINGLE_FRIEND: case TARGET_SINGLE_FRIEND:
@ -1728,12 +1728,23 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,UnitList& TagUnitMap)
// special target order // special target order
if (m_spellInfo->Id==64904) // Hymn of Hope if (m_spellInfo->Id==64904) // Hymn of Hope
// target amount stored in parent spell dummy effect but hard for access // target amount stored in parent spell dummy effect but hard for access
FillRaidOrPartyManaPriorityTargets(TagUnitMap, m_caster, radius, 3, true, false, false); FillRaidOrPartyManaPriorityTargets(TagUnitMap, m_caster, m_caster, radius, 3, true, false, false);
else else
FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY); FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY);
break; break;
case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: case TARGET_ALL_FRIENDLY_UNITS_IN_AREA:
FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_DEST_CENTER, SPELL_TARGETS_FRIENDLY); // Wild Growth
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellIconID == 2864)
{
Unit* target = m_targets.getUnitTarget();
if(!target)
target = m_caster;
uint32 count = CalculateDamage(2,m_caster); // stored in dummy effect, affected by mods
FillRaidOrPartyHealthPriorityTargets(TagUnitMap, m_caster, target, radius, count, true, false, true);
}
else
FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_DEST_CENTER, SPELL_TARGETS_FRIENDLY);
break; break;
// TARGET_SINGLE_PARTY means that the spells can only be casted on a party member and not on the caster (some seals, fire shield from imp, etc..) // TARGET_SINGLE_PARTY means that the spells can only be casted on a party member and not on the caster (some seals, fire shield from imp, etc..)
case TARGET_SINGLE_PARTY: case TARGET_SINGLE_PARTY:
@ -3555,13 +3566,14 @@ void Spell::HandleThreatSpells(uint32 spellId)
if(!m_targets.getUnitTarget()->CanHaveThreatList()) if(!m_targets.getUnitTarget()->CanHaveThreatList())
return; return;
SpellThreatEntry const *threatSpell = sSpellThreatStore.LookupEntry<SpellThreatEntry>(spellId); uint16 threat = spellmgr.GetSpellThreat(spellId);
if(!threatSpell)
if(!threat)
return; return;
m_targets.getUnitTarget()->AddThreat(m_caster, float(threatSpell->threat)); m_targets.getUnitTarget()->AddThreat(m_caster, float(threat));
DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat); DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threat);
} }
void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float DamageMultiplier) void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i, float DamageMultiplier)
@ -5751,14 +5763,14 @@ void Spell::FillAreaTargets( UnitList& TagUnitMap, float x, float y, float radiu
cell_lock->Visit(cell_lock, grid_notifier, *m_caster->GetMap()); cell_lock->Visit(cell_lock, grid_notifier, *m_caster->GetMap());
} }
void Spell::FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* target, float radius, bool raid, bool withPets, bool withcaster ) void Spell::FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, bool raid, bool withPets, bool withcaster )
{ {
Player *pTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself(); Player *pMember = member->GetCharmerOrOwnerPlayerOrPlayerItself();
Group *pGroup = pTarget ? pTarget->GetGroup() : NULL; Group *pGroup = pMember ? pMember->GetGroup() : NULL;
if (pGroup) if (pGroup)
{ {
uint8 subgroup = pTarget->GetSubGroup(); uint8 subgroup = pMember->GetSubGroup();
for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
{ {
@ -5768,36 +5780,36 @@ void Spell::FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* target, float ra
if (Target && (raid || subgroup==Target->GetSubGroup()) if (Target && (raid || subgroup==Target->GetSubGroup())
&& !m_caster->IsHostileTo(Target)) && !m_caster->IsHostileTo(Target))
{ {
if (Target==m_caster && withcaster || if ((Target==center || center->IsWithinDistInMap(Target, radius)) &&
Target!=m_caster && m_caster->IsWithinDistInMap(Target, radius)) (withcaster || Target != m_caster))
TagUnitMap.push_back(Target); TagUnitMap.push_back(Target);
if (withPets) if (withPets)
if (Pet* pet = Target->GetPet()) if (Pet* pet = Target->GetPet())
if (pet==m_caster && withcaster || if ((pet==center || center->IsWithinDistInMap(pet, radius)) &&
pet!=m_caster && m_caster->IsWithinDistInMap(pet, radius)) (withcaster || pet != m_caster))
TagUnitMap.push_back(pet); TagUnitMap.push_back(pet);
} }
} }
} }
else else
{ {
Unit* ownerOrSelf = pTarget ? pTarget : target->GetCharmerOrOwnerOrSelf(); Unit* ownerOrSelf = pMember ? pMember : member->GetCharmerOrOwnerOrSelf();
if (ownerOrSelf==m_caster && withcaster || if ((ownerOrSelf==center || center->IsWithinDistInMap(ownerOrSelf, radius)) &&
ownerOrSelf!=m_caster && m_caster->IsWithinDistInMap(ownerOrSelf, radius)) (withcaster || ownerOrSelf != m_caster))
TagUnitMap.push_back(ownerOrSelf); TagUnitMap.push_back(ownerOrSelf);
if (withPets) if (withPets)
if (Pet* pet = ownerOrSelf->GetPet()) if (Pet* pet = ownerOrSelf->GetPet())
if (pet==m_caster && withcaster || if ((pet==center || center->IsWithinDistInMap(pet, radius)) &&
pet!=m_caster && m_caster->IsWithinDistInMap(pet, radius)) (withcaster || pet != m_caster))
TagUnitMap.push_back(pet); TagUnitMap.push_back(pet);
} }
} }
void Spell::FillRaidOrPartyManaPriorityTargets( UnitList &TagUnitMap, Unit* target, float radius, uint32 count, bool raid, bool withPets, bool withCaster ) void Spell::FillRaidOrPartyManaPriorityTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withCaster )
{ {
FillRaidOrPartyTargets(TagUnitMap,target,radius,raid,withPets,withCaster); FillRaidOrPartyTargets(TagUnitMap, member, center, radius, raid, withPets, withCaster);
PrioritizeManaUnitQueue manaUsers; PrioritizeManaUnitQueue manaUsers;
for(UnitList::const_iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end() && manaUsers.size() < count; ++itr) for(UnitList::const_iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end() && manaUsers.size() < count; ++itr)
@ -5812,9 +5824,9 @@ void Spell::FillRaidOrPartyManaPriorityTargets( UnitList &TagUnitMap, Unit* targ
} }
} }
void Spell::FillRaidOrPartyHealthPriorityTargets( UnitList &TagUnitMap, Unit* target, float radius, uint32 count, bool raid, bool withPets, bool withCaster ) void Spell::FillRaidOrPartyHealthPriorityTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withCaster )
{ {
FillRaidOrPartyTargets(TagUnitMap,target,radius,raid,withPets,withCaster); FillRaidOrPartyTargets(TagUnitMap, member, center, radius, raid, withPets, withCaster);
PrioritizeHealthUnitQueue healthQueue; PrioritizeHealthUnitQueue healthQueue;
for(UnitList::const_iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end() && healthQueue.size() < count; ++itr) for(UnitList::const_iterator itr = TagUnitMap.begin(); itr != TagUnitMap.end() && healthQueue.size() < count; ++itr)

View file

@ -369,9 +369,9 @@ class Spell
void SetTargetMap(uint32 i,uint32 cur,UnitList& TagUnitMap); void SetTargetMap(uint32 i,uint32 cur,UnitList& TagUnitMap);
void FillAreaTargets( UnitList& TagUnitMap, float x, float y, float radius, SpellNotifyPushType pushType, SpellTargets spellTargets ); void FillAreaTargets( UnitList& TagUnitMap, float x, float y, float radius, SpellNotifyPushType pushType, SpellTargets spellTargets );
void FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* target, float radius, bool raid, bool withPets, bool withcaster ); void FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, bool raid, bool withPets, bool withcaster );
void FillRaidOrPartyManaPriorityTargets( UnitList &TagUnitMap, Unit* target, float radius, uint32 count, bool raid, bool withPets, bool withcaster ); void FillRaidOrPartyManaPriorityTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withcaster );
void FillRaidOrPartyHealthPriorityTargets( UnitList &TagUnitMap, Unit* target, float radius, uint32 count, bool raid, bool withPets, bool withcaster ); void FillRaidOrPartyHealthPriorityTargets( UnitList &TagUnitMap, Unit* member, Unit* center, float radius, uint32 count, bool raid, bool withPets, bool withcaster );
template<typename T> WorldObject* FindCorpseUsing(); template<typename T> WorldObject* FindCorpseUsing();

View file

@ -5788,6 +5788,23 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real)
m_modifier.m_amount += (int32)DoneActualBenefit; m_modifier.m_amount += (int32)DoneActualBenefit;
} }
// Ice Barrier (remove effect from Shattered Barrier)
if(!apply && 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 (!apply && caster && if (!apply && 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 &&
@ -6079,8 +6096,18 @@ void Aura::PeriodicTick()
if(m_modifier.m_auraname==SPELL_AURA_OBS_MOD_HEALTH) if(m_modifier.m_auraname==SPELL_AURA_OBS_MOD_HEALTH)
pdamage = uint32(m_target->GetMaxHealth() * amount / 100); pdamage = uint32(m_target->GetMaxHealth() * amount / 100);
else else
{
pdamage = amount; pdamage = amount;
// Wild Growth (1/7 - 6 + 2*ramainTicks) %
if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellIconID == 2864)
{
int32 ticks = m_maxduration/m_modifier.periodictime;
int32 remainingTicks = int32(float(m_duration) / m_modifier.periodictime + 0.5);
pdamage = int32(pdamage) + int32(amount)*ticks*(-6+2*remainingTicks)/100;
}
}
pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount()); pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount());
// This method can modify pdamage // This method can modify pdamage
@ -6954,9 +6981,7 @@ void Aura::UnregisterSingleCastAura()
{ {
if (IsSingleTarget()) if (IsSingleTarget())
{ {
Unit* caster = NULL; if(Unit* caster = GetCaster())
caster = GetCaster();
if(caster)
{ {
caster->GetSingleCastAuras().remove(this); caster->GetSingleCastAuras().remove(this);
} }

View file

@ -1831,7 +1831,7 @@ void Spell::EffectDummy(uint32 i)
break; break;
case SPELLFAMILY_DEATHKNIGHT: case SPELLFAMILY_DEATHKNIGHT:
// Death Coil // Death Coil
if(m_spellInfo->SpellFamilyFlags & UI64LIT(0x002000)) if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x002000))
{ {
if(m_caster->IsFriendlyTo(unitTarget)) if(m_caster->IsFriendlyTo(unitTarget))
{ {
@ -1848,6 +1848,12 @@ void Spell::EffectDummy(uint32 i)
} }
return; return;
} }
// Hungering Cold
else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000100000000000))
{
m_caster->CastSpell(m_caster, 51209, true);
return;
}
break; break;
} }
@ -2537,8 +2543,9 @@ void Spell::EffectHeal( uint32 /*i*/ )
Aura *targetAura = NULL; Aura *targetAura = NULL;
for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
{ {
if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID &&
&& ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) ) // Regrowth or Rejuvenation 0x40 | 0x10
((*i)->GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000000050)))
{ {
if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration()) if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
targetAura = *i; targetAura = *i;
@ -2560,7 +2567,10 @@ void Spell::EffectHeal( uint32 /*i*/ )
int32 tickheal = caster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT); int32 tickheal = caster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT);
int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx]; int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
// Glyph of Swiftmend
if(!caster->HasAura(54824))
unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
addhealth += tickheal * tickcount; addhealth += tickheal * tickcount;
} }
@ -5026,6 +5036,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
case 61177: // Northrend Inscription Research case 61177: // Northrend Inscription Research
case 61288: // Minor Inscription Research case 61288: // Minor Inscription Research
case 61756: // Northrend Inscription Research (FAST QA VERSION) case 61756: // Northrend Inscription Research (FAST QA VERSION)
case 64323: // Book of Glyph Mastery
{ {
if(m_caster->GetTypeId() != TYPEID_PLAYER) if(m_caster->GetTypeId() != TYPEID_PLAYER)
return; return;

View file

@ -700,6 +700,13 @@ bool SpellMgr::IsAffectedByMod(SpellEntry const *spellInfo, SpellModifier *mod)
return false; return false;
} }
struct DoSpellProcEvent
{
DoSpellProcEvent(SpellProcEventEntry const& _spe) : spe(_spe) {}
void operator() (uint32 spell_id) { spellmgr.mSpellProcEventMap[spell_id] = spe; }
SpellProcEventEntry const& spe;
};
void SpellMgr::LoadSpellProcEvents() void SpellMgr::LoadSpellProcEvents()
{ {
mSpellProcEventMap.clear(); // need for reload case mSpellProcEventMap.clear(); // need for reload case
@ -734,6 +741,15 @@ void SpellMgr::LoadSpellProcEvents()
continue; continue;
} }
uint32 first_id = GetFirstSpellInChain(entry);
if ( first_id != entry )
{
sLog.outErrorDb("Spell %u listed in `spell_proc_event` is not first rank (%u) in chain", entry, first_id);
// prevent loading since it won't have an effect anyway
continue;
}
SpellProcEventEntry spe; SpellProcEventEntry spe;
spe.schoolMask = fields[1].GetUInt32(); spe.schoolMask = fields[1].GetUInt32();
@ -748,6 +764,10 @@ void SpellMgr::LoadSpellProcEvents()
mSpellProcEventMap[entry] = spe; mSpellProcEventMap[entry] = spe;
// also add to high ranks
DoSpellProcEvent worker(spe);
doForHighRanks(entry,worker);
if (spell->procFlags==0) if (spell->procFlags==0)
{ {
if (spe.procFlags == 0) if (spe.procFlags == 0)
@ -769,6 +789,83 @@ void SpellMgr::LoadSpellProcEvents()
sLog.outString( ">> Loaded %u extra spell proc event conditions", count ); sLog.outString( ">> Loaded %u extra spell proc event conditions", count );
} }
struct DoSpellProcItemEnchant
{
DoSpellProcItemEnchant(float _ppm) : ppm(_ppm) {}
void operator() (uint32 spell_id) { spellmgr.mSpellProcItemEnchantMap[spell_id] = ppm; }
float ppm;
};
void SpellMgr::LoadSpellProcItemEnchant()
{
mSpellProcItemEnchantMap.clear(); // need for reload case
uint32 count = 0;
// 0 1
QueryResult *result = WorldDatabase.Query("SELECT entry, ppmRate FROM spell_proc_item_enchant");
if( !result )
{
barGoLink bar( 1 );
bar.step();
sLog.outString();
sLog.outString( ">> Loaded %u proc item enchant definitions", count );
return;
}
barGoLink bar( result->GetRowCount() );
do
{
Field *fields = result->Fetch();
bar.step();
uint32 entry = fields[0].GetUInt32();
float ppmRate = fields[1].GetFloat();
SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
if (!spellInfo)
{
sLog.outErrorDb("Spell %u listed in `spell_proc_item_enchant` does not exist", entry);
continue;
}
uint32 first_id = GetFirstSpellInChain(entry);
if ( first_id != entry )
{
sLog.outErrorDb("Spell %u listed in `spell_proc_item_enchant` is not first rank (%u) in chain", entry, first_id);
// prevent loading since it won't have an effect anyway
continue;
}
mSpellProcItemEnchantMap[entry] = ppmRate;
// also add to high ranks
DoSpellProcItemEnchant worker(ppmRate);
doForHighRanks(entry,worker);
++count;
} while( result->NextRow() );
delete result;
sLog.outString();
sLog.outString( ">> Loaded %u proc item enchant definitions", count );
}
struct DoSpellBonusess
{
DoSpellBonusess(SpellBonusEntry const& _spellBonus) : spellBonus(_spellBonus) {}
void operator() (uint32 spell_id) { spellmgr.mSpellBonusMap[spell_id] = spellBonus; }
SpellBonusEntry const& spellBonus;
};
void SpellMgr::LoadSpellBonusess() void SpellMgr::LoadSpellBonusess()
{ {
mSpellBonusMap.clear(); // need for reload case mSpellBonusMap.clear(); // need for reload case
@ -791,13 +888,22 @@ void SpellMgr::LoadSpellBonusess()
bar.step(); bar.step();
uint32 entry = fields[0].GetUInt32(); uint32 entry = fields[0].GetUInt32();
const SpellEntry *spell = sSpellStore.LookupEntry(entry); SpellEntry const* spell = sSpellStore.LookupEntry(entry);
if (!spell) if (!spell)
{ {
sLog.outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry); sLog.outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry);
continue; continue;
} }
uint32 first_id = GetFirstSpellInChain(entry);
if ( first_id != entry )
{
sLog.outErrorDb("Spell %u listed in `spell_bonus_data` is not first rank (%u) in chain", entry, first_id);
// prevent loading since it won't have an effect anyway
continue;
}
SpellBonusEntry sbe; SpellBonusEntry sbe;
sbe.direct_damage = fields[1].GetFloat(); sbe.direct_damage = fields[1].GetFloat();
@ -805,6 +911,11 @@ void SpellMgr::LoadSpellBonusess()
sbe.ap_bonus = fields[3].GetFloat(); sbe.ap_bonus = fields[3].GetFloat();
mSpellBonusMap[entry] = sbe; mSpellBonusMap[entry] = sbe;
// also add to high ranks
DoSpellBonusess worker(sbe);
doForHighRanks(entry,worker);
} while( result->NextRow() ); } while( result->NextRow() );
delete result; delete result;
@ -932,12 +1043,50 @@ void SpellMgr::LoadSpellElixirs()
void SpellMgr::LoadSpellThreats() void SpellMgr::LoadSpellThreats()
{ {
sSpellThreatStore.Free(); // for reload mSpellThreatMap.clear(); // need for reload case
sSpellThreatStore.Load(); uint32 count = 0;
// 0 1
QueryResult *result = WorldDatabase.Query("SELECT entry, Threat FROM spell_threat");
if( !result )
{
barGoLink bar( 1 );
bar.step();
sLog.outString();
sLog.outString( ">> Loaded %u aggro generating spells", count );
return;
}
barGoLink bar( result->GetRowCount() );
do
{
Field *fields = result->Fetch();
bar.step();
uint32 entry = fields[0].GetUInt32();
uint16 Threat = fields[1].GetUInt16();
if (!sSpellStore.LookupEntry(entry))
{
sLog.outErrorDb("Spell %u listed in `spell_threat` does not exist", entry);
continue;
}
mSpellThreatMap[entry] = Threat;
++count;
} while( result->NextRow() );
delete result;
sLog.outString( ">> Loaded %u aggro generating spells", sSpellThreatStore.RecordCount );
sLog.outString(); sLog.outString();
sLog.outString( ">> Loaded %u aggro generating spells", count );
} }
bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const
@ -2858,16 +3007,11 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
// Explicit Diminishing Groups // Explicit Diminishing Groups
switch(spellproto->SpellFamilyName) switch(spellproto->SpellFamilyName)
{ {
case SPELLFAMILY_MAGE: case SPELLFAMILY_GENERIC:
{ // some generic arena related spells have by some strange reason MECHANIC_TURN
// Shattered Barrier (triggered so doesn't share with Frost Nova) if (spellproto->Mechanic == MECHANIC_TURN)
if (spellproto->SpellFamilyFlags & UI64LIT(0x00000080000)) return DIMINISHING_NONE;
return DIMINISHING_TRIGGER_ROOT;
// Frost Nova / Freeze (Water Elemental)
else if (spellproto->SpellIconID == 193)
return DIMINISHING_CONTROL_ROOT;
break; break;
}
case SPELLFAMILY_ROGUE: case SPELLFAMILY_ROGUE:
{ {
// Blind // Blind

View file

@ -36,8 +36,6 @@ class Player;
class Spell; class Spell;
struct SpellModifier; struct SpellModifier;
extern SQLStorage sSpellThreatStore;
// only used in code // only used in code
enum SpellCategories enum SpellCategories
{ {
@ -155,7 +153,9 @@ inline bool IsElementalShield(SpellEntry const *spellInfo)
inline bool IsExplicitDiscoverySpell(SpellEntry const *spellInfo) inline bool IsExplicitDiscoverySpell(SpellEntry const *spellInfo)
{ {
return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_RANDOM_ITEM && spellInfo->Effect[1]==SPELL_EFFECT_SCRIPT_EFFECT; return spellInfo->Effect[0] == SPELL_EFFECT_CREATE_RANDOM_ITEM
&& spellInfo->Effect[1] == SPELL_EFFECT_SCRIPT_EFFECT
|| spellInfo->Id == 64323; // Book of Glyph Mastery (Effect0==SPELL_EFFECT_SCRIPT_EFFECT without any other data)
} }
inline bool IsLootCraftingSpell(SpellEntry const *spellInfo) inline bool IsLootCraftingSpell(SpellEntry const *spellInfo)
@ -447,6 +447,8 @@ typedef UNORDERED_MAP<uint32, SpellBonusEntry> SpellBonusMap;
#define ELIXIR_SHATTRATH_MASK 0x8 #define ELIXIR_SHATTRATH_MASK 0x8
typedef std::map<uint32, uint8> SpellElixirMap; typedef std::map<uint32, uint8> SpellElixirMap;
typedef std::map<uint32, float> SpellProcItemEnchantMap;
typedef std::map<uint32, uint16> SpellThreatMap;
// Spell script target related declarations (accessed using SpellMgr functions) // Spell script target related declarations (accessed using SpellMgr functions)
enum SpellTargetType enum SpellTargetType
@ -626,6 +628,10 @@ inline bool IsProfessionOrRidingSkill(uint32 skill)
class SpellMgr class SpellMgr
{ {
friend struct DoSpellBonusess;
friend struct DoSpellProcEvent;
friend struct DoSpellProcItemEnchant;
// Constructors // Constructors
public: public:
SpellMgr(); SpellMgr();
@ -660,6 +666,15 @@ class SpellMgr
return SPELL_NORMAL; return SPELL_NORMAL;
} }
uint16 GetSpellThreat(uint32 spellid) const
{
SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellid);
if(itr==mSpellThreatMap.end())
return 0;
return itr->second;
}
// Spell proc events // Spell proc events
SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const
{ {
@ -669,6 +684,16 @@ class SpellMgr
return NULL; return NULL;
} }
// Spell procs from item enchants
float GetItemEnchantProcChance(uint32 spellid) const
{
SpellProcItemEnchantMap::const_iterator itr = mSpellProcItemEnchantMap.find(spellid);
if(itr==mSpellProcItemEnchantMap.end())
return 0.0f;
return itr->second;
}
static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active); static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active);
// Spell bonus data // Spell bonus data
@ -678,13 +703,7 @@ class SpellMgr
SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId); SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId);
if( itr != mSpellBonusMap.end( ) ) if( itr != mSpellBonusMap.end( ) )
return &itr->second; return &itr->second;
// Not found, try lookup for 1 spell rank if exist
if (uint32 rank_1 = GetFirstSpellInChain(spellId))
{
SpellBonusMap::const_iterator itr2 = mSpellBonusMap.find(rank_1);
if( itr2 != mSpellBonusMap.end( ) )
return &itr2->second;
}
return NULL; return NULL;
} }
@ -725,6 +744,17 @@ class SpellMgr
SpellChainMapNext const& GetSpellChainNext() const { return mSpellChainsNext; } SpellChainMapNext const& GetSpellChainNext() const { return mSpellChainsNext; }
template<typename Worker>
void doForHighRanks(uint32 spellid, Worker& worker)
{
SpellChainMapNext const& nextMap = GetSpellChainNext();
for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr)
{
worker(itr->second);
doForHighRanks(itr->second,worker);
}
}
// Note: not use rank for compare to spell ranks: spell chains isn't linear order // Note: not use rank for compare to spell ranks: spell chains isn't linear order
// Use IsHighRankOfSpell instead // Use IsHighRankOfSpell instead
uint8 GetSpellRank(uint32 spell_id) const uint8 GetSpellRank(uint32 spell_id) const
@ -896,6 +926,7 @@ class SpellMgr
void LoadSpellScriptTarget(); void LoadSpellScriptTarget();
void LoadSpellElixirs(); void LoadSpellElixirs();
void LoadSpellProcEvents(); void LoadSpellProcEvents();
void LoadSpellProcItemEnchant();
void LoadSpellBonusess(); void LoadSpellBonusess();
void LoadSpellTargetPositions(); void LoadSpellTargetPositions();
void LoadSpellThreats(); void LoadSpellThreats();
@ -913,7 +944,9 @@ class SpellMgr
SpellLearnSpellMap mSpellLearnSpells; SpellLearnSpellMap mSpellLearnSpells;
SpellTargetPositionMap mSpellTargetPositions; SpellTargetPositionMap mSpellTargetPositions;
SpellElixirMap mSpellElixirs; SpellElixirMap mSpellElixirs;
SpellThreatMap mSpellThreatMap;
SpellProcEventMap mSpellProcEventMap; SpellProcEventMap mSpellProcEventMap;
SpellProcItemEnchantMap mSpellProcItemEnchantMap;
SpellBonusMap mSpellBonusMap; SpellBonusMap mSpellBonusMap;
SkillLineAbilityMap mSkillLineAbilityMap; SkillLineAbilityMap mSkillLineAbilityMap;
SpellPetAuraMap mSpellPetAuraMap; SpellPetAuraMap mSpellPetAuraMap;

View file

@ -803,7 +803,9 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType)
UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType); /* difference in AP between current attack power and base value from DB */
float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f);
float base_pct = GetModifierValue(unitMod, BASE_PCT); float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE); float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT); float total_pct = GetModifierValue(unitMod, TOTAL_PCT);

View file

@ -3892,10 +3892,10 @@ void Unit::RemoveNotOwnSingleTargetAuras()
for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end(); ) for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end(); )
{ {
Aura* aura = *iter; Aura* aura = *iter;
if (aura->GetTarget()!=this) if (aura->GetTarget() != this)
{ {
scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveAura scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveAura
aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetEffIndex()); aura->GetTarget()->RemoveAura(aura);
iter = scAuras.begin(); iter = scAuras.begin();
} }
else else
@ -3904,6 +3904,21 @@ void Unit::RemoveNotOwnSingleTargetAuras()
} }
void Unit::RemoveAura(Aura* aura)
{
AuraMap::iterator i = m_Auras.lower_bound(spellEffectPair(aura->GetId(), aura->GetEffIndex()));
AuraMap::iterator upperBound = m_Auras.upper_bound(spellEffectPair(aura->GetId(), aura->GetEffIndex()));
for (; i != upperBound; ++i)
{
if (i->second == aura)
{
RemoveAura(i);
return;
}
}
sLog.outDebug("Trying to remove aura id %u effect %u by pointer but aura not found on target", aura->GetId(), aura->GetEffIndex());
}
void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
{ {
Aura* Aur = i->second; Aura* Aur = i->second;
@ -4502,13 +4517,12 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 25997; triggered_spell_id = 25997;
break; break;
} }
// Sweeping Strikes // Sweeping Strikes (NPC spells may be)
case 12328:
case 18765: case 18765:
case 35429: case 35429:
{ {
// prevent chain of triggered spell from same triggered spell // prevent chain of triggered spell from same triggered spell
if(procSpell && procSpell->Id==26654) if(procSpell && procSpell->Id == 26654)
return false; return false;
target = SelectNearbyTarget(); target = SelectNearbyTarget();
@ -5034,6 +5048,21 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
basepoints0 = GetShieldBlockValue() * triggerAmount / 100; basepoints0 = GetShieldBlockValue() * triggerAmount / 100;
break; break;
} }
// Sweeping Strikes
if (dummySpell->Id == 12328)
{
// prevent chain of triggered spell from same triggered spell
if(procSpell && procSpell->Id == 26654)
return false;
target = SelectNearbyTarget();
if(!target)
return false;
triggered_spell_id = 26654;
break;
}
break; break;
} }
case SPELLFAMILY_WARLOCK: case SPELLFAMILY_WARLOCK:
@ -7881,7 +7910,8 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
} }
else // Tundra Stalker else // Tundra Stalker
{ {
if (pVictim->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0400000000000000))) // Frost Fever (target debuff)
if (pVictim->GetAura(SPELL_AURA_MOD_HASTE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0000000000000000), 0x00000002))
DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f; DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
break; break;
} }
@ -8896,8 +8926,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const
{ {
// proc per minute chance calculation // proc per minute chance calculation
if (PPM <= 0) return 0.0f; if (PPM <= 0) return 0.0f;
uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) return WeaponSpeed * PPM / 600.0f; // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
return result;
} }
void Unit::Mount(uint32 mount) void Unit::Mount(uint32 mount)
@ -9232,13 +9261,11 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList,
// NOW ONLY STEALTH CASE // NOW ONLY STEALTH CASE
// stealth and detected and visible for some seconds
if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->m_DetectInvTimer > 300 && ((Player*)u)->HaveAtClient(this))
return true;
//if in non-detect mode then invisible for unit //if in non-detect mode then invisible for unit
//mobs always detect players (detect == true)... return 'false' for those mobs which have (detect == false)
//players detect players only in Player::HandleStealthedUnitsDetection()
if (!detect) if (!detect)
return false; return (u->GetTypeId() == TYPEID_PLAYER) ? ((Player*)u)->HaveAtClient(this) : false;
// Special cases // Special cases
@ -9254,21 +9281,13 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList,
if (u->hasUnitState(UNIT_STAT_STUNNED) && (u != this)) if (u->hasUnitState(UNIT_STAT_STUNNED) && (u != this))
return false; return false;
// Creature can detect target only in aggro radius // set max ditance
if(u->GetTypeId() != TYPEID_PLAYER) float visibleDistance = (u->GetTypeId() == TYPEID_PLAYER) ? MAX_PLAYER_STEALTH_DETECT_RANGE : ((Creature const*)u)->GetAttackDistance(this);
{
//Always invisible from back and out of aggro range //Always invisible from back (when stealth detection is on), also filter max distance cases
bool isInFront = u->isInFrontInMap(this,((Creature const*)u)->GetAttackDistance(this)); bool isInFront = u->isInFrontInMap(this, visibleDistance);
if(!isInFront) if(!isInFront)
return false; return false;
}
else
{
//Always invisible from back
bool isInFront = u->isInFrontInMap(this,(GetTypeId()==TYPEID_PLAYER || GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
if(!isInFront)
return false;
}
// if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
if(!u->HasAuraType(SPELL_AURA_DETECT_STEALTH)) if(!u->HasAuraType(SPELL_AURA_DETECT_STEALTH))
@ -9276,7 +9295,7 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList,
//Calculation if target is in front //Calculation if target is in front
//Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
float visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/100.0f); visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/100.0f);
//Visible distance is modified by //Visible distance is modified by
//-Level Diff (every level diff = 1.0f in visible distance) //-Level Diff (every level diff = 1.0f in visible distance)
@ -9290,7 +9309,9 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList,
//-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
//based on wowwiki every 5 mod we have 1 more level diff in calculation //based on wowwiki every 5 mod we have 1 more level diff in calculation
visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT)) - stealthMod)/5.0f; visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT)) - stealthMod)/5.0f;
visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance;
// recheck new distance
if(visibleDistance <= 0 || !IsWithinDist(u,visibleDistance)) if(visibleDistance <= 0 || !IsWithinDist(u,visibleDistance))
return false; return false;
} }
@ -11710,7 +11731,10 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura* aura, SpellEntry con
} }
// Apply chance modifer aura // Apply chance modifer aura
if(Player* modOwner = GetSpellModOwner()) if(Player* modOwner = GetSpellModOwner())
{
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance); modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_FREQUENCY_OF_SUCCESS,chance);
}
return roll_chance_f(chance); return roll_chance_f(chance);
} }

View file

@ -102,14 +102,15 @@ enum SpellModOp
SPELLMOD_CRIT_DAMAGE_BONUS = 15, SPELLMOD_CRIT_DAMAGE_BONUS = 15,
SPELLMOD_RESIST_MISS_CHANCE = 16, SPELLMOD_RESIST_MISS_CHANCE = 16,
SPELLMOD_JUMP_TARGETS = 17, SPELLMOD_JUMP_TARGETS = 17,
SPELLMOD_CHANCE_OF_SUCCESS = 18, SPELLMOD_CHANCE_OF_SUCCESS = 18, // Only used with SPELL_AURA_ADD_FLAT_MODIFIER and affects proc spells
SPELLMOD_ACTIVATION_TIME = 19, SPELLMOD_ACTIVATION_TIME = 19,
SPELLMOD_EFFECT_PAST_FIRST = 20, SPELLMOD_EFFECT_PAST_FIRST = 20,
SPELLMOD_CASTING_TIME_OLD = 21, SPELLMOD_CASTING_TIME_OLD = 21,
SPELLMOD_DOT = 22, SPELLMOD_DOT = 22,
SPELLMOD_EFFECT3 = 23, SPELLMOD_EFFECT3 = 23,
SPELLMOD_SPELL_BONUS_DAMAGE = 24, SPELLMOD_SPELL_BONUS_DAMAGE = 24,
// spellmod 25, 26 unused // spellmod 25 unused
SPELLMOD_FREQUENCY_OF_SUCCESS = 26, // Only used with SPELL_AURA_ADD_PCT_MODIFIER and affects used on proc spells
SPELLMOD_MULTIPLE_VALUE = 27, SPELLMOD_MULTIPLE_VALUE = 27,
SPELLMOD_RESIST_DISPEL_CHANCE = 28 SPELLMOD_RESIST_DISPEL_CHANCE = 28
}; };
@ -851,6 +852,7 @@ typedef std::set<uint64> GuardianPetList;
// delay time next attack to prevent client attack animation problems // delay time next attack to prevent client attack animation problems
#define ATTACK_DISPLAY_DELAY 200 #define ATTACK_DISPLAY_DELAY 200
#define MAX_PLAYER_STEALTH_DETECT_RANGE 45.0f // max distance for detection targets by player
struct SpellProcEventEntry; // used only privately struct SpellProcEventEntry; // used only privately
@ -1195,6 +1197,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
bool AddAura(Aura *aur); bool AddAura(Aura *aur);
void RemoveAura(Aura* aura);
void RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT); void RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
void RemoveAura(uint32 spellId, uint32 effindex, Aura* except = NULL); void RemoveAura(uint32 spellId, uint32 effindex, Aura* except = NULL);
void RemoveSingleSpellAurasFromStack(uint32 spellId); void RemoveSingleSpellAurasFromStack(uint32 spellId);

View file

@ -126,7 +126,7 @@ bool UpdateData::BuildPacket(WorldPacket *packet)
if (pSize > 100 ) // compress large packets if (pSize > 100 ) // compress large packets
{ {
uint32 destsize = pSize; uint32 destsize = compressBound(pSize);
packet->resize( destsize + sizeof(uint32) ); packet->resize( destsize + sizeof(uint32) );
packet->put<uint32>(0, pSize); packet->put<uint32>(0, pSize);

View file

@ -1148,6 +1148,9 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Spell Bonus Data..." ); sLog.outString( "Loading Spell Bonus Data..." );
spellmgr.LoadSpellBonusess(); spellmgr.LoadSpellBonusess();
sLog.outString( "Loading Spell Proc Item Enchant..." );
spellmgr.LoadSpellProcItemEnchant(); // must be after LoadSpellChains
sLog.outString( "Loading Aggro Spells Definitions..."); sLog.outString( "Loading Aggro Spells Definitions...");
spellmgr.LoadSpellThreats(); spellmgr.LoadSpellThreats();

View file

@ -36,7 +36,6 @@ const char GameObjectInfodstfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
const char ItemPrototypesrcfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiisiiii"; const char ItemPrototypesrcfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiisiiii";
const char ItemPrototypedstfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiii"; const char ItemPrototypedstfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiii";
const char PageTextfmt[]="isi"; const char PageTextfmt[]="isi";
const char SpellThreatfmt[]="ii";
const char InstanceTemplatesrcfmt[]="iiiiiiiffffs"; const char InstanceTemplatesrcfmt[]="iiiiiiiffffs";
const char InstanceTemplatedstfmt[]="iiiiiiiffffi"; const char InstanceTemplatedstfmt[]="iiiiiiiffffi";
@ -48,7 +47,6 @@ SQLStorage sEquipmentStorage(EquipmentInfofmt,"entry","creature_equip_template")
SQLStorage sGOStorage(GameObjectInfosrcfmt, GameObjectInfodstfmt, "entry","gameobject_template"); SQLStorage sGOStorage(GameObjectInfosrcfmt, GameObjectInfodstfmt, "entry","gameobject_template");
SQLStorage sItemStorage(ItemPrototypesrcfmt, ItemPrototypedstfmt, "entry","item_template"); SQLStorage sItemStorage(ItemPrototypesrcfmt, ItemPrototypedstfmt, "entry","item_template");
SQLStorage sPageTextStore(PageTextfmt,"entry","page_text"); SQLStorage sPageTextStore(PageTextfmt,"entry","page_text");
SQLStorage sSpellThreatStore(SpellThreatfmt,"entry","spell_threat");
SQLStorage sInstanceTemplate(InstanceTemplatesrcfmt, InstanceTemplatedstfmt, "map","instance_template"); SQLStorage sInstanceTemplate(InstanceTemplatesrcfmt, InstanceTemplatedstfmt, "map","instance_template");
void SQLStorage::Free () void SQLStorage::Free ()

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 "8225" #define REVISION_NR "8251"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__