Skip to content

Commit

Permalink
ZG: Reimplement Hakkar using SpellScripts Spell lists and Combat AI
Browse files Browse the repository at this point in the history
  • Loading branch information
killerwife committed Jan 23, 2022
1 parent 35e5871 commit 7e0aaa6
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 184 deletions.
1 change: 1 addition & 0 deletions sql/scriptdev2/spell.sql
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ INSERT INTO spell_scripts(Id, ScriptName) VALUES
(24649,'spell_thousand_blades_renataki'),
(24699,'spell_renataki_vanish'),
(24700,'spell_renataki_vanish_teleport'),
(24324,'spell_hakkar_blood_siphon'),
(24693,'spell_hakkar_power_down'),
(24728,'spell_summon_nightmare_illusion_hazzarah'),
(25684,'spell_summon_mana_fiends_moam'),
Expand Down
4 changes: 4 additions & 0 deletions src/game/AI/BaseAI/UnitAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,10 @@ std::pair<bool, Unit*> UnitAI::ChooseTarget(CreatureSpellListTargeting* targetDa
}
break;
}
case SPELL_LIST_TARGET_CURRENT_NOT_ALONE:
result = m_unit->getThreatManager().getThreatList().size() > 1;
target = m_unit->GetVictim();
break;
}
break;
case SPELL_LIST_TARGETING_ATTACK:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ EndScriptData */

#include "AI/ScriptDevAI/include/sc_common.h"
#include "zulgurub.h"
#include "AI/ScriptDevAI/base/CombatAI.h"

enum
{
Expand All @@ -37,48 +38,31 @@ enum
SPELL_DOUBLE_ATTACK = 19818,

// The Aspects of all High Priests
SPELL_ASPECT_OF_JEKLIK = 24687,
SPELL_ASPECT_OF_VENOXIS = 24688,
SPELL_ASPECT_OF_MARLI = 24686,
SPELL_ASPECT_OF_THEKAL = 24689,
SPELL_ASPECT_OF_ARLOKK = 24690
SPELL_ASPECT_OF_JEKLIK = 24687, // assumed spell list index 5
SPELL_ASPECT_OF_VENOXIS = 24688, // assumed spell list index 6
SPELL_ASPECT_OF_MARLI = 24686, // assumed spell list index 7
SPELL_ASPECT_OF_THEKAL = 24689, // assumed spell list index 8
SPELL_ASPECT_OF_ARLOKK = 24690 // assumed spell list index 9
};

struct boss_hakkarAI : public ScriptedAI
enum HakkarActions
{
boss_hakkarAI(Creature* pCreature) : ScriptedAI(pCreature)
HAKKAR_ENRAGE_LOW,
HAKKAR_ACTION_MAX,
};

struct boss_hakkarAI : public CombatAI
{
boss_hakkarAI(Creature* creature) : CombatAI(creature, HAKKAR_ACTION_MAX), m_instance(static_cast<ScriptedInstance*>(creature->GetInstanceData()))
{
m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData();
Reset();
AddTimerlessCombatAction(HAKKAR_ENRAGE_LOW, true);
}

ScriptedInstance* m_pInstance;

uint32 m_uiBloodSiphonTimer;
uint32 m_uiCorruptedBloodTimer;
uint32 m_uiCauseInsanityTimer;
uint32 m_uiWillOfHakkarTimer;
uint32 m_uiEnrageTimer;

uint32 m_uiAspectOfJeklikTimer;
uint32 m_uiAspectOfVenoxisTimer;
uint32 m_uiAspectOfMarliTimer;
uint32 m_uiAspectOfThekalTimer;
uint32 m_uiAspectOfArlokkTimer;
ScriptedInstance* m_instance;

void Reset() override
{
m_uiBloodSiphonTimer = 90000;
m_uiCorruptedBloodTimer = 25000;
m_uiCauseInsanityTimer = 17000;
m_uiWillOfHakkarTimer = 17000;
m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS;

m_uiAspectOfJeklikTimer = 4000;
m_uiAspectOfVenoxisTimer = 7000;
m_uiAspectOfMarliTimer = 12000;
m_uiAspectOfThekalTimer = 8000;
m_uiAspectOfArlokkTimer = 18000;
CombatAI::Reset();

DoCastSpellIfCan(nullptr, SPELL_DOUBLE_ATTACK, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT);

Expand All @@ -90,18 +74,18 @@ struct boss_hakkarAI : public ScriptedAI
DoScriptText(SAY_AGGRO, m_creature);

// check if the priest encounters are done
if (m_pInstance)
if (m_instance)
{
if (m_pInstance->GetData(TYPE_JEKLIK) == DONE)
m_uiAspectOfJeklikTimer = 0;
if (m_pInstance->GetData(TYPE_VENOXIS) == DONE)
m_uiAspectOfVenoxisTimer = 0;
if (m_pInstance->GetData(TYPE_MARLI) == DONE)
m_uiAspectOfMarliTimer = 0;
if (m_pInstance->GetData(TYPE_THEKAL) == DONE)
m_uiAspectOfThekalTimer = 0;
if (m_pInstance->GetData(TYPE_ARLOKK) == DONE)
m_uiAspectOfArlokkTimer = 0;
if (m_instance->GetData(TYPE_JEKLIK) == DONE)
m_creature->UpdateSpell(5, 0);
if (m_instance->GetData(TYPE_VENOXIS) == DONE)
m_creature->UpdateSpell(6, 0);
if (m_instance->GetData(TYPE_MARLI) == DONE)
m_creature->UpdateSpell(7, 0);
if (m_instance->GetData(TYPE_THEKAL) == DONE)
m_creature->UpdateSpell(8, 0);
if (m_instance->GetData(TYPE_ARLOKK) == DONE)
m_creature->UpdateSpell(9, 0);
}
}

Expand All @@ -111,144 +95,20 @@ struct boss_hakkarAI : public ScriptedAI
m_creature->RemoveAurasDueToSpell(SPELL_HAKKAR_POWER);
for (uint8 i = 0; i < MAX_PRIESTS; i++)
{
if (m_pInstance->GetData(i) != DONE)
if (m_instance->GetData(i) != DONE)
m_creature->CastSpell(m_creature, SPELL_HAKKAR_POWER, TRIGGERED_NONE);
}
}

