Scripts/Zul'Aman: Rewrite Halazzi (#31835)

(cherry picked from commit 6954ef8c63ad96af2d0467fd119ad74b872195c8)
This commit is contained in:
offl
2026-07-19 23:52:03 +02:00
committed by Shauren
parent 0e9c00850a
commit 7b7fac8483
2 changed files with 508 additions and 64 deletions
@@ -0,0 +1,57 @@
-- Texts
DELETE FROM `creature_text` WHERE `CreatureID` = 23577;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(23577,0,0,"Get on ya knees and bow.... to da fang and claw!",14,0,100,0,0,12020,23612,0,"Halazzi SAY_AGGRO"),
(23577,1,0,"I fight wit' untamed spirit....",14,0,100,0,0,12021,22963,0,"Halazzi SAY_SPLIT"),
(23577,2,0,"Spirit, come back to me!",14,0,100,0,0,12022,22964,0,"Halazzi SAY_MERGE"),
(23577,3,0,"Me gonna carve ya now!",14,0,100,0,0,12023,23615,0,"Halazzi SAY_MELEE_1"),
(23577,3,1,"You gonna leave in pieces!",14,0,100,0,0,12024,23616,0,"Halazzi SAY_MELEE_2"),
(23577,4,0,"Whatchoo been doin', pacin' yourselves?",14,0,100,0,0,12025,24321,0,"Halazzi SAY_BERSERK"),
(23577,5,0,"You can't fight da power!",14,0,100,0,0,12026,23613,0,"Halazzi SAY_SLAY_1"),
(23577,5,1,"Ya all gonna fail!",14,0,100,0,0,12027,23614,0,"Halazzi SAY_SLAY_2"),
(23577,6,0,"Chaga... choka'jinn.",14,0,100,0,0,12028,23611,0,"Halazzi SAY_DEATH"),
(23577,7,0,"Come, fools. Fill ma empty cages....",14,0,100,0,0,12029,23309,0,"Halazzi SAY_EVENT_1"),
(23577,7,1,"I be waitin, strangers. Your deaths gonna make me stronger!",14,0,100,0,0,12030,23310,0,"Halazzi SAY_EVENT_2");
-- Halazzi
UPDATE `creature_template` SET `flags_extra` = `flags_extra`|0x00200000 WHERE `entry` = 23577;
UPDATE `creature_template_difficulty` SET `LevelScalingDeltaMin`=2,`LevelScalingDeltaMax`=2,`ContentTuningID`=1112,`DamageModifier`=35,`LootID`=23577,`GoldMin`=345432,`GoldMax`=422195,`StaticFlags1`=3498573824 WHERE `Entry` = 23577 AND `DifficultyID` = 2;
-- Halazzi (Transform)
UPDATE `creature_model_info` SET `BoundingRadius` = 0.7812495, `CombatReach` = 3.375 WHERE `DisplayID` = 22348;
UPDATE `creature_template_difficulty` SET `LevelScalingDeltaMin`=2,`LevelScalingDeltaMax`=2,`ContentTuningID`=1112,`DamageModifier`=35,`StaticFlags1`=3498573832 WHERE `Entry` = 24144 AND `DifficultyID` = 2;
-- Corrupted Lightning Totem
UPDATE `creature_template` SET `speed_walk` = 1, `speed_run` = 1, `AIName` = '', `ScriptName` = 'npc_corrupted_lightning_totem' WHERE `entry` = 24224;
UPDATE `creature_model_info` SET `BoundingRadius` = 1.55, `CombatReach` = 1.55 WHERE `DisplayID` = 22523;
UPDATE `creature_model_info` SET `BoundingRadius` = 1.5, `CombatReach` = 0 WHERE `DisplayID` = 31720;
DELETE FROM `smart_scripts` WHERE `entryorguid` = 24224 AND `source_type` = 0;
-- Spirit of the Lynx
UPDATE `creature_template` SET `speed_walk` = 1, `speed_run` = 2.14286, `BaseAttackTime` = 1500, `ScriptName` = 'npc_spirit_of_the_lynx' WHERE `entry` = 24143;
UPDATE `creature_template_difficulty` SET `LevelScalingDeltaMin` = 2, `LevelScalingDeltaMax` = 2, `ContentTuningID` = 1112, `DamageModifier` = 35, `StaticFlags1` = 3498573832, `StaticFlags2` = 4174, `StaticFlags4` = 1114112, `VerifiedBuild` = 68453 WHERE `Entry` = 24143 AND `DifficultyID` = 2;
UPDATE `creature_model_info` SET `BoundingRadius` = 1.311124086380004882, `CombatReach` = 0 WHERE `DisplayID` = 20808;
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` = 43615;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
(13,1,43615,0,0,31,0,3,24144,0,0,0,0,"","Group 0: Spell 'Halazzi Transform' (Effect 0) targets creature 'Halazzi'");
-- Spell scripts (range of spells is confusing, we ignore it and make caster spell target)
UPDATE `serverside_spell` SET `ProcChance` = 101 WHERE `Id` = 43536;
UPDATE `serverside_spell` SET `ProcChance` = 101 WHERE `Id` = 43537;
UPDATE `serverside_spell` SET `ProcChance` = 101 WHERE `Id` = 43538;
DELETE FROM `serverside_spell_effect` WHERE `SpellID` IN (43536,43537,43538) AND `EffectIndex` = 0;
INSERT INTO `serverside_spell_effect` (`SpellID`, `EffectIndex`, `Effect`, `EffectBasePoints`, `ImplicitTarget1`) VALUES
(43536, 0, 77, 60, 1),
(43537, 0, 77, 30, 1),
(43538, 0, 77, 25, 1);
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_halazzi_set_health';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(43536, 'spell_halazzi_set_health'),
(43537, 'spell_halazzi_set_health'),
(43538, 'spell_halazzi_set_health');
@@ -15,59 +15,236 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Combat timers requires to be revisited
* SAY_EVENT is NYI
*/
#include "ScriptMgr.h"
#include "Containers.h"
#include "InstanceScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "zulaman.h"
enum Says
enum HalazziTexts
{
SAY_AGGRO = 0,
SAY_PLAYER_KILL = 1,
SAY_MELEE = 2,
SAY_SPLIT = 3,
SAY_COMBINE = 4,
SAY_DEATH = 5
SAY_SPLIT = 1,
SAY_MERGE = 2,
SAY_MELEE = 3,
SAY_BERSERK = 4,
SAY_SLAY = 5,
SAY_DEATH = 6,
SAY_EVENT = 7
};
enum Spells
enum HalazziSpells
{
// Halazzi - Combat - Lynx Phase & Last Phase
SPELL_ENRAGE = 43139,
SPELL_SABER_LASH = 43267,
// Halazzi - Combat - Split
SPELL_TRANSFIGURE = 44054,
SPELL_SUMMON_SPIRIT_LYNX = 43143,
// Halazzi - Combat - Merge
SPELL_TRANSFORM_60_HEALTH = 43145,
SPELL_TRANSFORM_30_HEALTH = 43271,
SPELL_TRANSFORM_25_HEALTH = 43272,
// Halazzi - Combat - Spirit Phase & Last Phase
SPELL_LIGHTNING_TOTEM = 43302,
SPELL_FLAME_SHOCK = 43303,
SPELL_EARTH_SHOCK = 43305,
// Halazzi - Combat - All Phases
SPELL_BERSERK = 45078,
// Halazzi - Combat - Misc
SPELL_TRANSFORM_MAX_HEALTH = 43311,
// Spirit of the Lynx
SPELL_SPIRIT_CHANNEL = 43615,
SPELL_SPIRIT_EFFECT = 42466,
SPELL_SHRED_ARMOR = 43243,
SPELL_LYNX_FLURRY = 43290,
// Corrupted Lightning Totem
SPELL_LIGHTNING = 43301
};
enum Events
enum HalazziEvents
{
// Lynx Phase & Last Phase
EVENT_ENRAGE = 1,
EVENT_SABER_LASH,
// Split
EVENT_SPLIT_1,
EVENT_SPLIT_2,
// Merge
EVENT_MERGE_1,
EVENT_MERGE_2,
// Spirit Phase & Last Phase
EVENT_LIGHTNING_TOTEM,
EVENT_FLAME_SHOCK,
EVENT_EARTH_SHOCK,
// All Phases
EVENT_BERSERK
};
class boss_halazzi : public CreatureScript
enum HalazziPhases
{
public:
PHASE_LYNX = 1,
PHASE_SPIRIT,
PHASE_FINAL
};
boss_halazzi() : CreatureScript("boss_halazzi") { }
enum HalazziMisc
{
NPC_HALAZZI_LYNX = 23577,
NPC_HALAZZI_TROLL = 24144,
NPC_SPIRIT_LYNX = 24143,
ACTION_BEGIN_MERGE = 0,
ACTION_INFORM_LYNX = 1
};
struct boss_halazziAI : public BossAI
{
boss_halazziAI(Creature* creature) : BossAI(creature, BOSS_HALAZZI) { }
// 23577 - Halazzi
struct boss_halazzi : public BossAI
{
boss_halazzi(Creature* creature) : BossAI(creature, BOSS_HALAZZI), _transformCount(2) { }
void Reset() override
{
_Reset();
_transformCount = 2;
me->SetCanDualWield(true);
me->SetReactState(REACT_AGGRESSIVE);
me->SetUnkillable(false);
events.SetPhase(PHASE_LYNX);
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_ENRAGE, 15s, 25s);
events.ScheduleEvent(EVENT_SABER_LASH, 10s, 15s);
events.ScheduleEvent(EVENT_BERSERK, 10min);
}
void DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
{
if (events.IsInPhase(PHASE_LYNX) && me->HealthBelowPctDamaged(30 * _transformCount, damage))
{
me->SetUnkillable(true);
events.SetPhase(PHASE_SPIRIT);
events.ScheduleEvent(EVENT_SPLIT_1, 0s);
}
}
void OnHealthDepleted(Unit* /*attacker*/, bool /*isKill*/) override
{
if (events.IsInPhase(PHASE_SPIRIT))
{
events.SetPhase(PHASE_LYNX);
events.ScheduleEvent(EVENT_MERGE_1, 0s);
}
}
void PerformAdditionalEvents()
{
switch (_transformCount)
{
case 2:
DoCastSelf(SPELL_TRANSFORM_60_HEALTH);
break;
case 1:
DoCastSelf(SPELL_TRANSFORM_30_HEALTH);
break;
default:
break;
}
if (Creature* spirit = me->FindNearestCreature(NPC_SPIRIT_LYNX, 200.0f))
spirit->AI()->DoAction(ACTION_INFORM_LYNX);
--_transformCount;
if (_transformCount)
{
events.CancelEvent(EVENT_LIGHTNING_TOTEM);
events.CancelEvent(EVENT_FLAME_SHOCK);
events.CancelEvent(EVENT_EARTH_SHOCK);
events.ScheduleEvent(EVENT_ENRAGE, 15s, 25s);
events.ScheduleEvent(EVENT_SABER_LASH, 10s, 15s);
}
else
{
events.SetPhase(PHASE_FINAL);
events.ScheduleEvent(EVENT_ENRAGE, 15s, 25s);
events.ScheduleEvent(EVENT_SABER_LASH, 10s, 15s);
events.RescheduleEvent(EVENT_LIGHTNING_TOTEM, 10s, 15s);
events.RescheduleEvent(EVENT_FLAME_SHOCK, 10s, 25s);
events.RescheduleEvent(EVENT_EARTH_SHOCK, 10s, 20s);
}
}
void DoAction(int32 action) override
{
if (action == ACTION_BEGIN_MERGE && events.IsInPhase(PHASE_SPIRIT))
{
events.SetPhase(PHASE_LYNX);
events.ScheduleEvent(EVENT_MERGE_1, 0s);
}
}
void OnSpellCast(SpellInfo const* spellInfo) override
{
switch (spellInfo->Id)
{
case SPELL_SABER_LASH:
Talk(SAY_MELEE);
break;
case SPELL_BERSERK:
Talk(SAY_BERSERK);
break;
default:
break;
}
}
void EnterEvadeMode(EvadeReason why) override
{
DoCastSelf(SPELL_TRANSFORM_MAX_HEALTH);
if (me->GetEntry() == NPC_HALAZZI_TROLL)
me->UpdateEntry(NPC_HALAZZI_LYNX);
BossAI::EnterEvadeMode(why);
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
_JustDied();
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_PLAYER_KILL);
Talk(SAY_DEATH);
}
void UpdateAI(uint32 diff) override
@@ -79,26 +256,236 @@ class boss_halazzi : public CreatureScript
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
/*
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
default:
// Lynx Phase & Last Phase
case EVENT_ENRAGE:
DoCastSelf(SPELL_ENRAGE);
events.Repeat(15s, 25s);
break;
case EVENT_SABER_LASH:
DoCastVictim(SPELL_SABER_LASH);
events.Repeat(20s);
break;
// Split
case EVENT_SPLIT_1:
Talk(SAY_SPLIT);
DoCastSelf(SPELL_TRANSFIGURE);
me->SetReactState(REACT_PASSIVE);
events.CancelEvent(EVENT_ENRAGE);
events.CancelEvent(EVENT_SABER_LASH);
events.ScheduleEvent(EVENT_SPLIT_2, 3s);
break;
case EVENT_SPLIT_2:
me->SetReactState(REACT_AGGRESSIVE);
me->UpdateEntry(NPC_HALAZZI_TROLL);
DoCastSelf(SPELL_SUMMON_SPIRIT_LYNX);
events.ScheduleEvent(EVENT_LIGHTNING_TOTEM, 10s, 15s);
events.ScheduleEvent(EVENT_FLAME_SHOCK, 10s, 25s);
events.ScheduleEvent(EVENT_EARTH_SHOCK, 10s, 20s);
break;
// Merge
case EVENT_MERGE_1:
me->UpdateEntry(NPC_HALAZZI_LYNX);
me->SetReactState(REACT_PASSIVE);
Talk(SAY_MERGE);
PerformAdditionalEvents();
events.ScheduleEvent(EVENT_MERGE_2, 5s);
break;
case EVENT_MERGE_2:
me->SetReactState(REACT_AGGRESSIVE);
me->SetUnkillable(false);
break;
// Spirit Phase & Last Phase
case EVENT_LIGHTNING_TOTEM:
DoCastSelf(SPELL_LIGHTNING_TOTEM);
events.Repeat(10s, 25s);
break;
case EVENT_FLAME_SHOCK:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
DoCast(target, SPELL_FLAME_SHOCK);
events.Repeat(20s, 30s);
break;
case EVENT_EARTH_SHOCK:
{
std::vector<Player*> playerList;
GetPlayerListInGrid(playerList, me, 30.0f);
for (Player* player : playerList)
{
if (player->IsNonMeleeSpellCast(false))
{
DoCast(player, SPELL_EARTH_SHOCK);
break;
}
}
*/
events.Repeat(10s, 20s);
break;
}
};
CreatureAI* GetAI(Creature* creature) const override
// All Phases
case EVENT_BERSERK:
DoCastSelf(SPELL_BERSERK);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
private:
uint8 _transformCount;
};
// 24143 - Spirit of the Lynx
struct npc_spirit_of_the_lynx : public ScriptedAI
{
npc_spirit_of_the_lynx(Creature* creature) : ScriptedAI(creature),
_instance(creature->GetInstanceScript()) { }
void JustAppeared() override
{
return GetZulAmanAI<boss_halazziAI>(creature);
_scheduler.Schedule(0s, [this](TaskContext& task)
{
switch (task.GetRepeatCounter())
{
case 0:
DoZoneInCombat();
DoCastSelf(SPELL_SPIRIT_CHANNEL);
task.Repeat(1200ms);
break;
case 1:
DoCastSelf(SPELL_SPIRIT_EFFECT, true);
break;
default:
break;
}
});
}
void Reset() override
{
_scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler
.Schedule(4s, [this](TaskContext& task)
{
DoCastVictim(SPELL_SHRED_ARMOR);
task.Repeat(4s);
})
.Schedule(5s, 10s, [this](TaskContext& task)
{
DoCastSelf(SPELL_LYNX_FLURRY);
task.Repeat(15s, 20s);
});
}
void OnHealthDepleted(Unit* /*killer*/, bool /*isKill*/) override
{
if (Creature* halazzi = _instance->GetCreature(BOSS_HALAZZI))
halazzi->AI()->DoAction(ACTION_BEGIN_MERGE);
/// @todo: This part requires sniff verification. Basically copied from Halazzi's low health actions
me->SetReactState(REACT_PASSIVE);
me->DespawnOrUnsummon(3s);
}
void DoAction(int32 action) override
{
if (action == ACTION_INFORM_LYNX)
{
me->SetReactState(REACT_PASSIVE);
me->DespawnOrUnsummon(3s);
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
UpdateVictim();
}
private:
TaskScheduler _scheduler;
InstanceScript* _instance;
};
// 24224 - Corrupted Lightning Totem
struct npc_corrupted_lightning_totem : public ScriptedAI
{
using ScriptedAI::ScriptedAI;
void InitializeAI() override
{
me->SetReactState(REACT_PASSIVE);
}
void JustAppeared() override
{
DoZoneInCombat();
_scheduler.Schedule(2400ms, [this](TaskContext& task)
{
std::vector<Player*> playerList;
GetPlayerListInGrid(playerList, me, 30.0f);
Trinity::Containers::RandomResize(playerList, 1);
for (Player* player : playerList)
DoCast(player, SPELL_LIGHTNING);
task.Repeat(2400ms);
});
}
void Reset() override
{
_scheduler.CancelAll();
}
void UpdateAI(uint32 diff) override
{
UpdateVictim();
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
// 43536 - Set Health
// 43537 - Set Health
// 43538 - Set Health
class spell_halazzi_set_health : public SpellScript
{
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->SetHealth(GetCaster()->CountPctFromMaxHealth(GetEffectValue()));
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_halazzi_set_health::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_boss_halazzi()
{
new boss_halazzi();
RegisterZulAmanCreatureAI(boss_halazzi);
RegisterZulAmanCreatureAI(npc_spirit_of_the_lynx);
RegisterZulAmanCreatureAI(npc_corrupted_lightning_totem);
RegisterSpellScript(spell_halazzi_set_health);
}