Permalink
Browse files

[2288] Implement abilities for Hex Lord Malacrass

Spell 43501 - Siphon Soul - requires core support
  • Loading branch information...
1 parent c05a3a4 commit 2bda452f2f3b0689402e52cbef4b88a184420902 Xfurry committed Sep 21, 2011
Showing with 254 additions and 56 deletions.
  1. +253 −55 scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp
  2. +1 −1 sd2_revision_nr.h
View
308 scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp
@@ -16,8 +16,8 @@
/* ScriptData
SDName: Boss_Malacrass
-SD%Complete: 10
-SDComment: Contain adds and adds selection
+SD%Complete: 70
+SDComment: Contain adds and adds selection; Stolen abilities timers need improvement
SDCategory: Zul'Aman
EndScriptData */
@@ -38,15 +38,22 @@ enum
SAY_ADD_DIED3 = -1568054,
SAY_DEATH = -1568055,
+ /* Notes about the event:
+ * The boss casts siphon soul right after he finishes the spirit bolts channel, which takes 10 sec
+ * The siphon soul is a channeled spell for 30 sec during which the boss uses some class abilities of the target
+ * Basically the boss casts a dummy spell which chooses a random target on which it casts the actuall channel spell
+ * The drain power spell acts as a enrage timer. It's cast each 30 seconds after the boss' health is below 80%
+ */
SPELL_SPIRIT_BOLTS = 43383,
+ SPELL_SIPHON_SOUL_DUMMY = 43498,
SPELL_SIPHON_SOUL = 43501,
SPELL_DRAIN_POWER = 44131,
//for various powers he uses after using soul drain
//Death Knight
SPELL_DK_DEATH_AND_DECAY = 61603,
- SPELL_DK_PLAGUE_STRIKE = 61606,
- SPELL_DK_MARK_OF_BLOOD = 61600,
+ SPELL_DK_PLAGUE_STRIKE = 61600,
+ SPELL_DK_MARK_OF_BLOOD = 61606,
//Druid
SPELL_DR_THORNS = 43420,
@@ -98,7 +105,11 @@ enum
SPELL_WR_SPELL_REFLECT = 43443,
//misc
- //WEAPON_ID = 33494, //weapon equip id, must be set by database.
+ TARGET_TYPE_RANDOM = 0,
+ TARGET_TYPE_VICTIM = 1,
+ TARGET_TYPE_SELF = 2,
+ TARGET_TYPE_FRIENDLY = 3,
+
MAX_ACTIVE_ADDS = 4
};
@@ -123,6 +134,76 @@ SpawnGroup m_auiSpawnEntry[] =
{24246, 24247}, //Darkheart / Koragg
};
+struct PlayerAbilityStruct
+{
+ uint32 m_uiSpellId;
+ uint8 m_uiTargetType;
+ uint32 m_uiInitialTimer, m_uiCooldown;
+};
+
+// Classes are in the same order as they are in DBC
+static PlayerAbilityStruct m_aMalacrassStolenAbility[][4] =
+{
+ { // 0* shadow priest - exception: it seems that the priest has two specs. We use this slot for the shadow priest
+ {SPELL_PR_MIND_CONTROL, TARGET_TYPE_RANDOM, 15000, 30000},
+ {SPELL_PR_MIND_BLAST, TARGET_TYPE_RANDOM, 23000, 30000},
+ {SPELL_PR_SW_DEATH, TARGET_TYPE_RANDOM, 5000, 16000}
+ },
+ { // 1 warrior
+ {SPELL_WR_SPELL_REFLECT, TARGET_TYPE_SELF, 2000, 30000},
+ {SPELL_WR_WHIRLWIND, TARGET_TYPE_SELF, 10000, 30000},
+ {SPELL_WR_MORTAL_STRIKE, TARGET_TYPE_VICTIM, 6000, 15000}
+ },
+ { // 2 paladin
+ {SPELL_PA_CONSECRATION, TARGET_TYPE_SELF, 10000, 30000},
+ {SPELL_PA_HOLY_LIGHT, TARGET_TYPE_FRIENDLY, 17000, 30000},
+ {SPELL_PA_AVENGING_WRATH, TARGET_TYPE_SELF, 0, 30000}
+ },
+ { // 3 hunter
+ {SPELL_HU_EXPLOSIVE_TRAP, TARGET_TYPE_SELF, 12000, 30000},
+ {SPELL_HU_FREEZING_TRAP, TARGET_TYPE_SELF, 3000, 30000},
+ {SPELL_HU_SNAKE_TRAP, TARGET_TYPE_SELF, 21000, 30000}
+ },
+ { // 4 rogue
+ {SPELL_RO_WOUND_POISON, TARGET_TYPE_VICTIM, 3000, 17000},
+ {SPELL_RO_SLICE_DICE, TARGET_TYPE_SELF, 17000, 30000},
+ {SPELL_RO_BLIND, TARGET_TYPE_RANDOM, 12000, 30000}
+ },
+ { // 5 priest
+ {SPELL_PR_PAIN_SUPP, TARGET_TYPE_FRIENDLY, 24000, 30000},
+ {SPELL_PR_HEAL, TARGET_TYPE_FRIENDLY, 16000, 30000},
+ {SPELL_PR_PSYCHIC_SCREAM, TARGET_TYPE_RANDOM, 8000, 30000}
+ },
+ { // 6 death knight
+ {SPELL_DK_DEATH_AND_DECAY, TARGET_TYPE_RANDOM, 25000, 30000},
+ {SPELL_DK_PLAGUE_STRIKE, TARGET_TYPE_VICTIM, 5000, 17000},
+ {SPELL_DK_MARK_OF_BLOOD, TARGET_TYPE_RANDOM, 14000, 30000}
+ },
+ { // 7 shaman
+ {SPELL_SH_FIRE_NOVA, TARGET_TYPE_SELF, 25000, 30000},
+ {SPELL_SH_HEALING_WAVE, TARGET_TYPE_FRIENDLY, 15000, 30000},
+ {SPELL_SH_CHAIN_LIGHT, TARGET_TYPE_RANDOM, 4000, 16000}
+ },
+ { // 8 mage
+ {SPELL_MG_FIREBALL, TARGET_TYPE_RANDOM, 8000, 30000},
+ {SPELL_MG_FROSTBOLT, TARGET_TYPE_RANDOM, 25000, 30000},
+ {SPELL_MG_ICE_LANCE, TARGET_TYPE_RANDOM, 2000, 18000},
+ {SPELL_MG_FROST_NOVA, TARGET_TYPE_SELF, 17000, 30000}
+ },
+ { // 9 warlock
+ {SPELL_WL_CURSE_OF_DOOM, TARGET_TYPE_RANDOM, 0, 30000},
+ {SPELL_WL_RAIN_OF_FIRE, TARGET_TYPE_RANDOM, 16000, 30000},
+ {SPELL_WL_UNSTABLE_AFFL, TARGET_TYPE_RANDOM, 8000, 13000}
+ },
+ { // 10 unused - no class in DBC here
+ },
+ { // 11 druid
+ {SPELL_DR_LIFEBLOOM, TARGET_TYPE_FRIENDLY, 15000, 30000},
+ {SPELL_DR_THORNS, TARGET_TYPE_SELF, 0, 30000},
+ {SPELL_DR_MOONFIRE, TARGET_TYPE_RANDOM, 8000, 13000}
+ }
+};
+
struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI
{
boss_malacrassAI(Creature* pCreature) : ScriptedAI(pCreature)
@@ -134,17 +215,29 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI
ScriptedInstance* m_pInstance;
+ uint32 m_uiSpiritBoltsTimer;
+ uint32 m_uiDrainPowerTimer;
+ uint32 m_uiSiphonSoulTimer;
+ uint32 m_uiPlayerAbilityTimer;
+ uint8 m_uiPlayerClass;
+
+ bool m_bCanUsePlayerSpell;
+
+ std::vector<uint32> m_vPlayerSpellTimer;
std::list<uint32> m_lAddsEntryList;
ObjectGuid m_aAddGuid[MAX_ACTIVE_ADDS];
void Reset()
{
- InitializeAdds();
+ m_uiSpiritBoltsTimer = 30000;
+ m_uiDrainPowerTimer = 0;
+ m_uiSiphonSoulTimer = 40000;
+ m_uiPlayerAbilityTimer = 10000;
+ m_uiPlayerClass = 0;
- if (!m_pInstance)
- return;
+ m_bCanUsePlayerSpell = false;
- m_pInstance->SetData(TYPE_MALACRASS, NOT_STARTED);
+ InitializeAdds();
}
void JustReachedHome()
@@ -242,6 +335,28 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI
m_pInstance->SetData(TYPE_MALACRASS, DONE);
}
+ void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell)
+ {
+ // Set the player's class when hit with soul siphon
+ if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_SIPHON_SOUL)
+ {
+ m_uiPlayerClass = ((Player*)pTarget)->getClass();
+ m_bCanUsePlayerSpell = true;
+
+ // In case the player it's priest we can choose either a holy priest or a shadow priest
+ if (m_uiPlayerClass == CLASS_PRIEST)
+ m_uiPlayerClass = urand(0, 1) ? CLASS_PRIEST : 0;
+
+ // Init the spell timers
+ uint8 m_uiMaxSpells = m_uiPlayerClass == CLASS_MAGE ? 4 : 3;
+
+ m_vPlayerSpellTimer.clear();
+ m_vPlayerSpellTimer.reserve(m_uiMaxSpells);
+ for (uint8 i = 0; i < m_uiMaxSpells; ++i)
+ m_vPlayerSpellTimer.push_back(m_aMalacrassStolenAbility[m_uiPlayerClass][i].m_uiInitialTimer);
+ }
+ }
+
void CleanAdds()
{
for(uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i)
@@ -259,11 +374,94 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI
m_lAddsEntryList.clear();
}
+ bool CanUseSpecialAbility(uint32 uiSpellIndex)
+ {
+ Unit* pTarget = NULL;
+
+ switch(m_aMalacrassStolenAbility[m_uiPlayerClass][uiSpellIndex].m_uiTargetType)
+ {
+ case TARGET_TYPE_SELF:
+ pTarget = m_creature;
+ break;
+ case TARGET_TYPE_VICTIM:
+ pTarget = m_creature->getVictim();
+ break;
+ case TARGET_TYPE_RANDOM:
+ pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0);
+ break;
+ case TARGET_TYPE_FRIENDLY:
+ pTarget = DoSelectLowestHpFriendly(50.0f);
+ break;
+ }
+
+ if (pTarget)
+ {
+ if (DoCastSpellIfCan(pTarget, m_aMalacrassStolenAbility[m_uiPlayerClass][uiSpellIndex].m_uiSpellId, CAST_TRIGGERED) == CAST_OK)
+ return true;
+ }
+
+ return false;
+ }
+
void UpdateAI(const uint32 uiDiff)
{
if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
return;
+ // Acts as an enrage timer
+ if (m_creature->GetHealthPercent() < 80.0f)
+ {
+ if (m_uiDrainPowerTimer < uiDiff)
+ {
+ if (DoCastSpellIfCan(m_creature, SPELL_DRAIN_POWER) == CAST_OK)
+ {
+ DoScriptText(SAY_DRAIN_POWER, m_creature);
+ m_uiDrainPowerTimer = 30000;
+ }
+ }
+ else
+ m_uiDrainPowerTimer -= uiDiff;
+ }
+
+ if (m_uiSpiritBoltsTimer < uiDiff)
+ {
+ if (DoCastSpellIfCan(m_creature, SPELL_SPIRIT_BOLTS) == CAST_OK)
+ {
+ DoScriptText(SAY_SPIRIT_BOLTS, m_creature);
+ m_bCanUsePlayerSpell = false;
+ m_uiSpiritBoltsTimer = 40000;
+ }
+ }
+ else
+ m_uiSpiritBoltsTimer -= uiDiff;
+
+ if (m_uiSiphonSoulTimer < uiDiff)
+ {
+ if (DoCastSpellIfCan(m_creature, SPELL_SIPHON_SOUL_DUMMY) == CAST_OK)
+ {
+ DoScriptText(SAY_SOUL_SIPHON, m_creature);
+ m_uiSiphonSoulTimer = 40000;
+ }
+ }
+ else
+ m_uiSiphonSoulTimer -= uiDiff;
+
+ // Use abilities only during the siphon soul phases
+ if (m_bCanUsePlayerSpell)
+ {
+ // Loop through all abilities
+ for (uint8 i = 0; i < m_vPlayerSpellTimer.size(); ++i)
+ {
+ if (m_vPlayerSpellTimer[i] < uiDiff)
+ {
+ if (CanUseSpecialAbility(i))
+ m_vPlayerSpellTimer[i] = m_aMalacrassStolenAbility[m_uiPlayerClass][i].m_uiCooldown;
+ }
+ else
+ m_vPlayerSpellTimer[i] -= uiDiff;
+ }
+ }
+
DoMeleeAttackIfReady();
}
};
@@ -817,50 +1015,50 @@ CreatureAI* GetAI_mob_koragg(Creature* pCreature)
void AddSC_boss_malacrass()
{
- Script* newscript;
-
- newscript = new Script;
- newscript->Name = "boss_malacrass";
- newscript->GetAI = &GetAI_boss_malacrass;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "mob_thurg";
- newscript->GetAI = &GetAI_mob_thurg;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "mob_gazakroth";
- newscript->GetAI = &GetAI_mob_gazakroth;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "mob_lord_raadan";
- newscript->GetAI = &GetAI_mob_lord_raadan;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "mob_darkheart";
- newscript->GetAI = &GetAI_mob_darkheart;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "mob_slither";
- newscript->GetAI = &GetAI_mob_slither;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "mob_fenstalker";
- newscript->GetAI = &GetAI_mob_fenstalker;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "mob_koragg";
- newscript->GetAI = &GetAI_mob_koragg;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "mob_alyson_antille";
- newscript->GetAI = &GetAI_mob_alyson_antille;
- newscript->RegisterSelf();
+ Script* pNewScript;
+
+ pNewScript = new Script;
+ pNewScript->Name = "boss_malacrass";
+ pNewScript->GetAI = &GetAI_boss_malacrass;
+ pNewScript->RegisterSelf();
+
+ pNewScript = new Script;
+ pNewScript->Name = "mob_thurg";
+ pNewScript->GetAI = &GetAI_mob_thurg;
+ pNewScript->RegisterSelf();
+
+ pNewScript = new Script;
+ pNewScript->Name = "mob_gazakroth";
+ pNewScript->GetAI = &GetAI_mob_gazakroth;
+ pNewScript->RegisterSelf();
+
+ pNewScript = new Script;
+ pNewScript->Name = "mob_lord_raadan";
+ pNewScript->GetAI = &GetAI_mob_lord_raadan;
+ pNewScript->RegisterSelf();
+
+ pNewScript = new Script;
+ pNewScript->Name = "mob_darkheart";
+ pNewScript->GetAI = &GetAI_mob_darkheart;
+ pNewScript->RegisterSelf();
+
+ pNewScript = new Script;
+ pNewScript->Name = "mob_slither";
+ pNewScript->GetAI = &GetAI_mob_slither;
+ pNewScript->RegisterSelf();
+
+ pNewScript = new Script;
+ pNewScript->Name = "mob_fenstalker";
+ pNewScript->GetAI = &GetAI_mob_fenstalker;
+ pNewScript->RegisterSelf();
+
+ pNewScript = new Script;
+ pNewScript->Name = "mob_koragg";
+ pNewScript->GetAI = &GetAI_mob_koragg;
+ pNewScript->RegisterSelf();
+
+ pNewScript = new Script;
+ pNewScript->Name = "mob_alyson_antille";
+ pNewScript->GetAI = &GetAI_mob_alyson_antille;
+ pNewScript->RegisterSelf();
}
View
2 sd2_revision_nr.h
@@ -1,4 +1,4 @@
#ifndef __SD2_REVISION_NR_H__
#define __SD2_REVISION_NR_H__
- #define SD2_REVISION_NR "2287"
+ #define SD2_REVISION_NR "2288"
#endif // __SD2_REVISION_NR_H__

0 comments on commit 2bda452

Please sign in to comment.