void UpdateAI(const uint32 uiDiff) override
void ExecuteAction(uint32 action) override
{
if (!m_creature->SelectHostileTarget() || !m_creature->GetVictim())
return;

if (m_uiBloodSiphonTimer < uiDiff)
{
if (DoCastSpellIfCan(m_creature, SPELL_BLOOD_SIPHON) == CAST_OK)
m_uiBloodSiphonTimer = 90000;
}
else
m_uiBloodSiphonTimer -= uiDiff;

// Corrupted Blood Timer
if (m_uiCorruptedBloodTimer < uiDiff)
{
if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0))
{
if (DoCastSpellIfCan(pTarget, SPELL_CORRUPTED_BLOOD) == CAST_OK)
m_uiCorruptedBloodTimer = urand(30000, 45000);
}
}
else
m_uiCorruptedBloodTimer -= uiDiff;

// Cause Insanity Timer
if (m_uiCauseInsanityTimer < uiDiff)
{
if (m_creature->getThreatManager().getThreatList().size() > 1)
{
if (DoCastSpellIfCan(m_creature->GetVictim(), SPELL_CAUSE_INSANITY) == CAST_OK)
m_uiCauseInsanityTimer = urand(10000, 15000);
}
else // Solo case, check again later
m_uiCauseInsanityTimer = urand(35000, 43000);
}
else
m_uiCauseInsanityTimer -= uiDiff;

// Will Of Hakkar Timer
if (m_uiWillOfHakkarTimer < uiDiff)
{
if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1))
{
if (DoCastSpellIfCan(pTarget, SPELL_WILL_OF_HAKKAR) == CAST_OK)
m_uiWillOfHakkarTimer = urand(25000, 35000);
}
else // solo attempt, try again later
m_uiWillOfHakkarTimer = 25000;
}
else
m_uiWillOfHakkarTimer -= uiDiff;

if (m_uiEnrageTimer < uiDiff)
{
if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK)
m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS;
}
else
m_uiEnrageTimer -= uiDiff;

// Checking if Jeklik is dead. If not we cast her Aspect
if (m_uiAspectOfJeklikTimer)
{
if (m_uiAspectOfJeklikTimer <= uiDiff)
{
if (DoCastSpellIfCan(m_creature, SPELL_ASPECT_OF_JEKLIK) == CAST_OK)
m_uiAspectOfJeklikTimer = urand(10000, 14000);
}
else
m_uiAspectOfJeklikTimer -= uiDiff;
}

// Checking if Venoxis is dead. If not we cast his Aspect
if (m_uiAspectOfVenoxisTimer)
{
if (m_uiAspectOfVenoxisTimer <= uiDiff)
{
if (DoCastSpellIfCan(m_creature, SPELL_ASPECT_OF_VENOXIS) == CAST_OK)
m_uiAspectOfVenoxisTimer = 8000;
}
else
m_uiAspectOfVenoxisTimer -= uiDiff;
}

