aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/EventAI.txt18
-rw-r--r--sql/mangos.sql16
-rw-r--r--sql/updates/4043_world_npc_spellclick_spells.sql28
-rw-r--r--sql/updates/4045_world_spell_proc_event.sql5
-rw-r--r--sql/world_spell_full.sql80
-rw-r--r--src/game/CreatureEventAI.cpp33
-rw-r--r--src/game/CreatureEventAI.h11
-rw-r--r--src/game/CreatureEventAIMgr.cpp14
-rw-r--r--src/game/ObjectMgr.cpp62
-rw-r--r--src/game/ObjectMgr.h17
-rw-r--r--src/game/Player.cpp25
-rw-r--r--src/game/SpellAuras.cpp2
-rw-r--r--src/game/SpellHandler.cpp6
-rw-r--r--src/game/Unit.cpp14
-rw-r--r--src/game/Unit.h2
15 files changed, 243 insertions, 90 deletions
diff --git a/doc/EventAI.txt b/doc/EventAI.txt
index 76e4fa20c35..0f411b62833 100644
--- a/doc/EventAI.txt
+++ b/doc/EventAI.txt
@@ -80,6 +80,8 @@ Some events such as EVENT_T_AGGRO, EVENT_T_DEATH, EVENT_T_SPAWNED, and EVENT_T_E
18 EVENT_T_TARGET_MANA ManaMax%, ManaMin%, RepeatMin, RepeatMax
21 EVENT_T_REACHED_HOME NONE Expires when creature reach it's home(spawn) location after Evade.
22 EVENT_T_RECEIVE_EMOTE EmoteId, Condition, CondValue1, CondValue2 Expires when creature receive emote with text emote id(enum TextEmotes). Condition can be defined. If set, then most conditions has additional value (see enum ConditionType)
+23 EVENT_T_BUFFED SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when creature have spell (Param1) auras applied stack greater or equal provided in Param2 amount. Will repeat every (Param3) and (Param4).
+24 EVENT_T_TARGET_BUFFED SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when target unit have spell (Param1) auras applied stack greater or equal provided in Param2 amount. Will repeat every (Param3) and (Param4).
=========================================
Action Types
@@ -339,6 +341,22 @@ Most commonly used to cast spells that can not be casted in EVENT_T_EVADE and ot
Expires only when creature receive emote from player. Valid text emote id's are in Mangos source (enum TextEmotes)
Event does not require any conditions to process, however many are ecpected to have condition.
+---------------------------
+23 = EVENT_T_BUFFED :
+---------------------------
+Parameter 1: SpellId - This is the SpellID That the Aura Check will look for
+Parameter 2: Amount - This is the amount of SpellID's auras at creature required for event expire.
+Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire
+Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire
+
+---------------------------
+24 = EVENT_T_TARGET_BUFFED:
+---------------------------
+Parameter 1: SpellId - This is the SpellID That the Aura Check will look for
+Parameter 2: Amount - This is the amount of SpellID's auras at target unit required for event expire.
+Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire
+Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire
+
EventAI use conditions from available in Mangos (enum ConditionType)
Current implemented conditions:
CONDITION_NONE (0) 0 0
diff --git a/sql/mangos.sql b/sql/mangos.sql
index af73760ac0e..7316cd17dfa 100644
--- a/sql/mangos.sql
+++ b/sql/mangos.sql
@@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
- `required_7988_09_mangos_spell_proc_event` bit(1) default NULL
+ `required_8021_01_mangos_spell_proc_event` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@@ -3190,11 +3190,12 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `npc_spellclick_spells`;
CREATE TABLE `npc_spellclick_spells` (
- `npc_entry` INT UNSIGNED NOT NULL COMMENT 'reference to creature_template',
- `spell_id` INT UNSIGNED NOT NULL COMMENT 'spell which should be casted ',
- `quest_id` INT UNSIGNED NOT NULL COMMENT 'reference to quest_template',
- `quest_status` INT(11) UNSIGNED NOT NULL DEFAULT 3 COMMENT 'Quest status: 3 incompleted, 1 completed/rewarded',
- `cast_flags` TINYINT UNSIGNED NOT NULL COMMENT 'first bit defines caster: 1=player, 0=creature; second bit defines target, same mapping as caster bit'
+ `npc_entry` int unsigned NOT NULL COMMENT 'reference to creature_template',
+ `spell_id` int unsigned NOT NULL COMMENT 'spell which should be casted ',
+ `quest_start` mediumint(8) unsigned NOT NULL COMMENT 'reference to quest_template',
+ `quest_start_active` tinyint(1) unsigned NOT NULL default '0',
+ `quest_end` mediumint(8) unsigned NOT NULL default '0',
+ `cast_flags` tinyint unsigned NOT NULL COMMENT 'first bit defines caster: 1=player, 0=creature; second bit defines target, same mapping as caster bit'
) ENGINE = MYISAM DEFAULT CHARSET=utf8;
--
@@ -17408,6 +17409,9 @@ INSERT INTO `spell_proc_event` VALUES
(51474, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0.000000, 0.000000, 0),
(51478, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0.000000, 0.000000, 0),
(51479, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0.000000, 0.000000, 0),
+(51483, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0),
+(51485, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0),
+(51486, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0),
(51556, 0x00000000, 11, 0x000000C0, 0x00000000, 0x00000010, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(51557, 0x00000000, 11, 0x000000C0, 0x00000000, 0x00000010, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(51558, 0x00000000, 11, 0x000000C0, 0x00000000, 0x00000010, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
diff --git a/sql/updates/4043_world_npc_spellclick_spells.sql b/sql/updates/4043_world_npc_spellclick_spells.sql
new file mode 100644
index 00000000000..2e1895a25fd
--- /dev/null
+++ b/sql/updates/4043_world_npc_spellclick_spells.sql
@@ -0,0 +1,28 @@
+ALTER TABLE npc_spellclick_spells
+ DROP COLUMN quest_status,
+ CHANGE COLUMN quest_id quest_start mediumint(8) unsigned NOT NULL COMMENT 'reference to quest_template',
+ ADD COLUMN quest_start_active tinyint(1) unsigned NOT NULL default '0' AFTER quest_start,
+ ADD COLUMN quest_end mediumint(8) unsigned NOT NULL default '0' AFTER quest_start_active;
+
+/* compatibility with old data */
+UPDATE npc_spellclick_spells
+ SET quest_end = quest_start, quest_start_active = 1
+ WHERE quest_start <> 0;
+
+DELETE FROM `npc_spellclick_spells` WHERE `spell_id` IN (
+54568, 54575, 52263, 52280, 52447);
+INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_start`, `quest_start_active`, `quest_end`, `cast_flags`) VALUES
+(29488, 54568, 12670, 1, 0, 3), -- Taxi to Death's Breath
+(29501, 54575, 12670, 1, 0, 3),
+(28605, 52263, 12680, 1, 12680, 1), -- Stolen Horse
+(28606, 52263, 12680, 1, 12680, 1),
+(28607, 52263, 12680, 1, 12680, 1),
+(28782, 52280, 12687, 1, 12687, 1), -- Unbound Charger
+(28833, 52447, 12701, 1, 12701, 1), -- Scarlet Cannon Master
+(28887, 52447, 12701, 1, 12701, 1);
+
+DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (29912);
+INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_start`, `quest_start_active`, `quest_end`, `cast_flags`) VALUES
+(29912, 55479, 0, 0, 0, 3); # Obedience Crystal - Force Obedience
+
+REPLACE into `spell_target_position` values (51852, 609, 2361.21, -5660.45, 503.828, 4.49); \ No newline at end of file
diff --git a/sql/updates/4045_world_spell_proc_event.sql b/sql/updates/4045_world_spell_proc_event.sql
new file mode 100644
index 00000000000..6104f0d0782
--- /dev/null
+++ b/sql/updates/4045_world_spell_proc_event.sql
@@ -0,0 +1,5 @@
+DELETE FROM `spell_proc_event` WHERE `entry` IN (51483,51485,51486);
+INSERT INTO `spell_proc_event` VALUES
+(51483, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0.000000, 0.000000, 0),
+(51485, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0.000000, 0.000000, 0),
+(51486, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0.000000, 0.000000, 0); \ No newline at end of file
diff --git a/sql/world_spell_full.sql b/sql/world_spell_full.sql
index 08c23a2b726..c39370ec588 100644
--- a/sql/world_spell_full.sql
+++ b/sql/world_spell_full.sql
@@ -164,22 +164,6 @@ UPDATE creature_template SET speed = 1.0 WHERE entry = 23095; # molten_flame
-- CLICK
-- --------
-DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN ('29501', '29488');
-INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_id`, `quest_status`, `cast_flags`) VALUES
-('29488', '54568', '12670', '1', '3'),
-('29501', '54575', '12670', '1', '3');
-
-DELETE FROM npc_spellclick_spells WHERE `npc_entry` IN (28605,28606,28607);
-INSERT INTO npc_spellclick_spells (`npc_entry`, `spell_id`, `quest_id`, `quest_status`, `cast_flags`) VALUES
-(28605, 52263, 12680, 3, 1),
-(28606, 52263, 12680, 3, 1),
-(28607, 52263, 12680, 3, 1);
-
--- Spellclick spell to mount deathcharger
-DELETE FROM npc_spellclick_spells WHERE `npc_entry`=28782;
-INSERT INTO npc_spellclick_spells (`npc_entry`, `spell_id`, `quest_id`, `quest_status`, `cast_flags`) VALUES
-(28782, 52280, 12687, 3, 1);
-
-- --------
-- TARGET
-- --------
@@ -1216,6 +1200,9 @@ INSERT INTO `spell_proc_event` (`entry`, `SchoolMask`, `SpellFamilyName`, `Spell
( 51474, 0x00, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0, 0, 0), -- Astral Shift (Rank 1)
( 51478, 0x00, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0, 0, 0), -- Astral Shift (Rank 2)
( 51479, 0x00, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0, 0, 0), -- Astral Shift (Rank 3)
+(51483, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0.000000, 0.000000, 0),
+(51485, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0.000000, 0.000000, 0),
+(51486, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0.000000, 0.000000, 0),
( 51521, 0x00, 11, 0x00000000, 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0, 0, 0), -- Improved Stormstrike
( 51522, 0x00, 11, 0x00000000, 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0, 0, 0), -- Improved Stormstrike
( 51528, 0x00, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 2.5, 0, 0), -- Maelstrom Weapon (Rank 1)
@@ -1510,25 +1497,24 @@ UPDATE creature_template SET VehicleId = 312 WHERE entry IN (31857,31858,31861,3
update creature_template set spell5=51890 where entry = 28511; -- Eye of Acherus flight
DELETE FROM `spell_script_target` WHERE entry IN
-(51859, 48743);
+(51859, 48743, 52124, 52479, 52576, 53110);
INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES
(51859, 1, 28525), -- siphon of archerus
(51859, 1, 28542),
(51859, 1, 28543),
(51859, 1, 28544),
+(52124, 1, 28655), -- Sky Darkener Assault
+(52479, 1, 28819), -- gift of harvester
+(52479, 1, 28822),
+(52576, 1, 28834), -- Electro-magnetic Pulse
+(52576, 1, 28886),
+(53110, 1, 28940), -- Devour Humanoid
(48743, 1, 26125); -- Death pact
-update creature_template set minlevel=50,maxlevel=52,minhealth=2215,maxhealth=2317,faction_A=2084,faction_H=2084,mindmg=50,maxdmg=50 where entry=28528; -- ghoul
-
--- taxi
-DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN ('29501', '29488');
-INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_id`, `quest_status`, `cast_flags`) VALUES
-('29488', '54568', '12670', '1', '3'),
-('29501', '54575', '12670', '1', '3');
+-- Eye of Acherus
+REPLACE into `spell_target_position` values (51852, 609, 2361.21, -5660.45, 503.828, 4.49);
-DELETE FROM `spell_script_target` WHERE entry IN (52124);
-INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES
-(52124, 1, 28655);
+update creature_template set minlevel=50,maxlevel=52,minhealth=2215,maxhealth=2317,faction_A=2084,faction_H=2084,mindmg=50,maxdmg=50 where entry=28528; -- ghoul
UPDATE `creature_template` SET spell1=52372,spell2=52373,spell3=52374,spell4=52375 WHERE `entry`=28406;
-- death charger
@@ -1542,14 +1528,6 @@ UPDATE creature_template SET `VehicleId`=200 WHERE `entry` IN (28605,28606,28607
-- Vehicle and summon spell(summon npc 28788) for Acherus Deathcharger
UPDATE creature_template SET `spell1`=52362, `VehicleId`=200 WHERE `entry`=28782;
--- gift of harvester
-DELETE FROM `spell_script_target` WHERE entry IN
-(52479);
-INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES
-(52479,1,28819),
-(52479,1,28822);
-
-
replace into creature_questrelation (id,quest) VALUES (28377,12701);
replace into creature_involvedrelation (id,quest) VALUES (28377,12701);
replace into creature_involvedrelation (id,quest) VALUES (28914,12723);
@@ -1560,31 +1538,25 @@ replace into creature_involvedrelation (id,quest) VALUES (28912,12725);
replace into creature_questrelation (id,quest) VALUES (28912,12727);
replace into creature_involvedrelation (id,quest) VALUES (28913,12727);
--- ship cannon
-DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (28833,28887);
-INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_id`, `quest_status`, `cast_flags`) VALUES
-(28833, 52447, 12701, 3, 3),
-(28887, 52447, 12701, 3, 3);
+DELETE FROM `npc_spellclick_spells` WHERE `spell_id` IN (
+54568, 54575, 52263, 52280, 52447);
+INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_start`, `quest_start_active`, `quest_end`, `cast_flags`) VALUES
+(29488, 54568, 12670, 1, 0, 3), -- Taxi to Death's Breath
+(29501, 54575, 12670, 1, 0, 3),
+(28605, 52263, 12680, 1, 12680, 1), -- Stolen Horse
+(28606, 52263, 12680, 1, 12680, 1),
+(28607, 52263, 12680, 1, 12680, 1),
+(28782, 52280, 12687, 1, 12687, 1), -- Unbound Charger
+(28833, 52447, 12701, 1, 12701, 1), -- Scarlet Cannon Master
+(28887, 52447, 12701, 1, 12701, 1);
UPDATE creature_template SET spell1=52435,spell2=52576,spell5=52588,VehicleId=68,speed=0 WHERE entry IN (28833,28887);
UPDATE creature_template SET spell1=52211 WHERE entry=28864;
-DELETE FROM `spell_script_target` WHERE entry IN
-(52576);
-INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES
-(52576,1,28834),
-(52576,1,28886);
-
-- frostbrood vanquisher
update creature_template set maxhealth = 133525, minhealth = 133525, maxmana = 51360, minmana = 51360, spell1 = 53114, spell2 = 53112, spell3=53110, VehicleId = 156 where entry = 28670;
-DELETE FROM `spell_script_target` WHERE entry IN
-(53110);
-INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES
-(53110,1,28940);
-
-
-- --------
-- NAXXARAMAS
@@ -1634,8 +1606,8 @@ flags_extra = VALUES(flags_extra),
scriptname = VALUES(scriptname);
DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (29912);
-INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_id`, `cast_flags`) VALUES
-(29912, 55479, 0, 1); # Obedience Crystal - Force Obedience
+INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_start`, `quest_start_active`, `quest_end`, `cast_flags`) VALUES
+(29912, 55479, 0, 0, 0, 3); # Obedience Crystal - Force Obedience
DELETE FROM `spell_script_target` WHERE `entry` IN
(28732,54097,55479,
diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp
index 000d59fac28..3d83b2c4fb4 100644
--- a/src/game/CreatureEventAI.cpp
+++ b/src/game/CreatureEventAI.cpp
@@ -275,8 +275,8 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
//Repeat Timers
pHolder.UpdateRepeatTimer(m_creature,event.summon_unit.repeatMin,event.summon_unit.repeatMax);
+ break;
}
- break;
case EVENT_T_TARGET_MANA:
{
if (!m_creature->isInCombat() || !m_creature->getVictim() || !m_creature->getVictim()->GetMaxPower(POWER_MANA))
@@ -294,6 +294,34 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
case EVENT_T_REACHED_HOME:
case EVENT_T_RECEIVE_EMOTE:
break;
+ case EVENT_T_BUFFED:
+ {
+ //Note: checked only aura for effect 0, if need check aura for effect 1/2 then
+ // possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
+ Aura* aura = m_creature->GetAura(event.buffed.spellId,0);
+ if(!aura || aura->GetStackAmount() < event.buffed.amount)
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.buffed.repeatMin,event.buffed.repeatMax);
+ break;
+ }
+ case EVENT_T_TARGET_BUFFED:
+ {
+ //Prevent event from occuring on no unit
+ if (!pActionInvoker)
+ return false;
+
+ //Note: checked only aura for effect 0, if need check aura for effect 1/2 then
+ // possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
+ Aura* aura = pActionInvoker->GetAura(event.buffed.spellId,0);
+ if(!aura || aura->GetStackAmount() < event.buffed.amount)
+ return false;
+
+ //Repeat Timers
+ pHolder.UpdateRepeatTimer(m_creature,event.buffed.repeatMin,event.buffed.repeatMax);
+ break;
+ }
default:
sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type);
break;
@@ -853,6 +881,9 @@ void CreatureEventAI::JustDied(Unit* killer)
if ((*i).Event.event_type == EVENT_T_DEATH)
ProcessEvent(*i, killer);
}
+
+ // reset phase after any death state events
+ Phase = 0;
}
void CreatureEventAI::KilledUnit(Unit* victim)
diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h
index d94ceeeac18..db9cb680670 100644
--- a/src/game/CreatureEventAI.h
+++ b/src/game/CreatureEventAI.h
@@ -56,6 +56,8 @@ enum EventAI_Type
EVENT_T_QUEST_COMPLETE = 20, //
EVENT_T_REACHED_HOME = 21, // NONE
EVENT_T_RECEIVE_EMOTE = 22, // EmoteId, Condition, CondValue1, CondValue2
+ EVENT_T_BUFFED = 23, // Param1 = SpellID, Param2 = Number of Time STacked, Param3/4 Repeat Min/Max
+ EVENT_T_TARGET_BUFFED = 24, // Param1 = SpellID, Param2 = Number of Time STacked, Param3/4 Repeat Min/Max
EVENT_T_END,
};
@@ -507,6 +509,15 @@ struct CreatureEventAI_Event
uint32 conditionValue1;
uint32 conditionValue2;
} receive_emote;
+ // EVENT_T_BUFFED = 23
+ // EVENT_T_TARGET_BUFFED = 24
+ struct
+ {
+ uint32 spellId;
+ uint32 amount;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } buffed;
// RAW
struct
diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp
index 0a6fb8bdb59..643a5a3212a 100644
--- a/src/game/CreatureEventAIMgr.cpp
+++ b/src/game/CreatureEventAIMgr.cpp
@@ -378,6 +378,20 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
break;
}
+ case EVENT_T_BUFFED:
+ case EVENT_T_TARGET_BUFFED:
+ {
+ SpellEntry const* pSpell = sSpellStore.LookupEntry(temp.buffed.spellId);
+ if (!pSpell)
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.spell_hit.spellId, i);
+ continue;
+ }
+ if (temp.buffed.repeatMax < temp.buffed.repeatMin)
+ sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ break;
+ }
+
default:
sLog.outErrorDb("CreatureEventAI: Creature %u using not checked at load event (%u) in event %u. Need check code update?", temp.creature_id, temp.event_id, i);
break;
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 20ace65d79b..867da4401d3 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -110,6 +110,25 @@ LanguageDesc const* GetLanguageDescByID(uint32 lang)
return NULL;
}
+bool SpellClickInfo::IsFitToRequirements(Player const* player) const
+{
+ if(questStart)
+ {
+ // not in expected required quest state
+ if(!player || (!questStartCanActive || !player->IsActiveQuest(questStart)) && !player->GetQuestRewardStatus(questStart))
+ return false;
+ }
+
+ if(questEnd)
+ {
+ // not in expected forbidden quest state
+ if(!player || player->GetQuestRewardStatus(questEnd))
+ return false;
+ }
+
+ return true;
+}
+
ObjectMgr::ObjectMgr()
{
m_hiCharGuid = 1;
@@ -699,6 +718,12 @@ void ObjectMgr::LoadCreatureTemplates()
if(cInfo->rangeattacktime == 0)
const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
+ if(cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, it expect to be set by code base at `npc_spellclick_spells` content.",cInfo->Entry,UNIT_NPC_FLAG_SPELLCLICK);
+ const_cast<CreatureInfo*>(cInfo)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK;
+ }
+
if((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type);
@@ -6567,8 +6592,8 @@ void ObjectMgr::LoadNPCSpellClickSpells()
uint32 count = 0;
mSpellClickInfoMap.clear();
-
- QueryResult *result = WorldDatabase.Query("SELECT npc_entry, spell_id, quest_id, quest_status, cast_flags FROM npc_spellclick_spells");
+ // 0 1 2 3 4 5
+ QueryResult *result = WorldDatabase.Query("SELECT npc_entry, spell_id, quest_start, quest_start_active, quest_end, cast_flags FROM npc_spellclick_spells");
if(!result)
{
@@ -6607,28 +6632,45 @@ void ObjectMgr::LoadNPCSpellClickSpells()
continue;
}
- uint32 quest = fields[2].GetUInt32();
+ uint32 quest_start = fields[2].GetUInt32();
// quest might be 0 to enable spellclick independent of any quest
- if (quest)
+ if (quest_start)
{
- if(mQuestTemplates.find(quest) == mQuestTemplates.end())
+ if(mQuestTemplates.find(quest_start) == mQuestTemplates.end())
{
- sLog.outErrorDb("Table npc_spellclick_spells references unknown quest %u. Skipping entry.", spellid);
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown start quest %u. Skipping entry.", quest_start);
continue;
}
}
- uint32 queststatus = fields[3].GetUInt32();
+ bool quest_start_active = fields[3].GetBool();
+
+ uint32 quest_end = fields[4].GetUInt32();
+ // quest might be 0 to enable spellclick active infinity after start quest
+ if (quest_end)
+ {
+ if(mQuestTemplates.find(quest_end) == mQuestTemplates.end())
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown end quest %u. Skipping entry.", quest_end);
+ continue;
+ }
+
+ }
- uint8 castFlags = fields[4].GetUInt8();
+ uint8 castFlags = fields[5].GetUInt8();
SpellClickInfo info;
info.spellId = spellid;
- info.questId = quest;
- info.questStatus = queststatus;
+ info.questStart = quest_start;
+ info.questStartCanActive = quest_start_active;
+ info.questEnd = quest_end;
info.castFlags = castFlags;
mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info));
+
+ // mark creature template as spell clickable
+ const_cast<CreatureInfo*>(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK;
+
++count;
} while (result->NextRow());
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index a508c573ef6..0c032bc8ec3 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -102,12 +102,17 @@ extern ScriptMapMap sWaypointScripts;
struct SpellClickInfo
{
uint32 spellId;
- uint32 questId;
- uint32 questStatus;
+ uint32 questStart; // quest start (quest must be active or rewarded for spell apply)
+ uint32 questEnd; // quest end (quest don't must be rewarded for spell apply)
+ bool questStartCanActive; // if true then quest start can be active (not only rewarded)
uint8 castFlags;
+
+ // helpers
+ bool IsFitToRequirements(Player const* player) const;
};
typedef std::multimap<uint32, SpellClickInfo> SpellClickInfoMap;
+typedef std::pair<SpellClickInfoMap::const_iterator,SpellClickInfoMap::const_iterator> SpellClickInfoMapBounds;
struct AreaTrigger
{
@@ -585,7 +590,6 @@ class ObjectMgr
void LoadReputationOnKill();
void LoadPointsOfInterest();
- SpellClickInfoMap mSpellClickInfoMap;
void LoadNPCSpellClickSpells();
void LoadWeatherZoneChances();
@@ -828,6 +832,11 @@ class ObjectMgr
int GetOrNewIndexForLocale(LocaleConstant loc);
+ SpellClickInfoMapBounds GetSpellClickInfoMapBounds(uint32 creature_id) const
+ {
+ return SpellClickInfoMapBounds(mSpellClickInfoMap.lower_bound(creature_id),mSpellClickInfoMap.upper_bound(creature_id));
+ }
+
ItemRequiredTargetMapBounds GetItemRequiredTargetMapBounds(uint32 uiItemEntry) const
{
return ItemRequiredTargetMapBounds(m_ItemRequiredTarget.lower_bound(uiItemEntry),m_ItemRequiredTarget.upper_bound(uiItemEntry));
@@ -921,6 +930,8 @@ class ObjectMgr
ScriptNameMap m_scriptNames;
+ SpellClickInfoMap mSpellClickInfoMap;
+
ItemRequiredTargetMap m_ItemRequiredTarget;
typedef std::vector<LocaleConstant> LocalForIndex;
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 19e5c7e02d2..af7057518fb 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -19186,18 +19186,20 @@ void Player::UpdateForQuestWorldObjects()
Creature *obj = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, *itr);
if(!obj)
continue;
+
// check if this unit requires quest specific flags
+ if(!obj->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_SPELLCLICK))
+ continue;
- SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap;
- for(SpellClickInfoMap::const_iterator itr = map.lower_bound(obj->GetEntry()); itr != map.upper_bound(obj->GetEntry()); ++itr)
+ SpellClickInfoMapBounds clickPair = objmgr.GetSpellClickInfoMapBounds(obj->GetEntry());
+ for(SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr)
{
- if(itr->second.questId != 0)
+ if(itr->second.questStart || itr->second.questEnd)
{
obj->BuildCreateUpdateBlockForPlayer(&udata,this);
break;
}
}
-
}
}
udata.BuildPacket(&packet);
@@ -20754,16 +20756,17 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
bool Player::canSeeSpellClickOn(Creature const *c) const
{
- SpellClickInfoMap::const_iterator lower = objmgr.mSpellClickInfoMap.lower_bound(c->GetEntry());
- SpellClickInfoMap::const_iterator upper = objmgr.mSpellClickInfoMap.upper_bound(c->GetEntry());
- if(lower == upper)
+ if(!c->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_SPELLCLICK))
+ return false;
+
+ SpellClickInfoMapBounds clickPair = objmgr.GetSpellClickInfoMapBounds(c->GetEntry());
+ if(clickPair.first == clickPair.second)
return true;
- for(SpellClickInfoMap::const_iterator itr = lower; itr != upper; ++itr)
- {
- if(itr->second.questId == 0 || GetQuestStatus(itr->second.questId) == itr->second.questStatus)
+ for(SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr)
+ if(itr->second.IsFitToRequirements(this))
return true;
- }
+
return false;
}
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 471209e8f77..c83134335ea 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -4573,7 +4573,7 @@ void AuraEffect::HandleAuraPeriodicDummy(bool apply, bool Real, bool changeAmoun
{
// Explosive Shot
if (apply && !loading && caster)
- m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 16 / 100);
+ m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 14 / 100);
break;
}
}
diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp
index 1a9bc13eab8..74313eaa38b 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -522,10 +522,10 @@ void WorldSession::HandleSpellClick( WorldPacket & recv_data )
if(!unit)
return;
- SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap;
- for(SpellClickInfoMap::const_iterator itr = map.lower_bound(unit->GetEntry()); itr != map.upper_bound(unit->GetEntry()); ++itr)
+ SpellClickInfoMapBounds clickPair = objmgr.GetSpellClickInfoMapBounds(unit->GetEntry());
+ for(SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr)
{
- if(itr->second.questId == 0 || _player->GetQuestStatus(itr->second.questId) == itr->second.questStatus)
+ if(itr->second.IsFitToRequirements(_player))
{
Unit *caster = (itr->second.castFlags & 0x1) ? (Unit*)_player : (Unit*)unit;
Unit *target = (itr->second.castFlags & 0x2) ? (Unit*)_player : (Unit*)unit;
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index dd1307e7ef4..190aea1b923 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -6575,6 +6575,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
break;
}
}
+ // Storm, Earth and Fire
+ if (dummySpell->SpellIconID == 3063)
+ {
+ // Earthbind Totem summon only
+ if(procSpell->Id != 2484)
+ return false;
+
+ float chance = triggerAmount;
+ if (!roll_chance_f(chance))
+ return false;
+
+ triggered_spell_id = 64695;
+ break;
+ }
// Ancestral Awakening
if (dummySpell->SpellIconID == 3065)
{
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 00478a74acd..ce1c0265268 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -614,7 +614,7 @@ enum NPCFlags
UNIT_NPC_FLAG_AUCTIONEER = 0x00200000, // 100%
UNIT_NPC_FLAG_STABLEMASTER = 0x00400000, // 100%
UNIT_NPC_FLAG_GUILD_BANKER = 0x00800000, // cause client to send 997 opcode
- UNIT_NPC_FLAG_SPELLCLICK = 0x01000000, // cause client to send 1015 opcode (spell click)
+ UNIT_NPC_FLAG_SPELLCLICK = 0x01000000, // cause client to send 1015 opcode (spell click), dynamic, set at loading and don't must be set in DB
UNIT_NPC_FLAG_GUARD = 0x10000000, // custom flag for guards
UNIT_NPC_FLAG_OUTDOORPVP = 0x20000000, // custom flag for outdoor pvp creatures
};