diff --git a/data/sql/updates/pending_db_world/rev_1701608044519062000.sql b/data/sql/updates/pending_db_world/rev_1701608044519062000.sql new file mode 100644 index 000000000..2f2abf98f --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1701608044519062000.sql @@ -0,0 +1,6 @@ +-- +SET @ENTRY := 25040; -- Greater Water Elemental +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = @ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid` = @ENTRY AND `source_type` = 0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(@ENTRY, 0, 1, 0, 0, 0, 100, 0, 3000, 3000, 5000, 5000, 11, 46983, 64, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 'Greater Water Elemental - In Combat - Cast Waterbolt'); diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp index c3b59c8f5..a7a749c97 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp @@ -23,14 +23,16 @@ enum Spells SPELL_ARCANE_EXPLOSION = 46608, SPELL_CONE_OF_COLD = 38384, SPELL_FIREBALL = 46988, - SPELL_FROSTBOLT = 46987 + SPELL_FROSTBOLT = 46987, + SPELL_SUMMON_WATER_ELEMENTAL = 45067, + SPELL_ICEBLOCK = 46604 }; enum Yells { - YELL_AGGRO = 0, - YELL_EVADE = 1, - YELL_SALVATION = 2, + SAY_AGGRO = 0, + SAY_EVADE = 1, + SAY_SALVATION = 2, }; enum Creatures @@ -38,181 +40,110 @@ enum Creatures NPC_WATER_ELEMENTAL = 25040 }; -enum WaterElementalSpells +struct boss_balinda : public ScriptedAI { - SPELL_WATERBOLT = 46983 -}; - -class npc_water_elemental : public CreatureScript -{ -public: - npc_water_elemental() : CreatureScript("npc_water_elemental") { } - - struct npc_water_elementalAI : public ScriptedAI + boss_balinda(Creature* creature) : ScriptedAI(creature), summons(me), _hasCastIceBlock(false) { - npc_water_elementalAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 waterBoltTimer; - ObjectGuid balindaGUID; - uint32 resetTimer; - - void Reset() override + scheduler.SetValidator([this] { - waterBoltTimer = 3 * IN_MILLISECONDS; - resetTimer = 5 * IN_MILLISECONDS; - balindaGUID.Clear(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (waterBoltTimer < diff) - { - DoCastVictim(SPELL_WATERBOLT); - waterBoltTimer = 5 * IN_MILLISECONDS; - } - else waterBoltTimer -= diff; - - // check if creature is not outside of building - if (resetTimer < diff) - { - if (Creature* pBalinda = ObjectAccessor::GetCreature(*me, balindaGUID)) - if (me->GetDistance2d(pBalinda->GetHomePosition().GetPositionX(), pBalinda->GetHomePosition().GetPositionY()) > 50) - EnterEvadeMode(); - resetTimer = 5 * IN_MILLISECONDS; - } - else resetTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_water_elementalAI(creature); + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } -}; -class boss_balinda : public CreatureScript -{ -public: - boss_balinda() : CreatureScript("boss_balinda") { } - - struct boss_balindaAI : public ScriptedAI + void Reset() override { - boss_balindaAI(Creature* creature) : ScriptedAI(creature), summons(me) { } + summons.DespawnAll(); + } - uint32 arcaneExplosionTimer; - uint32 coneOfColdTimer; - uint32 fireBoltTimer; - uint32 frostboltTimer; - uint32 resetTimer; - uint32 waterElementalTimer; + void JustEngagedWith(Unit* /*who*/) override + { + _hasCastIceBlock = false; - SummonList summons; + Talk(SAY_AGGRO); - void Reset() override + ScheduleTimedEvent(3s, [&] { - arcaneExplosionTimer = urand(5 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); - coneOfColdTimer = 8 * IN_MILLISECONDS; - fireBoltTimer = 1 * IN_MILLISECONDS; - frostboltTimer = 4 * IN_MILLISECONDS; - resetTimer = 5 * IN_MILLISECONDS; - waterElementalTimer = 0; - - summons.DespawnAll(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(YELL_AGGRO); - } - - void JustRespawned() override - { - Reset(); - } - - void JustSummoned(Creature* summoned) override - { - CAST_AI(npc_water_elemental::npc_water_elementalAI, summoned->AI())->balindaGUID = me->GetGUID(); - summoned->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 50, true)); - summoned->SetFaction(me->GetFaction()); - summons.Summon(summoned); - } - - void JustDied(Unit* /*killer*/) override - { - summons.DespawnAll(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (waterElementalTimer < diff) + if (summons.empty()) { - if (summons.empty()) - me->SummonCreature(NPC_WATER_ELEMENTAL, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45 * IN_MILLISECONDS); - waterElementalTimer = 50 * IN_MILLISECONDS; + DoCast(SPELL_SUMMON_WATER_ELEMENTAL); } - else waterElementalTimer -= diff; + }, 50s, 50s); - if (arcaneExplosionTimer < diff) + ScheduleTimedEvent(5s, 15s, [&] + { + DoCastAOE(SPELL_ARCANE_EXPLOSION); + }, 5s, 15s); + + ScheduleTimedEvent(8s, [&] + { + DoCastVictim(SPELL_CONE_OF_COLD); + }, 10s, 20s); + + ScheduleTimedEvent(1s, [&] + { + DoCastVictim(SPELL_FIREBALL); + }, 5s, 9s); + + ScheduleTimedEvent(4s, [&] + { + DoCastVictim(SPELL_FROSTBOLT); + }, 4s, 12s); + + ScheduleTimedEvent(5s, [&] + { + if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) { - DoCastVictim(SPELL_ARCANE_EXPLOSION); - arcaneExplosionTimer = urand(5 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); + EnterEvadeMode(); + Talk(SAY_EVADE); } - else arcaneExplosionTimer -= diff; - if (coneOfColdTimer < diff) + if (Creature* elemental = summons.GetCreatureWithEntry(NPC_WATER_ELEMENTAL)) { - DoCastVictim(SPELL_CONE_OF_COLD); - coneOfColdTimer = urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS); - } - else coneOfColdTimer -= diff; - - if (fireBoltTimer < diff) - { - DoCastVictim(SPELL_FIREBALL); - fireBoltTimer = urand(5 * IN_MILLISECONDS, 9 * IN_MILLISECONDS); - } - else fireBoltTimer -= diff; - - if (frostboltTimer < diff) - { - DoCastVictim(SPELL_FROSTBOLT); - frostboltTimer = urand(4 * IN_MILLISECONDS, 12 * IN_MILLISECONDS); - } - else frostboltTimer -= diff; - - // check if creature is not outside of building - if (resetTimer < diff) - { - if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) + if (elemental->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) { - EnterEvadeMode(); - Talk(YELL_EVADE); + elemental->AI()->EnterEvadeMode(); } - resetTimer = 5 * IN_MILLISECONDS; } - else resetTimer -= diff; - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new boss_balindaAI(creature); + }, 5s, 5s); } + + void JustSummoned(Creature* summoned) override + { + summoned->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 50, true)); + summoned->SetFaction(me->GetFaction()); + summons.Summon(summoned); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override + { + if (me->HealthBelowPctDamaged(40, damage) && !_hasCastIceBlock) + { + DoCast(SPELL_ICEBLOCK); + _hasCastIceBlock = true; + } + } + + void JustDied(Unit* /*killer*/) override + { + summons.DespawnAll(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + scheduler.Update(diff, + std::bind(&ScriptedAI::DoMeleeAttackIfReady, this)); + } + +private: + SummonList summons; + bool _hasCastIceBlock; }; void AddSC_boss_balinda() { - new boss_balinda; - new npc_water_elemental; + RegisterCreatureAI(boss_balinda); }