// Checking if Marli is dead. If not we cast her Aspect
if (m_uiAspectOfMarliTimer)
{
if (m_uiAspectOfMarliTimer <= uiDiff)
{
if (DoCastSpellIfCan(m_creature->GetVictim(), SPELL_ASPECT_OF_MARLI) == CAST_OK)
m_uiAspectOfMarliTimer = 10000;
}
else
m_uiAspectOfMarliTimer -= uiDiff;
}

// Checking if Thekal is dead. If not we cast his Aspect
if (m_uiAspectOfThekalTimer)
{
if (m_uiAspectOfThekalTimer <= uiDiff)
{
if (DoCastSpellIfCan(m_creature, SPELL_ASPECT_OF_THEKAL) == CAST_OK)
m_uiAspectOfThekalTimer = 15000;
}
else
m_uiAspectOfThekalTimer -= uiDiff;
}

// Checking if Arlokk is dead. If yes we cast her Aspect
if (m_uiAspectOfArlokkTimer)
{
if (m_uiAspectOfArlokkTimer <= uiDiff)
{
if (DoCastSpellIfCan(m_creature->GetVictim(), SPELL_ASPECT_OF_ARLOKK) == CAST_OK)
{
DoResetThreat();
m_uiAspectOfArlokkTimer = urand(10000, 15000);
}
}
else
m_uiAspectOfArlokkTimer -= uiDiff;
}

DoMeleeAttackIfReady();
if (action == HAKKAR_ENRAGE_LOW)
if (m_creature->GetHealthPercent() < 5.f)
if (DoCastSpellIfCan(nullptr, SPELL_ENRAGE) == CAST_OK)
DisableCombatAction(action);
}
};

UnitAI* GetAI_boss_hakkar(Creature* pCreature)
{
return new boss_hakkarAI(pCreature);
}

struct HakkarPowerDown : public SpellScript
{
void OnEffectExecute(Spell* spell, SpellEffectIndex effIdx) const override
Expand All @@ -264,12 +124,25 @@ struct HakkarPowerDown : public SpellScript
}
};

struct BloodSiphon : public SpellScript
{
void OnEffectExecute(Spell* spell, SpellEffectIndex effIdx) const override
{
if (effIdx != EFFECT_INDEX_0)
return;

Unit* target = spell->GetUnitTarget();
target->CastSpell(spell->GetCaster(), target->HasAura(24321) ? 24323 : 24322, TRIGGERED_OLD_TRIGGERED);
}
};

void AddSC_boss_hakkar()
{
Script* pNewScript = new Script;
pNewScript->Name = "boss_hakkar";
pNewScript->GetAI = &GetAI_boss_hakkar;
pNewScript->GetAI = &GetNewAIInstance<boss_hakkarAI>;
pNewScript->RegisterSelf();

RegisterSpellScript<HakkarPowerDown>("spell_hakkar_power_down");
RegisterSpellScript<BloodSiphon>("spell_hakkar_blood_siphon");
}
7 changes: 6 additions & 1 deletion src/game/Entities/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2354,7 +2354,12 @@ void Creature::UpdateSpell(int32 index, int32 newSpellId)
{
auto itr = m_spellList.Spells.find(index);
if (itr != m_spellList.Spells.end())
(*itr).second.SpellId = newSpellId;
{
if (newSpellId == 0)
m_spellList.Spells.erase(itr);
else
(*itr).second.SpellId = newSpellId;
}
}

void Creature::SetSpellList(uint32 spellSet)
Expand Down
1 change: 1 addition & 0 deletions src/game/Entities/CreatureSpellList.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum SpellListTargetingHardcoded
SPELL_LIST_TARGET_DISPELLABLE_FRIENDLY_NO_SELF = 4,
SPELL_LIST_TARGET_FRIENDLY_MISSING_BUFF = 5,
SPELL_LIST_TARGET_FRIENDLY_MISSING_BUFF_NO_SELF = 6,
SPELL_LIST_TARGET_CURRENT_NOT_ALONE = 7, // current target exists and more than 1 on threat list
SPELL_LIST_HARDCODED_MAX = 100,
};

Expand Down
8 changes: 0 additions & 8 deletions src/game/Spells/SpellEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8405,14 +8405,6 @@ void Spell::EffectScriptEffect(SpellEffectIndex eff_idx)
unitTarget->CastSpell(unitTarget, 24321, TRIGGERED_OLD_TRIGGERED, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 24324: // Blood Siphon
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;

unitTarget->CastSpell(m_caster, unitTarget->HasAura(24321) ? 24323 : 24322, TRIGGERED_OLD_TRIGGERED);
return;
}
case 24590: // Brittle Armor - need remove one 24575 Brittle Armor aura
unitTarget->RemoveAuraHolderFromStack(24575);
return;
Expand Down

0 comments on commit 7e0aaa6

Please sign in to comment.