Skip to content

Commit

Permalink
[2288] Implement abilities for Hex Lord Malacrass
Browse files Browse the repository at this point in the history
Spell 43501 - Siphon Soul - requires core support
  • Loading branch information
Xfurry committed Sep 21, 2011
1 parent c05a3a4 commit 2bda452
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 56 deletions.
308 changes: 253 additions & 55 deletions scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp
Expand Up @@ -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 */

Expand All @@ -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,
Expand Down Expand Up @@ -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
};

Expand All @@ -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)
Expand All @@ -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()
Expand Down Expand Up @@ -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)
Expand All @@ -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();
}
};
Expand Down Expand Up @@ -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();
}
2 changes: 1 addition & 1 deletion 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.