From b55ebc186ddec46843277c8ccf3059a2bdf18b37 Mon Sep 17 00:00:00 2001 From: Dan <83884799+elthehablo@users.noreply.github.com> Date: Tue, 18 Jul 2023 13:45:58 +0200 Subject: [PATCH 01/19] fix(Scripts/TempleOfAhnQiraj): make C'thun Dark Glare face location of last eyebeam before cast, instead of random target (#16785) * initial * fix oopsie * whitespace --- .../Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index df615ef0d..306c6c569 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp @@ -242,7 +242,11 @@ struct boss_eye_of_cthun : public BossAI { scheduler.Schedule(5s, [this](TaskContext task) { - DoCastRandomTarget(SPELL_GREEN_BEAM); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + { + DoCast(target, SPELL_GREEN_BEAM); + DarkGlareAngle = me->GetAngle(target); //keep as the location dark glare will be at + } task.SetGroup(GROUP_BEAM_PHASE); task.Repeat(3s); @@ -284,21 +288,18 @@ struct boss_eye_of_cthun : public BossAI scheduler.Schedule(1s, [this](TaskContext /*task*/) { - //Select random target for dark beam to start on - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) - { - //Face our target - DarkGlareAngle = me->GetAngle(target); - DarkGlareTick = 0; - ClockWise = RAND(true, false); + //Select last target that had a beam cast on it + //Face our target - //Add red coloration to C'thun - DoCast(me, SPELL_RED_COLORATION, true); + DarkGlareTick = 0; + ClockWise = RAND(true, false); - me->StopMoving(); - me->SetFacingToObject(target); - me->SetOrientation(DarkGlareAngle); - } + //Add red coloration to C'thun + DoCast(me, SPELL_RED_COLORATION, true); + + me->StopMoving(); + me->SetOrientation(DarkGlareAngle); + me->SetFacingTo(DarkGlareAngle); scheduler.Schedule(3s, [this](TaskContext tasker) { From 89e7fb301a6bc2d0decda25e25f23b59fe09f931 Mon Sep 17 00:00:00 2001 From: Dan <83884799+elthehablo@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:56:00 +0200 Subject: [PATCH 02/19] chore(Scripts/Karazhan): rework Shade of Aran using TaskScheduler and fixes (#16689) --- .../Karazhan/boss_shade_of_aran.cpp | 869 ++++++++---------- 1 file changed, 384 insertions(+), 485 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp index 063b3937c..50fab68d7 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp @@ -20,6 +20,7 @@ #include "ScriptedCreature.h" #include "SpellInfo.h" #include "karazhan.h" +#include "TaskScheduler.h" enum ShadeOfAran { @@ -58,9 +59,9 @@ enum ShadeOfAran SPELL_SHADOW_PYRO = 29978, //Creatures - CREATURE_WATER_ELEMENTAL = 17167, - CREATURE_SHADOW_OF_ARAN = 18254, - CREATURE_ARAN_BLIZZARD = 17161, + NPC_WATER_ELEMENTAL = 17167, + NPC_SHADOW_OF_ARAN = 18254, + NPC_ARAN_BLIZZARD = 17161, }; enum SuperSpell @@ -70,560 +71,458 @@ enum SuperSpell SUPER_AE, }; -class boss_shade_of_aran : public CreatureScript +enum Groups { -public: - boss_shade_of_aran() : CreatureScript("boss_shade_of_aran") { } + GROUP_FLAMEWREATH = 0, + GROUP_DRINKING = 1 +}; - struct boss_aranAI : public BossAI +Position const elementalPos[4] = +{ + {-11168.1f, -1939.29f, 232.092f, 1.46f}, + {-11138.2f, -1915.38f, 232.092f, 3.00f}, + {-11161.7f, -1885.36f, 232.092f, 4.59f}, + {-11192.4f, -1909.36f, 232.092f, 6.19f} +}; + +struct boss_shade_of_aran : public BossAI +{ + boss_shade_of_aran(Creature* creature) : BossAI(creature, DATA_ARAN) { - boss_aranAI(Creature* creature) : BossAI(creature, DATA_ARAN) + scheduler.SetValidator([this] { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + uint8 LastSuperSpell; + + ObjectGuid FlameWreathTarget[3]; + float FWTargPosX[3]; + float FWTargPosY[3]; + + uint32 CurrentNormalSpell; + + bool Drinking; + + void Reset() override + { + BossAI::Reset(); + drinkScheduler.CancelAll(); + LastSuperSpell = rand() % 3; + + for (uint8 i = 0; i < 3; ++i) + FlameWreathTarget[i].Clear(); + + CurrentNormalSpell = 0; + + _arcaneCooledDown = true; + _fireCooledDown = true; + _frostCooledDown = true; + + Drinking = false; + + // Not in progress + instance->SetData(DATA_ARAN, NOT_STARTED); + + if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR))) + { + libraryDoor->SetGoState(GO_STATE_ACTIVE); + libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); } - uint32 SecondarySpellTimer; - uint32 NormalCastTimer; - uint32 SuperCastTimer; - uint32 BerserkTimer; - uint32 CloseDoorTimer; // Don't close the door right on aggro in case some people are still entering. + ScheduleHealthCheckEvent(40, [&]{ + Talk(SAY_ELEMENTALS); - uint8 LastSuperSpell; - - uint32 FlameWreathTimer; - uint32 FlameWreathCheckTime; - ObjectGuid FlameWreathTarget[3]; - float FWTargPosX[3]; - float FWTargPosY[3]; - - uint32 CurrentNormalSpell; - uint32 ArcaneCooldown; - uint32 FireCooldown; - uint32 FrostCooldown; - - uint32 DrinkInterruptTimer; - - bool ElementalsSpawned; - bool Drinking; - bool DrinkInturrupted; - void Reset() override - { - SecondarySpellTimer = 5000; - NormalCastTimer = 0; - SuperCastTimer = 35000; - BerserkTimer = 720000; - CloseDoorTimer = 15000; - - LastSuperSpell = rand() % 3; - - FlameWreathTimer = 0; - FlameWreathCheckTime = 0; - - for (uint8 i = 0; i < 3; ++i) - FlameWreathTarget[i].Clear(); - - CurrentNormalSpell = 0; - ArcaneCooldown = 0; - FireCooldown = 0; - FrostCooldown = 0; - - DrinkInterruptTimer = 10000; - - ElementalsSpawned = false; - Drinking = false; - DrinkInturrupted = false; - - // Not in progress - instance->SetData(DATA_ARAN, NOT_STARTED); - - if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR))) + for(Position pos : elementalPos) { - libraryDoor->SetGoState(GO_STATE_ACTIVE); - libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); + if(Creature* elemental = me->SummonCreature(NPC_WATER_ELEMENTAL, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000)) + { + if(Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true)) + { + DoStartNoMovement(target); + elemental->SetInCombatWithZone(); + elemental->CombatStart(target); + } + } } - } + }); + } - void KilledUnit(Unit* /*victim*/) override + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_KILL); + } + + void TriggerArcaneCooldown() + { + scheduler.Schedule(5s, [this](TaskContext) { - Talk(SAY_KILL); - } + _arcaneCooledDown = true; + }); + } - void JustDied(Unit* /*killer*/) override + void TriggerFireCooldown() + { + scheduler.Schedule(5s, [this](TaskContext) { - Talk(SAY_DEATH); + _fireCooledDown = true; + }); + } - instance->SetData(DATA_ARAN, DONE); - - if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR))) - { - libraryDoor->SetGoState(GO_STATE_ACTIVE); - libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - } - - void JustEngagedWith(Unit* /*who*/) override + void TriggerFrostCooldown() + { + scheduler.Schedule(5s, [this](TaskContext) { - Talk(SAY_AGGRO); + _frostCooledDown = true; + }); + } - instance->SetData(DATA_ARAN, IN_PROGRESS); + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + instance->SetData(DATA_ARAN, DONE); + + if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR))) + { + libraryDoor->SetGoState(GO_STATE_ACTIVE); + libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + + instance->SetData(DATA_ARAN, IN_PROGRESS); + + DoZoneInCombat(); + + //handle timed closing door + scheduler.Schedule(15s, [this](TaskContext) + { if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR))) { libraryDoor->SetGoState(GO_STATE_READY); libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); } - - DoZoneInCombat(); - } - - void FlameWreathEffect() + }).Schedule(1ms, [this](TaskContext context) { - std::vector targets; - ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList(); - - if (t_list.empty()) - return; - - //store the threat list in a different container - for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr) + if (!me->IsNonMeleeSpellCast(false)) { - Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); - //only on alive players - if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); - } + Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true); + if (!target) + return; - //cut down to size if we have more than 3 targets - while (targets.size() > 3) - targets.erase(targets.begin() + rand() % targets.size()); + uint32 Spells[3]; + uint8 AvailableSpells = 0; - uint32 i = 0; - for (std::vector::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - if (*itr) + //Check for what spells are not on cooldown + if (_arcaneCooledDown) { - FlameWreathTarget[i] = (*itr)->GetGUID(); - FWTargPosX[i] = (*itr)->GetPositionX(); - FWTargPosY[i] = (*itr)->GetPositionY(); - DoCast((*itr), SPELL_FLAME_WREATH, true); - ++i; + Spells[AvailableSpells] = SPELL_ARCMISSLE; + ++AvailableSpells; + } + if (_fireCooledDown) + { + Spells[AvailableSpells] = SPELL_FIREBALL; + ++AvailableSpells; + } + if (_frostCooledDown) + { + Spells[AvailableSpells] = SPELL_FROSTBOLT; + ++AvailableSpells; + } + + //If no available spells wait 1 second and try again + if (AvailableSpells) + { + CurrentNormalSpell = Spells[rand() % AvailableSpells]; + DoCast(target, CurrentNormalSpell); } } - } - - void UpdateAI(uint32 diff) override + context.Repeat(10s); + }).Schedule(5s, [this](TaskContext context) { - if (!UpdateVictim()) - return; - - if (CloseDoorTimer) + switch (urand(0, 1)) { - if (CloseDoorTimer <= diff) - { - if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR))) + case 0: + DoCastSelf(SPELL_AOE_CS); + break; + case 1: + DoCastRandomTarget(SPELL_CHAINSOFICE); + break; + } + context.Repeat(5s, 20s); + }).Schedule(35s, [this](TaskContext context) + { + uint8 Available[2]; + + switch (LastSuperSpell) + { + case SUPER_AE: + Available[0] = SUPER_FLAME; + Available[1] = SUPER_BLIZZARD; + break; + case SUPER_FLAME: + Available[0] = SUPER_AE; + Available[1] = SUPER_BLIZZARD; + break; + case SUPER_BLIZZARD: + Available[0] = SUPER_FLAME; + Available[1] = SUPER_AE; + break; + } + + LastSuperSpell = Available[urand(0, 1)]; + + switch (LastSuperSpell) + { + case SUPER_AE: + Talk(SAY_EXPLOSION); + + DoCastSelf(SPELL_BLINK_CENTER, true); + DoCastSelf(SPELL_PLAYERPULL, true); + DoCastSelf(SPELL_MASSSLOW, true); + DoCastSelf(SPELL_AEXPLOSION, false); + break; + + case SUPER_FLAME: + Talk(SAY_FLAMEWREATH); + + scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext) { - libraryDoor->SetGoState(GO_STATE_READY); - libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - CloseDoorTimer = 0; - } - else - CloseDoorTimer -= diff; - } - - //Cooldowns for casts - if (ArcaneCooldown) - { - if (ArcaneCooldown >= diff) - ArcaneCooldown -= diff; - else - ArcaneCooldown = 0; - } - - if (FireCooldown) - { - if (FireCooldown >= diff) - FireCooldown -= diff; - else - FireCooldown = 0; - } - - if (FrostCooldown) - { - if (FrostCooldown >= diff) - FrostCooldown -= diff; - else - FrostCooldown = 0; - } - - if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20) - { - Drinking = true; - me->InterruptNonMeleeSpells(false); - - Talk(SAY_DRINK); - - if (!DrinkInturrupted) - { - DoCast(me, SPELL_MASS_POLY, true); - DoCast(me, SPELL_CONJURE, false); - DoCast(me, SPELL_DRINK, false); - me->SetStandState(UNIT_STAND_STATE_SIT); - DrinkInterruptTimer = 10000; - } - } - - //Drink Interrupt - if (Drinking && DrinkInturrupted) - { - Drinking = false; - me->RemoveAurasDueToSpell(SPELL_DRINK); - me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000); - DoCast(me, SPELL_POTION, false); - } - - //Drink Interrupt Timer - if (Drinking && !DrinkInturrupted) - { - if (DrinkInterruptTimer >= diff) - DrinkInterruptTimer -= diff; - else - { - me->SetStandState(UNIT_STAND_STATE_STAND); - DoCast(me, SPELL_POTION, true); - DoCast(me, SPELL_AOE_PYROBLAST, false); - DrinkInturrupted = true; - Drinking = false; - } - } - - //Don't execute any more code if we are drinking - if (Drinking) - return; - - //Normal casts - if (NormalCastTimer <= diff) - { - if (!me->IsNonMeleeSpellCast(false)) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true); - if (!target) - return; - - uint32 Spells[3]; - uint8 AvailableSpells = 0; - - //Check for what spells are not on cooldown - if (!ArcaneCooldown) + scheduler.CancelGroup(GROUP_FLAMEWREATH); + }).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context) { - Spells[AvailableSpells] = SPELL_ARCMISSLE; - ++AvailableSpells; - } - if (!FireCooldown) - { - Spells[AvailableSpells] = SPELL_FIREBALL; - ++AvailableSpells; - } - if (!FrostCooldown) - { - Spells[AvailableSpells] = SPELL_FROSTBOLT; - ++AvailableSpells; - } - - //If no available spells wait 1 second and try again - if (AvailableSpells) - { - CurrentNormalSpell = Spells[rand() % AvailableSpells]; - DoCast(target, CurrentNormalSpell); - } - } - NormalCastTimer = 1000; - } - else - NormalCastTimer -= diff; - - if (SecondarySpellTimer <= diff) - { - switch (urand(0, 1)) - { - case 0: - DoCast(me, SPELL_AOE_CS); - break; - case 1: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_CHAINSOFICE); - break; - } - SecondarySpellTimer = urand(5000, 20000); - } - else - SecondarySpellTimer -= diff; - - if (SuperCastTimer <= diff) - { - uint8 Available[2]; - - switch (LastSuperSpell) - { - case SUPER_AE: - Available[0] = SUPER_FLAME; - Available[1] = SUPER_BLIZZARD; - break; - case SUPER_FLAME: - Available[0] = SUPER_AE; - Available[1] = SUPER_BLIZZARD; - break; - case SUPER_BLIZZARD: - Available[0] = SUPER_FLAME; - Available[1] = SUPER_AE; - break; - } - - LastSuperSpell = Available[urand(0, 1)]; - - switch (LastSuperSpell) - { - case SUPER_AE: - Talk(SAY_EXPLOSION); - - DoCast(me, SPELL_BLINK_CENTER, true); - DoCast(me, SPELL_PLAYERPULL, true); - DoCast(me, SPELL_MASSSLOW, true); - DoCast(me, SPELL_AEXPLOSION, false); - break; - - case SUPER_FLAME: - Talk(SAY_FLAMEWREATH); - - FlameWreathTimer = 20000; - FlameWreathCheckTime = 500; - - FlameWreathTarget[0].Clear(); - FlameWreathTarget[1].Clear(); - FlameWreathTarget[2].Clear(); - - FlameWreathEffect(); - break; - - case SUPER_BLIZZARD: - Talk(SAY_BLIZZARD); - - if (Creature* pSpawn = me->SummonCreature(CREATURE_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000)) + for (uint8 i = 0; i < 3; ++i) { - pSpawn->SetFaction(me->GetFaction()); - pSpawn->CastSpell(pSpawn, SPELL_CIRCULAR_BLIZZARD, false); + if (!FlameWreathTarget[i]) + continue; + + Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]); + if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3)) + { + unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID()); + unit->CastSpell(unit, 11027, true); + FlameWreathTarget[i].Clear(); + } } - break; - } + context.Repeat(500ms); + }); - SuperCastTimer = urand(35000, 40000); - } - else - SuperCastTimer -= diff; + FlameWreathTarget[0].Clear(); + FlameWreathTarget[1].Clear(); + FlameWreathTarget[2].Clear(); - if (!ElementalsSpawned && HealthBelowPct(40)) - { - ElementalsSpawned = true; + FlameWreathEffect(); + break; - Creature* ElementalOne = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11168.1f, -1939.29f, 232.092f, 1.46f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); - Creature* ElementalTwo = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11138.2f, -1915.38f, 232.092f, 3.00f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); - Creature* ElementalThree = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11161.7f, -1885.36f, 232.092f, 4.59f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); - Creature* ElementalFour = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11192.4f, -1909.36f, 232.092f, 6.19f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); + case SUPER_BLIZZARD: + Talk(SAY_BLIZZARD); - if (ElementalOne) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true); - if (!target) - return; - - DoStartNoMovement(target); - ElementalOne->SetInCombatWithZone(); - ElementalOne->CombatStart(target); - ElementalOne->SetFaction(me->GetFaction()); - ElementalOne->SetUnitMovementFlags(MOVEMENTFLAG_ROOT); - ElementalOne->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0); - } - - if (ElementalTwo) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true); - if (!target) - return; - - DoStartNoMovement(target); - ElementalTwo->SetInCombatWithZone(); - ElementalTwo->CombatStart(target); - ElementalTwo->SetFaction(me->GetFaction()); - ElementalTwo->SetUnitMovementFlags(MOVEMENTFLAG_ROOT); - ElementalTwo->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0); - } - - if (ElementalThree) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true); - if (!target) - return; - - DoStartNoMovement(target); - ElementalThree->SetInCombatWithZone(); - ElementalThree->CombatStart(target); - ElementalThree->SetFaction(me->GetFaction()); - ElementalThree->SetUnitMovementFlags(MOVEMENTFLAG_ROOT); - ElementalThree->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0); - } - - if (ElementalFour) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true); - if (!target) - return; - - DoStartNoMovement(target); - ElementalFour->SetInCombatWithZone(); - ElementalFour->CombatStart(target); - ElementalFour->SetFaction(me->GetFaction()); - ElementalFour->SetUnitMovementFlags(MOVEMENTFLAG_ROOT); - ElementalFour->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0); - } - - Talk(SAY_ELEMENTALS); - } - - if (BerserkTimer <= diff) - { - for (uint32 i = 0; i < 5; ++i) - { - if (Creature* unit = me->SummonCreature(CREATURE_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000)) + if (Creature* pSpawn = me->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000)) { - unit->Attack(me->GetVictim(), true); - unit->SetFaction(me->GetFaction()); + pSpawn->SetFaction(me->GetFaction()); + pSpawn->CastSpell(me, SPELL_CIRCULAR_BLIZZARD, false); } - } - - Talk(SAY_TIMEOVER); - - BerserkTimer = 60000; + break; } - else - BerserkTimer -= diff; - - //Flame Wreath check - if (FlameWreathTimer) + context.Repeat(35s, 40s); + }).Schedule(12min, [this](TaskContext context) + { + for (uint32 i = 0; i < 5; ++i) { - if (FlameWreathTimer >= diff) - FlameWreathTimer -= diff; - else - FlameWreathTimer = 0; - - if (FlameWreathCheckTime <= diff) + if (Creature* unit = me->SummonCreature(NPC_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000)) { - for (uint8 i = 0; i < 3; ++i) - { - if (!FlameWreathTarget[i]) - continue; - - Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]); - if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3)) - { - unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID()); - unit->CastSpell(unit, 11027, true); - FlameWreathTarget[i].Clear(); - } - } - FlameWreathCheckTime = 500; + unit->Attack(me->GetVictim(), true); + unit->SetFaction(me->GetFaction()); } - else - FlameWreathCheckTime -= diff; } - if (ArcaneCooldown && FireCooldown && FrostCooldown) - DoMeleeAttackIfReady(); + Talk(SAY_TIMEOVER); + + context.Repeat(1min); + }); + } + + void FlameWreathEffect() + { + std::vector targets; + ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList(); + + if (t_list.empty()) + return; + + //store the threat list in a different container + for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr) + { + Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); + //only on alive players + if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER) + targets.push_back(target); } - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + //cut down to size if we have more than 3 targets + while (targets.size() > 3) + targets.erase(targets.begin() + rand() % targets.size()); + + uint32 i = 0; + for (std::vector::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) { - if (!DrinkInturrupted && Drinking && damage) - DrinkInturrupted = true; + if (*itr) + { + FlameWreathTarget[i] = (*itr)->GetGUID(); + FWTargPosX[i] = (*itr)->GetPositionX(); + FWTargPosY[i] = (*itr)->GetPositionY(); + DoCast((*itr), SPELL_FLAME_WREATH, true); + ++i; + } } + } - void SpellHit(Unit* /*pAttacker*/, SpellInfo const* Spell) override + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + drinkScheduler.Update(diff); + + if (!UpdateVictim()) + return; + + if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20) { - //We only care about interrupt effects and only if they are durring a spell currently being cast - if ((Spell->Effects[0].Effect != SPELL_EFFECT_INTERRUPT_CAST && - Spell->Effects[1].Effect != SPELL_EFFECT_INTERRUPT_CAST && - Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCast(false)) - return; - - //Interrupt effect + Drinking = true; me->InterruptNonMeleeSpells(false); - //Normally we would set the cooldown equal to the spell duration - //but we do not have access to the DurationStore + Talk(SAY_DRINK); - switch (CurrentNormalSpell) + scheduler.DelayAll(10s); + DoCastSelf(SPELL_MASS_POLY, true); + DoCastSelf(SPELL_CONJURE, false); + me->SetReactState(REACT_PASSIVE); + me->SetStandState(UNIT_STAND_STATE_SIT); + DoCastSelf(SPELL_DRINK, true); + _currentHealth = me->GetHealth(); + drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context) { - case SPELL_ARCMISSLE: - ArcaneCooldown = 5000; - break; - case SPELL_FIREBALL: - FireCooldown = 5000; - break; - case SPELL_FROSTBOLT: - FrostCooldown = 5000; - break; + //check for damage to interrupt + if(CheckDamageDuringDrinking(_currentHealth)) + { + Drinking = false; + me->RemoveAurasDueToSpell(SPELL_DRINK); + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SetReactState(REACT_AGGRESSIVE); + me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000); + DoCastSelf(SPELL_POTION, false); + DoCastSelf(SPELL_AOE_PYROBLAST, false); + drinkScheduler.CancelGroup(GROUP_DRINKING); + } else { + context.Repeat(500ms); + } + }).Schedule(10s, GROUP_DRINKING, [this](TaskContext) + { + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SetReactState(REACT_AGGRESSIVE); + me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000); + DoCastSelf(SPELL_POTION, true); + DoCastSelf(SPELL_AOE_PYROBLAST, false); + + Drinking = false; + drinkScheduler.CancelGroup(GROUP_DRINKING); + }); + } + + if (_arcaneCooledDown && _fireCooledDown && _frostCooledDown && !Drinking) + DoMeleeAttackIfReady(); + } + + bool CheckDamageDuringDrinking(uint32 oldHealth) + { + if (Drinking) + { + if (me->GetHealth() < oldHealth) + { + return true; } } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); + return false; } + + void SpellHit(Unit* /*pAttacker*/, SpellInfo const* Spell) override + { + //We only care about interrupt effects and only if they are durring a spell currently being cast + if ((Spell->Effects[0].Effect != SPELL_EFFECT_INTERRUPT_CAST && + Spell->Effects[1].Effect != SPELL_EFFECT_INTERRUPT_CAST && + Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCast(false)) + return; + + //Interrupt effect + me->InterruptNonMeleeSpells(false); + + //Normally we would set the cooldown equal to the spell duration + //but we do not have access to the DurationStore + + switch (CurrentNormalSpell) + { + case SPELL_ARCMISSLE: + TriggerArcaneCooldown(); + break; + case SPELL_FIREBALL: + TriggerFireCooldown(); + break; + case SPELL_FROSTBOLT: + TriggerFrostCooldown(); + break; + } + } +private: + TaskScheduler drinkScheduler; + + bool _arcaneCooledDown; + bool _fireCooledDown; + bool _frostCooledDown; + uint32 _currentHealth; }; -class npc_aran_elemental : public CreatureScript +struct npc_aran_elemental : public ScriptedAI { -public: - npc_aran_elemental() : CreatureScript("npc_aran_elemental") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_aran_elemental(Creature* creature) : ScriptedAI(creature) { - return new water_elementalAI(creature); + SetCombatMovement(false); + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - struct water_elementalAI : public ScriptedAI + void Reset() override { - water_elementalAI(Creature* creature) : ScriptedAI(creature) + _scheduler.CancelAll(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _scheduler.Schedule(2s, [this](TaskContext context) { - } + DoCastVictim(SPELL_WATERBOLT); + context.Repeat(2s); + }); + } - uint32 CastTimer; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void Reset() override - { - CastTimer = 2000 + (rand() % 3000); - } - - void JustEngagedWith(Unit* /*who*/) override { } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (CastTimer <= diff) - { - DoCastVictim(SPELL_WATERBOLT); - CastTimer = urand(2000, 5000); - } - else - CastTimer -= diff; - } - }; + _scheduler.Update(diff); + } +private: + TaskScheduler _scheduler; }; void AddSC_boss_shade_of_aran() { - new boss_shade_of_aran(); - new npc_aran_elemental(); + RegisterKarazhanCreatureAI(boss_shade_of_aran); + RegisterKarazhanCreatureAI(npc_aran_elemental); } From 59886c565733243e57c80516db9cc71a21b2d10a Mon Sep 17 00:00:00 2001 From: Eddy Vega <61223313+Si1ker@users.noreply.github.com> Date: Tue, 18 Jul 2023 10:51:32 -0600 Subject: [PATCH 03/19] refactor(Scripts/Karazhan): Update Attumen and Midnight (#16681) * init * . --- .../Karazhan/boss_midnight.cpp | 666 ++++++++---------- 1 file changed, 308 insertions(+), 358 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp index b64c25a28..82061fcb8 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp @@ -24,18 +24,18 @@ enum Texts { - SAY_KILL = 0, - SAY_RANDOM = 1, - SAY_DISARMED = 2, - SAY_MIDNIGHT_KILL = 3, - SAY_APPEAR = 4, - SAY_MOUNT = 5, + SAY_KILL = 0, + SAY_RANDOM = 1, + SAY_DISARMED = 2, + SAY_MIDNIGHT_KILL = 3, + SAY_APPEAR = 4, + SAY_MOUNT = 5, - SAY_DEATH = 3, + SAY_DEATH = 3, // Midnight - EMOTE_CALL_ATTUMEN = 0, - EMOTE_MOUNT_UP = 1 + EMOTE_CALL_ATTUMEN = 0, + EMOTE_MOUNT_UP = 1 }; enum Spells @@ -45,7 +45,6 @@ enum Spells SPELL_INTANGIBLE_PRESENCE = 29833, SPELL_SPAWN_SMOKE = 10389, SPELL_CHARGE = 29847, - // Midnight SPELL_KNOCKDOWN = 29711, SPELL_SUMMON_ATTUMEN = 29714, @@ -62,406 +61,357 @@ enum Phases enum Actions { - ACTION_SET_MIDNIGHT_PHASE, + ACTION_SET_MIDNIGHT_PHASE }; -class boss_attumen : public CreatureScript +struct boss_attumen : public BossAI { -public: - boss_attumen() : CreatureScript("boss_attumen") { } - - struct boss_attumenAI : public BossAI + boss_attumen(Creature* creature) : BossAI(creature, DATA_ATTUMEN) { - boss_attumenAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN) - { - Initialize(); - } + Initialize(); + } - void Initialize() + void Initialize() + { + _phase = PHASE_NONE; + } + + void Reset() override + { + Initialize(); + } + + bool CanMeleeHit() + { + return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) + { + midnight->AI()->EnterEvadeMode(why); + } + me->DespawnOrUnsummon(); + } + + void ScheduleTasks() override + { + scheduler.Schedule(15s, 25s, [this](TaskContext task) + { + DoCastVictim(SPELL_SHADOWCLEAVE); + task.Repeat(15s, 25s); + }); + scheduler.Schedule(25s, 45s, [this](TaskContext task) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + { + DoCast(target, SPELL_INTANGIBLE_PRESENCE); + } + + task.Repeat(25s, 45s); + }); + scheduler.Schedule(30s, 1min, [this](TaskContext task) + { + Talk(SAY_RANDOM); + task.Repeat(30s, 1min); + }); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override + { + // Attumen does not die until he mounts Midnight, let health fall to 1 and prevent further damage. + if (damage >= me->GetHealth() && _phase != PHASE_MOUNTED) + { + damage = me->GetHealth() - 1; + } + if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage)) { _phase = PHASE_NONE; - } - void Reset() override - { - Initialize(); - } - - bool CanMeleeHit() - { - return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); - } - - void EnterEvadeMode(EvadeReason why) override - { if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) { - midnight->AI()->EnterEvadeMode(why); - } - - me->DespawnOrUnsummon(); - } - - void ScheduleTasks() override - { - scheduler.Schedule(Seconds(15), Seconds(25), [this](TaskContext task) - { - DoCastVictim(SPELL_SHADOWCLEAVE); - task.Repeat(Seconds(15), Seconds(25)); - }); - - scheduler.Schedule(Seconds(25), Seconds(45), [this](TaskContext task) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - { - DoCast(target, SPELL_INTANGIBLE_PRESENCE); - } - - task.Repeat(Seconds(25), Seconds(45)); - }); - - scheduler.Schedule(Seconds(30), Seconds(60), [this](TaskContext task) - { - Talk(SAY_RANDOM); - task.Repeat(Seconds(30), Seconds(60)); - }); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override - { - // Attumen does not die until he mounts Midnight, let health fall to 1 and prevent further damage. - if (damage >= me->GetHealth() && _phase != PHASE_MOUNTED) - { - damage = me->GetHealth() - 1; - } - - if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage)) - { - _phase = PHASE_NONE; - - if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) - { - midnight->AI()->DoCastAOE(SPELL_MOUNT, true); - } + midnight->AI()->DoCastAOE(SPELL_MOUNT, true); } } + } - void KilledUnit(Unit* /*victim*/) override + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) { Talk(SAY_KILL); } + } - void JustSummoned(Creature* summon) override + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED) { - if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED) - { - if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) - { - if (midnight->GetHealth() > me->GetHealth()) - { - summon->SetHealth(midnight->GetHealth()); - } - else - { - summon->SetHealth(me->GetHealth()); - } - - summon->AI()->DoZoneInCombat(); - } - } - - BossAI::JustSummoned(summon); - } - - void IsSummonedBy(WorldObject* summoner) override - { - if (summoner->GetEntry() == NPC_MIDNIGHT) - { - _phase = PHASE_ATTUMEN_ENGAGES; - } - - if (summoner->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN) - { - _phase = PHASE_MOUNTED; - DoCastSelf(SPELL_SPAWN_SMOKE); - - scheduler.Schedule(Seconds(10), Seconds(25), [this](TaskContext task) - { - Unit* target = nullptr; - std::vector target_list; - - for (auto* ref : me->GetThreatMgr().GetUnsortedThreatList()) - { - target = ref->GetVictim(); - if (target && !target->IsWithinDist(me, 8.00f, false) && target->IsWithinDist(me, 25.0f, false)) - target_list.push_back(target); - - target = nullptr; - } - - if (!target_list.empty()) - { - target = Acore::Containers::SelectRandomContainerElement(target_list); - } - - DoCast(target, SPELL_CHARGE); - task.Repeat(Seconds(10), Seconds(25)); - }); - - scheduler.Schedule(Seconds(25), Seconds(35), [this](TaskContext task) - { - DoCastVictim(SPELL_KNOCKDOWN); - task.Repeat(Seconds(25), Seconds(35)); - }); - } - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) { - midnight->KillSelf(); + if (midnight->GetHealth() > me->GetHealth()) + { + summon->SetHealth(midnight->GetHealth()); + } + else + { + summon->SetHealth(me->GetHealth()); + } + summon->AI()->DoZoneInCombat(); } + } + BossAI::JustSummoned(summon); + } - _JustDied(); + void IsSummonedBy(WorldObject* summoner) override + { + if (summoner->GetEntry() == NPC_MIDNIGHT) + { + _phase = PHASE_ATTUMEN_ENGAGES; + } + if (summoner->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN) + { + _phase = PHASE_MOUNTED; + DoCastSelf(SPELL_SPAWN_SMOKE); + scheduler.Schedule(10s, 25s, [this](TaskContext task) + { + Unit* target = nullptr; + std::vector target_list; + for (auto* ref : me->GetThreatMgr().GetUnsortedThreatList()) + { + target = ref->GetVictim(); + if (target && !target->IsWithinDist(me, 8.00f, false) && target->IsWithinDist(me, 25.0f, false)) + { + target_list.push_back(target); + } + target = nullptr; + } + if (!target_list.empty()) + { + target = Acore::Containers::SelectRandomContainerElement(target_list); + } + DoCast(target, SPELL_CHARGE); + task.Repeat(10s, 25s); + }); + scheduler.Schedule(25s, 35s, [this](TaskContext task) + { + DoCastVictim(SPELL_KNOCKDOWN); + task.Repeat(25s, 35s); + }); + } + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) + { + midnight->KillSelf(); + } + _JustDied(); + } + + void UpdateAI(uint32 diff) override + { + if (_phase != PHASE_NONE) + { + if (!UpdateVictim()) + { + return; + } + } + if (!CanMeleeHit()) + { + BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY); + } + scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this)); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Mechanic == MECHANIC_DISARM) + { + Talk(SAY_DISARMED); } - void UpdateAI(uint32 diff) override + if (spellInfo->Id == SPELL_MOUNT) { - if (_phase != PHASE_NONE) + if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) { - if (!UpdateVictim()) + _phase = PHASE_NONE; + scheduler.CancelAll(); + midnight->AI()->DoAction(ACTION_SET_MIDNIGHT_PHASE); + midnight->AttackStop(); + midnight->RemoveAllAttackers(); + midnight->SetReactState(REACT_PASSIVE); + midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f); + midnight->AI()->Talk(EMOTE_MOUNT_UP); + me->AttackStop(); + me->RemoveAllAttackers(); + me->SetReactState(REACT_PASSIVE); + me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f); + Talk(SAY_MOUNT); + scheduler.Schedule(1s, [this](TaskContext task) { - return; - } + if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) + { + if (me->IsWithinDist2d(midnight, 5.0f)) + { + DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED); + me->DespawnOrUnsummon(1s, 0s); + midnight->SetVisible(false); + } + else + { + midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f); + me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f); + task.Repeat(); + } + } + }); } + } + } +private: + uint8 _phase; +}; + +struct boss_midnight : public BossAI +{ + boss_midnight(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { } + + void Reset() override + { + BossAI::Reset(); + me->SetVisible(true); + me->SetReactState(REACT_DEFENSIVE); + } + + bool CanMeleeHit() + { + return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override + { + // Midnight never dies, let health fall to 1 and prevent further damage. + if (damage >= me->GetHealth()) + { + damage = me->GetHealth() - 1; + } + + if (_phase == PHASE_NONE && me->HealthBelowPctDamaged(95, damage)) + { + _phase = PHASE_ATTUMEN_ENGAGES; + Talk(EMOTE_CALL_ATTUMEN); + DoCastAOE(SPELL_SUMMON_ATTUMEN); + } + else if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage)) + { + _phase = PHASE_MOUNTED; + DoCastAOE(SPELL_MOUNT, true); + } + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN) + { + summon->AI()->AttackStart(me->GetVictim()); + summon->AI()->Talk(SAY_APPEAR); + } + BossAI::JustSummoned(summon); + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_SET_MIDNIGHT_PHASE) + { + _phase = PHASE_MOUNTED; + } + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + scheduler.Schedule(15s, 25s, [this](TaskContext task) + { + DoCastVictim(SPELL_KNOCKDOWN); + task.Repeat(15s, 25s); + }); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + me->DespawnOnEvade(10s); + _phase = PHASE_NONE; + } + + void KilledUnit(Unit* /*victim*/) override + { + if (_phase == PHASE_ATTUMEN_ENGAGES) + { + if (Creature* attumen = instance->GetCreature(DATA_ATTUMEN)) + { + Talk(SAY_MIDNIGHT_KILL, attumen); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (_phase != PHASE_MOUNTED) + { + if (!UpdateVictim()) + { + return; + } if (!CanMeleeHit()) { BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY); } - - scheduler.Update(diff, - std::bind(&BossAI::DoMeleeAttackIfReady, this)); } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Mechanic == MECHANIC_DISARM) - { - Talk(SAY_DISARMED); - } - - if (spellInfo->Id == SPELL_MOUNT) - { - if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) - { - _phase = PHASE_NONE; - scheduler.CancelAll(); - - midnight->AI()->DoAction(ACTION_SET_MIDNIGHT_PHASE); - midnight->AttackStop(); - midnight->RemoveAllAttackers(); - midnight->SetReactState(REACT_PASSIVE); - midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f); - midnight->AI()->Talk(EMOTE_MOUNT_UP); - - me->AttackStop(); - me->RemoveAllAttackers(); - me->SetReactState(REACT_PASSIVE); - me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f); - Talk(SAY_MOUNT); - - scheduler.Schedule(Seconds(1), [this](TaskContext task) - { - if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) - { - if (me->IsWithinDist2d(midnight, 5.0f)) - { - DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED); - me->DespawnOrUnsummon(1s, 0s); - midnight->SetVisible(false); - } - else - { - midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f); - me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f); - task.Repeat(); - } - } - }); - } - } - } - - private: - uint8 _phase; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); + scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this)); } + +private: + uint8 _phase; }; -class boss_midnight : public CreatureScript +class spell_midnight_fixate : public AuraScript { -public: - boss_midnight() : CreatureScript("boss_midnight") { } + PrepareAuraScript(spell_midnight_fixate) - struct boss_midnightAI : public BossAI + void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - boss_midnightAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { } - - void Reset() override + Unit* target = GetTarget(); + if (Unit* caster = GetCaster()) { - BossAI::Reset(); - me->SetVisible(true); - me->SetReactState(REACT_DEFENSIVE); + caster->TauntApply(target); } - - bool CanMeleeHit() - { - return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override - { - // Midnight never dies, let health fall to 1 and prevent further damage. - if (damage >= me->GetHealth()) - { - damage = me->GetHealth() - 1; - } - - if (_phase == PHASE_NONE && me->HealthBelowPctDamaged(95, damage)) - { - _phase = PHASE_ATTUMEN_ENGAGES; - Talk(EMOTE_CALL_ATTUMEN); - DoCastAOE(SPELL_SUMMON_ATTUMEN); - } - else if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage)) - { - _phase = PHASE_MOUNTED; - DoCastAOE(SPELL_MOUNT, true); - } - } - - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN) - { - summon->AI()->AttackStart(me->GetVictim()); - summon->AI()->Talk(SAY_APPEAR); - } - - BossAI::JustSummoned(summon); - } - - void DoAction(int32 actionId) override - { - if (actionId == ACTION_SET_MIDNIGHT_PHASE) - { - _phase = PHASE_MOUNTED; - } - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - - scheduler.Schedule(Seconds(15), Seconds(25), [this](TaskContext task) - { - DoCastVictim(SPELL_KNOCKDOWN); - task.Repeat(Seconds(15), Seconds(25)); - }); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - me->DespawnOnEvade(10s); - _phase = PHASE_NONE; - } - - void KilledUnit(Unit* /*victim*/) override - { - if (_phase == PHASE_ATTUMEN_ENGAGES) - { - if (Creature* attumen = instance->GetCreature(DATA_ATTUMEN)) - { - Talk(SAY_MIDNIGHT_KILL, attumen); - } - } - } - - void UpdateAI(uint32 diff) override - { - if (_phase != PHASE_MOUNTED) - { - if (!UpdateVictim()) - { - return; - } - - if (!CanMeleeHit()) - { - BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY); - } - } - - scheduler.Update(diff, - std::bind(&BossAI::DoMeleeAttackIfReady, this)); - } - - private: - uint8 _phase; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); } -}; -class spell_midnight_fixate : public SpellScriptLoader -{ -public: - spell_midnight_fixate() : SpellScriptLoader("spell_midnight_fixate") { } - - class spell_midnight_fixate_AuraScript : public AuraScript + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - PrepareAuraScript(spell_midnight_fixate_AuraScript); - - void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + Unit* target = GetTarget(); + if (Unit* caster = GetCaster()) { - Unit* target = GetTarget(); - if (Unit* caster = GetCaster()) - caster->TauntApply(target); + caster->TauntFadeOut(target); } + } - void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - if (Unit* caster = GetCaster()) - caster->TauntFadeOut(target); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_midnight_fixate_AuraScript(); + OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; void AddSC_boss_attumen() { - new boss_midnight(); - new boss_attumen(); - new spell_midnight_fixate(); + RegisterKarazhanCreatureAI(boss_midnight); + RegisterKarazhanCreatureAI(boss_attumen); + RegisterSpellScript(spell_midnight_fixate); } From 7ea62f1b7c32fe9b96deb8aa51d50bc6da4816ea Mon Sep 17 00:00:00 2001 From: David K Date: Tue, 18 Jul 2023 17:52:31 +0100 Subject: [PATCH 04/19] fix(DB/Commands): Fix typo in `wp show` command description. (#16591) * This adds a SQL `UPDATE` command which fixes a typo present in the `wp show` command help text. `s/$slected__waypoint/$selected_waypoint` --- Previously: `Syntax: .wp show $option Options: on $pathid (or selected creature with loaded path) - Show path off - Hide path info $selected_waypoint - Show info for selected waypoint.` `` * Fix SQL Codestyle in `command_typo_fix.sql` This change changes the format of the SQL query to be easier to read. Additionally uses a variable to improve the readability of the actual UPDATE query, due the length of the help text string. --- data/sql/updates/pending_db_world/command_typo_fix.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 data/sql/updates/pending_db_world/command_typo_fix.sql diff --git a/data/sql/updates/pending_db_world/command_typo_fix.sql b/data/sql/updates/pending_db_world/command_typo_fix.sql new file mode 100644 index 000000000..9dbc950c9 --- /dev/null +++ b/data/sql/updates/pending_db_world/command_typo_fix.sql @@ -0,0 +1,3 @@ + +SET @HELP_TEXT := 'Syntax: .wp show $option\nOptions:\non $pathid (or selected creature with loaded path) - Show path\noff - Hide path\ninfo $selected_waypoint - Show info for selected waypoint.'; +UPDATE `command` SET `help` = @HELP_TEXT WHERE `name` = 'wp show'; From 08ed1fb47a21b21a986e3602550150fdc9940439 Mon Sep 17 00:00:00 2001 From: avarishd <46330494+avarishd@users.noreply.github.com> Date: Tue, 18 Jul 2023 19:53:44 +0300 Subject: [PATCH 05/19] fix(Scripts/Pets): Darting Hatchling not running around. (#15251) * fix(Scripts/Pets): Darting Hatchling not running around. * cs * Update pet_generic.cpp * RemoveAurasDueToSpell --- .../rev_1677852115511081000.sql | 3 ++ .../game/Spells/SpellInfoCorrections.cpp | 6 +++ src/server/scripts/Pet/pet_generic.cpp | 44 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1677852115511081000.sql diff --git a/data/sql/updates/pending_db_world/rev_1677852115511081000.sql b/data/sql/updates/pending_db_world/rev_1677852115511081000.sql new file mode 100644 index 000000000..58d53fdf9 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1677852115511081000.sql @@ -0,0 +1,3 @@ +-- Darting Hatchling (pet) +UPDATE `creature_template_addon` SET `auras` = 62586 WHERE `entry` = 35396; +UPDATE `creature_template` SET `ScriptName` = 'npc_pet_darting_hatchling' WHERE `entry` = 35396; diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index bff534f0a..f94e31d44 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -4547,6 +4547,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->MaxAffectedTargets = 1; }); + // Mulgore Hatchling (periodic) + ApplySpellFix({ 62586 }, [](SpellInfo* spellInfo) + { + spellInfo->Effects[EFFECT_0].TriggerSpell = 62585; // Mulgore Hatchling (fear) + }); + for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo* spellInfo = mSpellInfoMap[i]; diff --git a/src/server/scripts/Pet/pet_generic.cpp b/src/server/scripts/Pet/pet_generic.cpp index 34621293f..7ecae8d6b 100644 --- a/src/server/scripts/Pet/pet_generic.cpp +++ b/src/server/scripts/Pet/pet_generic.cpp @@ -774,6 +774,49 @@ struct npc_pet_gen_moth : public NullCreatureAI } }; +// Darting Hatchling +enum Darting +{ + SPELL_DARTING_ON_SPAWN = 62586, // Applied on spawn via creature_template_addon + SPELL_DARTING_FEAR = 62585, // Applied every 20s from SPELL_DARTING_ON_SPAWN +}; + +struct npc_pet_darting_hatchling : public NullCreatureAI +{ + npc_pet_darting_hatchling(Creature* c) : NullCreatureAI(c) + { + goFast = false; + checkTimer = 0; + } + + bool goFast; + uint32 checkTimer; + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_DARTING_FEAR) + { + goFast = true; + } + } + + void UpdateAI(uint32 diff) override + { + if (!goFast) + { + return; + } + + checkTimer += diff; + if (checkTimer >= 2000) + { + me->RemoveAurasDueToSpell(SPELL_DARTING_FEAR); + checkTimer = 0; + goFast = false; + } + } +}; + void AddSC_generic_pet_scripts() { RegisterCreatureAI(npc_pet_gen_soul_trader_beacon); @@ -788,4 +831,5 @@ void AddSC_generic_pet_scripts() RegisterCreatureAI(npc_pet_gen_toxic_wasteling); RegisterCreatureAI(npc_pet_gen_fetch_ball); RegisterCreatureAI(npc_pet_gen_moth); + RegisterCreatureAI(npc_pet_darting_hatchling); } From 18aecfd8bd85e5da1e003a35083e1890098390ab Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Tue, 18 Jul 2023 16:56:17 +0000 Subject: [PATCH 06/19] chore(DB): import pending files Referenced commit(s): 08ed1fb47a21b21a986e3602550150fdc9940439 --- .../command_typo_fix.sql => db_world/2023_07_18_01.sql} | 1 + .../rev_1677852115511081000.sql => db_world/2023_07_18_02.sql} | 1 + 2 files changed, 2 insertions(+) rename data/sql/updates/{pending_db_world/command_typo_fix.sql => db_world/2023_07_18_01.sql} (85%) rename data/sql/updates/{pending_db_world/rev_1677852115511081000.sql => db_world/2023_07_18_02.sql} (81%) diff --git a/data/sql/updates/pending_db_world/command_typo_fix.sql b/data/sql/updates/db_world/2023_07_18_01.sql similarity index 85% rename from data/sql/updates/pending_db_world/command_typo_fix.sql rename to data/sql/updates/db_world/2023_07_18_01.sql index 9dbc950c9..832c72e7d 100644 --- a/data/sql/updates/pending_db_world/command_typo_fix.sql +++ b/data/sql/updates/db_world/2023_07_18_01.sql @@ -1,3 +1,4 @@ +-- DB update 2023_07_18_00 -> 2023_07_18_01 SET @HELP_TEXT := 'Syntax: .wp show $option\nOptions:\non $pathid (or selected creature with loaded path) - Show path\noff - Hide path\ninfo $selected_waypoint - Show info for selected waypoint.'; UPDATE `command` SET `help` = @HELP_TEXT WHERE `name` = 'wp show'; diff --git a/data/sql/updates/pending_db_world/rev_1677852115511081000.sql b/data/sql/updates/db_world/2023_07_18_02.sql similarity index 81% rename from data/sql/updates/pending_db_world/rev_1677852115511081000.sql rename to data/sql/updates/db_world/2023_07_18_02.sql index 58d53fdf9..dc03217fc 100644 --- a/data/sql/updates/pending_db_world/rev_1677852115511081000.sql +++ b/data/sql/updates/db_world/2023_07_18_02.sql @@ -1,3 +1,4 @@ +-- DB update 2023_07_18_01 -> 2023_07_18_02 -- Darting Hatchling (pet) UPDATE `creature_template_addon` SET `auras` = 62586 WHERE `entry` = 35396; UPDATE `creature_template` SET `ScriptName` = 'npc_pet_darting_hatchling' WHERE `entry` = 35396; From cc6454b2efbbdd9db2159ade285d8c756e8c33f8 Mon Sep 17 00:00:00 2001 From: Dan <83884799+elthehablo@users.noreply.github.com> Date: Tue, 18 Jul 2023 21:50:16 +0200 Subject: [PATCH 07/19] chore(Scripts/Karazhan): change Moroes to use TaskScheduler instead of events (#16791) * initial * fix * add garrote line * change line * add immunity during stealth * bump + spacing --- .../EasternKingdoms/Karazhan/boss_moroes.cpp | 145 +++++++++--------- 1 file changed, 69 insertions(+), 76 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp index 708d27836..c78c7fa7c 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp @@ -46,19 +46,15 @@ enum Spells enum Misc { - EVENT_GUEST_TALK = 1, - EVENT_GUEST_TALK2 = 2, - EVENT_SPELL_VANISH = 3, - EVENT_SPELL_GARROTE = 4, - EVENT_SPELL_BLIND = 5, - EVENT_SPELL_GOUGE = 6, - EVENT_SPELL_ENRAGE = 7, - EVENT_KILL_TALK = 8, - ACTIVE_GUEST_COUNT = 4, MAX_GUEST_COUNT = 6 }; +enum Groups +{ + GROUP_PRECOMBAT_TALK = 0 +}; + const Position GuestsPosition[4] = { {-10987.38f, -1883.38f, 81.73f, 1.50f}, @@ -78,6 +74,10 @@ struct boss_moroes : public BossAI boss_moroes(Creature* creature) : BossAI(creature, DATA_MOROES) { _activeGuests = 0; + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } void InitializeAI() override @@ -111,46 +111,83 @@ struct boss_moroes : public BossAI me->SummonCreature(GuestEntries[i], GuestsPosition[summons.size()], TEMPSUMMON_MANUAL_DESPAWN); } } - _events2.Reset(); - _events2.ScheduleEvent(EVENT_GUEST_TALK, 10s); + + scheduler.Schedule(10s, GROUP_PRECOMBAT_TALK, [this](TaskContext context) + { + if(Creature* guest = GetRandomGuest()) + { + guest->AI()->Talk(SAY_GUEST); + } + context.Repeat(5s); + }).Schedule(1min, 2min, GROUP_PRECOMBAT_TALK, [this](TaskContext context) + { + //this was not scheduled in the previous commit + //does this have to be removed? + Talk(SAY_OUT_OF_COMBAT); + context.Repeat(1min, 2min); + }); } void Reset() override { BossAI::Reset(); DoCastSelf(SPELL_DUAL_WIELD, true); + _recentlySpoken = false; + _vanished = false; + + ScheduleHealthCheckEvent(30, [&] { + DoCastSelf(SPELL_FRENZY, true); + }); } void JustEngagedWith(Unit* who) override { BossAI::JustEngagedWith(who); Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_SPELL_VANISH, 30s); - events.ScheduleEvent(EVENT_SPELL_BLIND, 20s); - events.ScheduleEvent(EVENT_SPELL_GOUGE, 13s); - events.ScheduleEvent(EVENT_SPELL_ENRAGE, 10min); - _events2.Reset(); me->CallForHelp(20.0f); DoZoneInCombat(); - } + scheduler.CancelGroup(GROUP_PRECOMBAT_TALK); - void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override - { - if (HealthBelowPct(30)) + scheduler.Schedule(30s, [this](TaskContext context) { - DoCastSelf(SPELL_FRENZY, true); - } + scheduler.DelayAll(9s); + _vanished = true; + Talk(SAY_SPECIAL); + DoCastSelf(SPELL_VANISH); + me->SetImmuneToAll(true); + scheduler.Schedule(5s, 7s, [this](TaskContext) + { + me->SetImmuneToAll(false); + DoCastRandomTarget(SPELL_GARROTE, 0, 100.0f, true, true); + DoCastSelf(SPELL_VANISH_TELEPORT); + _vanished = false; + }); + + context.Repeat(30s); + }).Schedule(20s, [this](TaskContext context) + { + DoCastMaxThreat(SPELL_BLIND, 1, 10.0f, true); + context.Repeat(25s, 40s); + }).Schedule(13s, [this](TaskContext context) + { + DoCastVictim(SPELL_GOUGE); + context.Repeat(25s, 40s); + }).Schedule(10min, [this](TaskContext) + { + DoCastSelf(SPELL_BERSERK, true); + }); } void KilledUnit(Unit* victim) override { - if (events.GetNextEventTime(EVENT_KILL_TALK) == 0) + if(!_recentlySpoken && victim->GetTypeId() == TYPEID_PLAYER) { - if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_KILL); + _recentlySpoken = true; + scheduler.Schedule(5s, [this](TaskContext) { - Talk(SAY_KILL); - events.ScheduleEvent(EVENT_KILL_TALK, 5s); - } + _recentlySpoken = false; + }); } } @@ -176,66 +213,22 @@ struct boss_moroes : public BossAI void UpdateAI(uint32 diff) override { - _events2.Update(diff); - switch (_events2.ExecuteEvent()) - { - case EVENT_GUEST_TALK: - if (Creature* guest = GetRandomGuest()) - { - guest->AI()->Talk(SAY_GUEST); - } - _events2.Repeat(5s); - break; - case EVENT_GUEST_TALK2: - Talk(SAY_OUT_OF_COMBAT); - _events2.Repeat(1min, 2min); - break; - } + scheduler.Update(diff); if (!UpdateVictim()) return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) + if (_vanished == false) { - case EVENT_SPELL_ENRAGE: - DoCastSelf(SPELL_BERSERK, true); - break; - case EVENT_SPELL_BLIND: - if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 10.0f, true)) - { - DoCast(target, SPELL_BLIND); - } - events.Repeat(25s, 40s); - break; - case EVENT_SPELL_GOUGE: - DoCastVictim(SPELL_GOUGE); - events.Repeat(25s, 40s); - return; - case EVENT_SPELL_VANISH: - events.DelayEvents(9s); - events.SetPhase(1); - DoCastSelf(SPELL_VANISH); - events.Repeat(30s); - events.ScheduleEvent(EVENT_SPELL_GARROTE, 5s, 7s); - return; - case EVENT_SPELL_GARROTE: - Talk(SAY_SPECIAL); - DoCastRandomTarget(SPELL_GARROTE, 0, 100.0f, true, true); - DoCastSelf(SPELL_VANISH_TELEPORT); - events.SetPhase(0); - break; - } - if (events.GetPhaseMask() == 0) // Xinef: not in vanish DoMeleeAttackIfReady(); + } } private: EventMap _events2; uint8 _activeGuests; + bool _recentlySpoken; + bool _vanished; }; class spell_moroes_vanish : public SpellScript From d71f5dcfb2c463e00d09a935911ece71f15f14d7 Mon Sep 17 00:00:00 2001 From: Eddy Vega <61223313+Si1ker@users.noreply.github.com> Date: Tue, 18 Jul 2023 13:51:16 -0600 Subject: [PATCH 08/19] refactor(Scripts/Karazhan): Update Servant Quarters (#16680) init --- .../Karazhan/boss_servant_quarters.cpp | 132 ++++++++---------- 1 file changed, 55 insertions(+), 77 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp index 82c548fa9..0c23ed406 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp @@ -19,7 +19,7 @@ #include "ScriptedCreature.h" #include "karazhan.h" -enum ServantQuartersSpells +enum Spells { SPELL_SNEAK = 22766, SPELL_ACIDIC_FANG = 29901, @@ -33,41 +33,37 @@ enum ServantQuartersSpells SPELL_RAVAGE = 29906 }; -enum ServantQuertersMisc -{ - EVENT_SPELL_ACIDIC_FANG = 1, - EVENT_SPELL_HYAKISS_WEB = 2, - - EVENT_SPELL_DIVE = 10, - EVENT_SPELL_SONIC_BURST = 11, - EVENT_SPELL_WING_BUFFET = 12, - EVENT_SPELL_FEAR = 13, - - EVENT_SPELL_RAVAGE = 20, - - EVENT_CHECK_VISIBILITY = 30 -}; - struct boss_servant_quarters : public BossAI { boss_servant_quarters(Creature* creature) : BossAI(creature, DATA_SERVANT_QUARTERS) { } void Reset() override { - events.Reset(); + _scheduler.CancelAll(); me->SetVisible(false); me->SetReactState(REACT_PASSIVE); me->SetFaction(FACTION_FRIENDLY); - _events2.Reset(); - _events2.ScheduleEvent(EVENT_CHECK_VISIBILITY, 5s); - + _scheduler.Schedule(5s, [this](TaskContext context) + { + if (instance->GetBossState(DATA_SERVANT_QUARTERS) == DONE) + { + me->SetVisible(true); + me->SetReactState(REACT_AGGRESSIVE); + me->RestoreFaction(); + } + else + { + context.Repeat(5s); + } + }); if (me->GetEntry() == NPC_HYAKISS_THE_LURKER) { DoCastSelf(SPELL_SNEAK, true); } - if (instance->GetData(DATA_SELECTED_RARE) != me->GetEntry()) + { me->DespawnOrUnsummon(1); + } } void JustEngagedWith(Unit* /*who*/) override @@ -75,18 +71,42 @@ struct boss_servant_quarters : public BossAI me->setActive(true); if (me->GetEntry() == NPC_HYAKISS_THE_LURKER) { - events.ScheduleEvent(EVENT_SPELL_ACIDIC_FANG, 5s); - events.ScheduleEvent(EVENT_SPELL_HYAKISS_WEB, 9s); + _scheduler.Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_ACIDIC_FANG); + context.Repeat(12s, 18s); + }).Schedule(9s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_HYAKISS_WEB, 0, 30.0f); + context.Repeat(15s); + }); } else if (me->GetEntry() == NPC_SHADIKITH_THE_GLIDER) { - events.ScheduleEvent(EVENT_SPELL_SONIC_BURST, 4s); - events.ScheduleEvent(EVENT_SPELL_WING_BUFFET, 7s); - events.ScheduleEvent(EVENT_SPELL_DIVE, 10s); + _scheduler.Schedule(4s, [this](TaskContext context) + { + DoCastSelf(SPELL_SONIC_BURST); + context.Repeat(12s, 18s); + }).Schedule(7s, [this](TaskContext context) + { + DoCastSelf(SPELL_WING_BUFFET); + context.Repeat(12s, 18s); + }).Schedule(10s, [this](TaskContext context) + { + if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true))) + { + me->CastSpell(target, SPELL_DIVE); + } + context.Repeat(20s); + }); } else // if (me->GetEntry() == NPC_ROKAD_THE_RAVAGER) { - events.ScheduleEvent(EVENT_SPELL_RAVAGE, 3s); + _scheduler.Schedule(3s, [this](TaskContext context) + { + DoCastVictim(SPELL_RAVAGE); + context.Repeat(10500ms); + }); } } @@ -97,70 +117,28 @@ struct boss_servant_quarters : public BossAI void MovementInform(uint32 type, uint32 point) override { if (type == POINT_MOTION_TYPE && point == EVENT_CHARGE) - events.ScheduleEvent(EVENT_SPELL_FEAR, 0); + { + _scheduler.Schedule(1ms, [this](TaskContext /*context*/) + { + DoCastVictim(SPELL_FEAR); + }); + } } void UpdateAI(uint32 diff) override { - _events2.Update(diff); - switch (_events2.ExecuteEvent()) - { - case EVENT_CHECK_VISIBILITY: - if (instance->GetBossState(DATA_SERVANT_QUARTERS) == DONE) - { - me->SetVisible(true); - me->SetReactState(REACT_AGGRESSIVE); - me->RestoreFaction(); - } - else - _events2.ScheduleEvent(EVENT_CHECK_VISIBILITY, 5s); - break; - } - if (!UpdateVictim()) return; - events.Update(diff); + _scheduler.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - switch (events.ExecuteEvent()) - { - case EVENT_SPELL_ACIDIC_FANG: - me->CastSpell(me->GetVictim(), SPELL_ACIDIC_FANG, false); - events.Repeat(12s, 18s); - break; - case EVENT_SPELL_HYAKISS_WEB: - DoCastRandomTarget(SPELL_HYAKISS_WEB, 0, 30.0f); - events.Repeat(15s); - break; - case EVENT_SPELL_SONIC_BURST: - DoCastSelf(SPELL_SONIC_BURST); - events.Repeat(12s, 18s); - break; - case EVENT_SPELL_WING_BUFFET: - DoCastSelf(SPELL_WING_BUFFET); - events.Repeat(12s, 18s); - break; - case EVENT_SPELL_DIVE: - if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true))) - me->CastSpell(target, SPELL_DIVE, false); - events.Repeat(20s); - break; - case EVENT_SPELL_FEAR: - DoCastVictim(SPELL_FEAR); - break; - case EVENT_SPELL_RAVAGE: - me->CastSpell(me->GetVictim(), SPELL_RAVAGE, false); - events.ScheduleEvent(EVENT_SPELL_RAVAGE, 10500); - break; - } - DoMeleeAttackIfReady(); } private: - EventMap _events2; + TaskScheduler _scheduler; }; void AddSC_boss_servant_quarters() From c6c2abf20ba185e72311542b2b47d50832342372 Mon Sep 17 00:00:00 2001 From: Samsequel <20357406+Samsequel@users.noreply.github.com> Date: Wed, 19 Jul 2023 07:52:58 +0200 Subject: [PATCH 09/19] fix(DB/Spell) Fix trinkets procs TBC and Vanilla (#16783) --- data/sql/updates/pending_db_world/trinkets.sql | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 data/sql/updates/pending_db_world/trinkets.sql diff --git a/data/sql/updates/pending_db_world/trinkets.sql b/data/sql/updates/pending_db_world/trinkets.sql new file mode 100644 index 000000000..c940e10de --- /dev/null +++ b/data/sql/updates/pending_db_world/trinkets.sql @@ -0,0 +1,8 @@ +-- +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 37655; +UPDATE `spell_proc_event` SET `Cooldown` = 40000 WHERE `entry` = 37247; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 60066; +UPDATE `spell_proc_event` SET `Cooldown` = 2000 WHERE `entry` = 15600; + +UPDATE `spell_proc_event` SET `procEx` = 262144 WHERE `entry` = 37655; +UPDATE `item_template` SET `spellcooldown_2` = -1 WHERE (`entry` = 28823); From 710f3fe7b12c29be2acec5ec5dd549d793c68b8d Mon Sep 17 00:00:00 2001 From: Samsequel <20357406+Samsequel@users.noreply.github.com> Date: Wed, 19 Jul 2023 07:53:27 +0200 Subject: [PATCH 10/19] fix(DB/Spell): Bangle of Endless Blessing ICD adjustment (#16780) --- data/sql/updates/pending_db_world/bangle.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/sql/updates/pending_db_world/bangle.sql diff --git a/data/sql/updates/pending_db_world/bangle.sql b/data/sql/updates/pending_db_world/bangle.sql new file mode 100644 index 000000000..224a699b7 --- /dev/null +++ b/data/sql/updates/pending_db_world/bangle.sql @@ -0,0 +1,2 @@ +-- +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 38334; From 9ccdb1dcdf737ebdf6af601e0b08498ea61d86ea Mon Sep 17 00:00:00 2001 From: Samsequel <20357406+Samsequel@users.noreply.github.com> Date: Wed, 19 Jul 2023 07:53:47 +0200 Subject: [PATCH 11/19] fix(DB/Spell): Badge of the Swarmguard PPM fix (#16777) --- data/sql/updates/pending_db_world/badgeoftheswarmguard.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 data/sql/updates/pending_db_world/badgeoftheswarmguard.sql diff --git a/data/sql/updates/pending_db_world/badgeoftheswarmguard.sql b/data/sql/updates/pending_db_world/badgeoftheswarmguard.sql new file mode 100644 index 000000000..c854ed539 --- /dev/null +++ b/data/sql/updates/pending_db_world/badgeoftheswarmguard.sql @@ -0,0 +1,3 @@ +-- +UPDATE `spell_proc_event` SET `ppmRate` = 10 WHERE `entry` = 26480; +UPDATE `spell_proc_event` SET `procFlags` = 68 WHERE `entry` = 26480; From 1a967dc3da4a30b80cce201206bf2c582dd80ed3 Mon Sep 17 00:00:00 2001 From: Samsequel <20357406+Samsequel@users.noreply.github.com> Date: Wed, 19 Jul 2023 07:54:07 +0200 Subject: [PATCH 12/19] fix(DB/Spell): Talisman of Ascendance should only proc on spell casts (#16776) --- data/sql/updates/pending_db_world/talismanofascendance.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 data/sql/updates/pending_db_world/talismanofascendance.sql diff --git a/data/sql/updates/pending_db_world/talismanofascendance.sql b/data/sql/updates/pending_db_world/talismanofascendance.sql new file mode 100644 index 000000000..cd934c637 --- /dev/null +++ b/data/sql/updates/pending_db_world/talismanofascendance.sql @@ -0,0 +1 @@ +UPDATE `spell_proc_event` SET `procEx` = 262144 WHERE `entry` = 28200; From 75fc7a437f59babe641a8161b69e4efb8208acb5 Mon Sep 17 00:00:00 2001 From: Samsequel <20357406+Samsequel@users.noreply.github.com> Date: Wed, 19 Jul 2023 07:54:35 +0200 Subject: [PATCH 13/19] fix(DB/Spell): Darkmoon Card: Blue Dragon should only trigger on spellcast (#16779) --- data/sql/updates/pending_db_world/darkmoonbluedragon.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/sql/updates/pending_db_world/darkmoonbluedragon.sql diff --git a/data/sql/updates/pending_db_world/darkmoonbluedragon.sql b/data/sql/updates/pending_db_world/darkmoonbluedragon.sql new file mode 100644 index 000000000..21f2f9a66 --- /dev/null +++ b/data/sql/updates/pending_db_world/darkmoonbluedragon.sql @@ -0,0 +1,2 @@ +-- +UPDATE `spell_proc_event` SET `procPhase` = 1 WHERE `entry` = 23688; From 30197f40d687eae97a07d6730b6933c63f1a3983 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Wed, 19 Jul 2023 05:57:13 +0000 Subject: [PATCH 14/19] chore(DB): import pending files Referenced commit(s): 75fc7a437f59babe641a8161b69e4efb8208acb5 --- .../badgeoftheswarmguard.sql => db_world/2023_07_19_00.sql} | 1 + .../{pending_db_world/bangle.sql => db_world/2023_07_19_01.sql} | 1 + .../darkmoonbluedragon.sql => db_world/2023_07_19_02.sql} | 1 + .../talismanofascendance.sql => db_world/2023_07_19_03.sql} | 1 + .../trinkets.sql => db_world/2023_07_19_04.sql} | 1 + 5 files changed, 5 insertions(+) rename data/sql/updates/{pending_db_world/badgeoftheswarmguard.sql => db_world/2023_07_19_00.sql} (76%) rename data/sql/updates/{pending_db_world/bangle.sql => db_world/2023_07_19_01.sql} (63%) rename data/sql/updates/{pending_db_world/darkmoonbluedragon.sql => db_world/2023_07_19_02.sql} (62%) rename data/sql/updates/{pending_db_world/talismanofascendance.sql => db_world/2023_07_19_03.sql} (61%) rename data/sql/updates/{pending_db_world/trinkets.sql => db_world/2023_07_19_04.sql} (90%) diff --git a/data/sql/updates/pending_db_world/badgeoftheswarmguard.sql b/data/sql/updates/db_world/2023_07_19_00.sql similarity index 76% rename from data/sql/updates/pending_db_world/badgeoftheswarmguard.sql rename to data/sql/updates/db_world/2023_07_19_00.sql index c854ed539..4b589b943 100644 --- a/data/sql/updates/pending_db_world/badgeoftheswarmguard.sql +++ b/data/sql/updates/db_world/2023_07_19_00.sql @@ -1,3 +1,4 @@ +-- DB update 2023_07_18_02 -> 2023_07_19_00 -- UPDATE `spell_proc_event` SET `ppmRate` = 10 WHERE `entry` = 26480; UPDATE `spell_proc_event` SET `procFlags` = 68 WHERE `entry` = 26480; diff --git a/data/sql/updates/pending_db_world/bangle.sql b/data/sql/updates/db_world/2023_07_19_01.sql similarity index 63% rename from data/sql/updates/pending_db_world/bangle.sql rename to data/sql/updates/db_world/2023_07_19_01.sql index 224a699b7..7a37f29bb 100644 --- a/data/sql/updates/pending_db_world/bangle.sql +++ b/data/sql/updates/db_world/2023_07_19_01.sql @@ -1,2 +1,3 @@ +-- DB update 2023_07_19_00 -> 2023_07_19_01 -- UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 38334; diff --git a/data/sql/updates/pending_db_world/darkmoonbluedragon.sql b/data/sql/updates/db_world/2023_07_19_02.sql similarity index 62% rename from data/sql/updates/pending_db_world/darkmoonbluedragon.sql rename to data/sql/updates/db_world/2023_07_19_02.sql index 21f2f9a66..9d72b4266 100644 --- a/data/sql/updates/pending_db_world/darkmoonbluedragon.sql +++ b/data/sql/updates/db_world/2023_07_19_02.sql @@ -1,2 +1,3 @@ +-- DB update 2023_07_19_01 -> 2023_07_19_02 -- UPDATE `spell_proc_event` SET `procPhase` = 1 WHERE `entry` = 23688; diff --git a/data/sql/updates/pending_db_world/talismanofascendance.sql b/data/sql/updates/db_world/2023_07_19_03.sql similarity index 61% rename from data/sql/updates/pending_db_world/talismanofascendance.sql rename to data/sql/updates/db_world/2023_07_19_03.sql index cd934c637..d04cdf7de 100644 --- a/data/sql/updates/pending_db_world/talismanofascendance.sql +++ b/data/sql/updates/db_world/2023_07_19_03.sql @@ -1 +1,2 @@ +-- DB update 2023_07_19_02 -> 2023_07_19_03 UPDATE `spell_proc_event` SET `procEx` = 262144 WHERE `entry` = 28200; diff --git a/data/sql/updates/pending_db_world/trinkets.sql b/data/sql/updates/db_world/2023_07_19_04.sql similarity index 90% rename from data/sql/updates/pending_db_world/trinkets.sql rename to data/sql/updates/db_world/2023_07_19_04.sql index c940e10de..d61f8750f 100644 --- a/data/sql/updates/pending_db_world/trinkets.sql +++ b/data/sql/updates/db_world/2023_07_19_04.sql @@ -1,3 +1,4 @@ +-- DB update 2023_07_19_03 -> 2023_07_19_04 -- UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 37655; UPDATE `spell_proc_event` SET `Cooldown` = 40000 WHERE `entry` = 37247; From 9482836e3392b3e0063880333bab8301445f8721 Mon Sep 17 00:00:00 2001 From: Tereneckla <50233983+Tereneckla@users.noreply.github.com> Date: Fri, 21 Jul 2023 22:16:11 +0000 Subject: [PATCH 15/19] fix(Core/Session): don't refund soul shards when logging out with warlock pets (#16803) --- src/server/game/Server/WorldSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 71683e858..d45144cb4 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -643,7 +643,7 @@ void WorldSession::LogoutPlayer(bool save) guild->HandleMemberLogout(this); ///- Remove pet - _player->RemovePet(nullptr, PET_SAVE_AS_CURRENT, true); + _player->RemovePet(nullptr, PET_SAVE_AS_CURRENT); // pussywizard: on logout remove auras that are removed at map change (before saving to db) // there are some positive auras from boss encounters that can be kept by logging out and logging in after boss is dead, and may be used on next bosses From 076534852bbac37fce40e6e5cf46f021abbf034e Mon Sep 17 00:00:00 2001 From: v-mstrs <104088833+v-mstrs@users.noreply.github.com> Date: Sat, 22 Jul 2023 14:25:24 +0200 Subject: [PATCH 16/19] fix(DB/Quest): Port quests regarding Corki from Trinity (#16080) * fix Corki's issues, Trinity help * Remove * Update data/sql/updates/pending_db_world/rev_1682394052134857558.sql Co-authored-by: Gultask <100873791+Gultask@users.noreply.github.com> * Update data/sql/updates/pending_db_world/rev_1682394052134857558.sql Co-authored-by: Gultask <100873791+Gultask@users.noreply.github.com> * Update rev_1682394052134857558.sql * Update rev_1682394052134857558.sql * spelling mistakes * Update Co-authored-by: Killyana --------- Co-authored-by: v-mstrs Co-authored-by: Gultask <100873791+Gultask@users.noreply.github.com> Co-authored-by: Killyana --- .../rev_1682394052134857558.sql | 43 ++++++ src/server/scripts/Outland/zone_nagrand.cpp | 123 ------------------ 2 files changed, 43 insertions(+), 123 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1682394052134857558.sql diff --git a/data/sql/updates/pending_db_world/rev_1682394052134857558.sql b/data/sql/updates/pending_db_world/rev_1682394052134857558.sql new file mode 100644 index 000000000..7b1b524b1 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1682394052134857558.sql @@ -0,0 +1,43 @@ +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName`='' WHERE `entry` IN (18445,18369,20812); +UPDATE `gameobject_template` SET `Data2`=300000, `AIName`='SmartGameObjectAI', `ScriptName`='' WHERE `entry` IN (182521,182349,182350); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (182521,182349,182350) AND `source_type`=1; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (18445,18369,20812) AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (1844500,1836900,2081200) AND `source_type`=9; +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 +(182521, 1, 0 ,1,70, 0, 100, 0, 2, 0, 0,0,64,1,0,0,0,0,0,16,0,0,0,0, 0, 0, 0, 'Corkis Prison - On State Changed - Store Targetlist'), +(182521, 1, 1 ,2,61, 0, 100, 0, 0, 0, 0,0,100,1,0,0,0,0,0,19,18445,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Send Targetlist'), +(182521, 1, 2 ,0,61, 0, 100, 0, 0, 0, 0,0,45,1,1,0,0,0,0,19,18445,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Set Data'), +(18445, 0, 0 ,0,38, 0, 100, 0, 1, 1, 0,0,80,1844500,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - On Data Set - Action list'), +(1844500, 9, 0 ,0,0, 0, 100, 0, 0, 0, 0,0,1,0,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Say'), +(1844500, 9, 1 ,0,0, 0, 100, 0, 0, 0, 0,0,33,18444,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Kill Credit'), +(1844500, 9, 2 ,0,0, 0, 100, 0, 4000, 4000, 0,0,69,0,0,0,0,0,0,8,0,0,0,-896.082, 8687.346, 170.455, 3.81311, 'Corki - Action listt - Move Forward'), +(1844500, 9, 3 ,0,0, 0, 100, 0, 4000, 4000, 0,0,41,0,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - Action list - Despawn after 5 seconds'), +(182349, 1, 0 ,1,70, 0, 100, 0, 2, 0, 0,0,64,1,0,0,0,0,0,16,0,0,0,0, 0, 0, 0, 'Corkis Prison - On State Changed - Store Targetlist'), +(182349, 1, 1 ,2,61, 0, 100, 0, 0, 0, 0,0,100,1,0,0,0,0,0,19,18369,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Send Targetlist'), +(182349, 1, 2 ,0,61, 0, 100, 0, 0, 0, 0,0,45,1,1,0,0,0,0,19,18369,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Set Data'), +(18369, 0, 0 ,0,38, 0, 100, 0, 1, 1, 0,0,80,1836900,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - On Data Set - Action list'), +(1836900, 9, 0 , 0, 0, 0, 100, 0, 0, 0, 0,0,1,0,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Say'), +(1836900, 9, 1 , 0, 0, 0, 100, 0, 0, 0, 0,0,33,18369,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Kill Credit'), +(1836900, 9, 2 ,0,0, 0, 100, 0, 4000, 4000, 0,0,69,0,0,0,0,0,0,8,0,0,0,-2547.684, 6271.637, 14.767, 5.349, 'Corki - Action list - Move Forward'), +(1836900, 9, 3 , 0, 0, 0, 100, 0, 4000, 4000, 0,0,41,0,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - Action list - Despawn after 5 seconds'), +(182350, 1, 0 ,1,70, 0, 100, 0, 2, 0, 0,0,64,1,0,0,0,0,0,16,0,0,0,0, 0, 0, 0, 'Corkis Prison - On State Changed - Store Targetlist'), +(182350, 1, 1 ,2,61, 0, 100, 0, 0, 0, 0,0,100,1,0,0,0,0,0,19,20812,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Send Targetlist'), +(182350, 1, 2 ,0,61, 0, 100, 0, 0, 0, 0,0,45,1,1,0,0,0,0,19,20812,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Set Data'), +(20812, 0, 0 ,0,38, 0, 100, 0, 1, 1, 0,0,80,2081200,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - On Data Set - Action list'), +(2081200, 9, 0 , 0, 0, 0, 100, 0, 0, 0, 0,0,1,0,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Say'), +(2081200, 9, 1 , 0, 0, 0, 100, 0, 0, 0, 0,0,33,20812,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Kill Credit'), +(2081200, 9, 2 , 0, 0, 0, 100, 0, 4000, 4000, 0,0,69,0,0,0,0,0,0,8,0,0,0,-1001.022, 8113.366, -95.849, 0.352908, 'Corki - Action list - Move Forward'), +(2081200, 9, 3 , 0, 0, 0, 100, 0, 4000, 4000, 0,0,41,0,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - Action list - Despawn after 5 seconds'); + +UPDATE `creature` SET `position_x`=-2563.89,`position_y`=6288.29,`position_z`=15.295,`orientation`=5.23599 WHERE `guid`=65786 AND `id1`=18369; +UPDATE `creature` SET `position_x`=-918.143,`position_y`=8663.94,`position_z`=172.542,`orientation`=0.523599 WHERE `guid`=65849 AND `id1`=18445; + +DELETE FROM `creature_questender` WHERE `id` IN (18369,18445); +INSERT INTO `creature_questender` (`id`, `quest`) VALUES +(18445, 9954); + +DELETE FROM `creature_queststarter` WHERE `id` IN (18369,18445); +INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES +(18369, 9923), +(18445, 9955); + diff --git a/src/server/scripts/Outland/zone_nagrand.cpp b/src/server/scripts/Outland/zone_nagrand.cpp index 39d7d95bd..5b8590169 100644 --- a/src/server/scripts/Outland/zone_nagrand.cpp +++ b/src/server/scripts/Outland/zone_nagrand.cpp @@ -259,127 +259,6 @@ public: }; }; -/*###### -## go_corkis_prison and npc_corki -######*/ - -enum CorkiData -{ - // first quest - QUEST_HELP = 9923, - NPC_CORKI = 18445, - NPC_CORKI_CREDIT_1 = 18369, - GO_CORKIS_PRISON = 182349, - CORKI_SAY_THANKS = 0, - // 2nd quest - QUEST_CORKIS_GONE_MISSING_AGAIN = 9924, - NPC_CORKI_2 = 20812, - GO_CORKIS_PRISON_2 = 182350, - CORKI_SAY_PROMISE = 0, - // 3rd quest - QUEST_CHOWAR_THE_PILLAGER = 9955, - NPC_CORKI_3 = 18369, - NPC_CORKI_CREDIT_3 = 18444, - GO_CORKIS_PRISON_3 = 182521, - CORKI_SAY_LAST = 0 -}; - -class go_corkis_prison : public GameObjectScript -{ -public: - go_corkis_prison() : GameObjectScript("go_corkis_prison") { } - - bool OnGossipHello(Player* player, GameObject* go) override - { - go->SetGoState(GO_STATE_READY); - if (go->GetEntry() == GO_CORKIS_PRISON) - { - if (Creature* corki = go->FindNearestCreature(NPC_CORKI, 25, true)) - { - corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() + 5, go->GetPositionY(), go->GetPositionZ()); - if (player) - player->KilledMonsterCredit(NPC_CORKI_CREDIT_1); - } - } - - if (go->GetEntry() == GO_CORKIS_PRISON_2) - { - if (Creature* corki = go->FindNearestCreature(NPC_CORKI_2, 25, true)) - { - corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() - 5, go->GetPositionY(), go->GetPositionZ()); - if (player) - player->KilledMonsterCredit(NPC_CORKI_2); - } - } - - if (go->GetEntry() == GO_CORKIS_PRISON_3) - { - if (Creature* corki = go->FindNearestCreature(NPC_CORKI_3, 25, true)) - { - corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() + 4, go->GetPositionY(), go->GetPositionZ()); - if (player) - player->KilledMonsterCredit(NPC_CORKI_CREDIT_3); - } - } - - return true; - } -}; - -class npc_corki : public CreatureScript -{ -public: - npc_corki() : CreatureScript("npc_corki") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_corkiAI(creature); - } - - struct npc_corkiAI : public ScriptedAI - { - npc_corkiAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 Say_Timer; - bool ReleasedFromCage; - - void Reset() override - { - Say_Timer = 5000; - ReleasedFromCage = false; - } - - void UpdateAI(uint32 diff) override - { - if (ReleasedFromCage) - { - if (Say_Timer <= diff) - { - me->DespawnOrUnsummon(); - ReleasedFromCage = false; - } - else - Say_Timer -= diff; - } - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE && id == 1) - { - Say_Timer = 5000; - ReleasedFromCage = true; - if (me->GetEntry() == NPC_CORKI) - Talk(CORKI_SAY_THANKS); - if (me->GetEntry() == NPC_CORKI_2) - Talk(CORKI_SAY_PROMISE); - if (me->GetEntry() == NPC_CORKI_3) - Talk(CORKI_SAY_LAST); - } - }; - }; -}; - /*##### ## npc_kurenai_captive #####*/ @@ -608,8 +487,6 @@ void AddSC_nagrand() { new npc_maghar_captive(); new npc_creditmarker_visit_with_ancestors(); - new npc_corki(); - new go_corkis_prison(); new npc_kurenai_captive(); new go_warmaul_prison(); } From 4d68c79edfaca1362a30eacf7096385dd9a2cf85 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Sat, 22 Jul 2023 12:27:53 +0000 Subject: [PATCH 17/19] chore(DB): import pending files Referenced commit(s): 076534852bbac37fce40e6e5cf46f021abbf034e --- .../rev_1682394052134857558.sql => db_world/2023_07_22_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1682394052134857558.sql => db_world/2023_07_22_00.sql} (99%) diff --git a/data/sql/updates/pending_db_world/rev_1682394052134857558.sql b/data/sql/updates/db_world/2023_07_22_00.sql similarity index 99% rename from data/sql/updates/pending_db_world/rev_1682394052134857558.sql rename to data/sql/updates/db_world/2023_07_22_00.sql index 7b1b524b1..f914b1895 100644 --- a/data/sql/updates/pending_db_world/rev_1682394052134857558.sql +++ b/data/sql/updates/db_world/2023_07_22_00.sql @@ -1,3 +1,4 @@ +-- DB update 2023_07_19_04 -> 2023_07_22_00 UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName`='' WHERE `entry` IN (18445,18369,20812); UPDATE `gameobject_template` SET `Data2`=300000, `AIName`='SmartGameObjectAI', `ScriptName`='' WHERE `entry` IN (182521,182349,182350); DELETE FROM `smart_scripts` WHERE `entryorguid` IN (182521,182349,182350) AND `source_type`=1; From 338a5fe3080e8e606c58f4a2d2c1b5005ee177b9 Mon Sep 17 00:00:00 2001 From: Dan <83884799+elthehablo@users.noreply.github.com> Date: Sun, 23 Jul 2023 08:27:19 +0200 Subject: [PATCH 18/19] fix(Scripts/Magtheridon): allow for Magtheridon to also break free immediately when all Hellfire Channelers are killed (#16794) * initial * oops * add space Co-authored-by: Skjalf <47818697+Nyeriah@users.noreply.github.com> * another space Co-authored-by: Skjalf <47818697+Nyeriah@users.noreply.github.com> * everything in doaction, scheduler is dumb * leftovers turns out the free say line was unused --------- --- .../hellfire-channeler-does-action-on-mag.sql | 12 ++ .../MagtheridonsLair/boss_magtheridon.cpp | 126 +++++++++++------- 2 files changed, 93 insertions(+), 45 deletions(-) create mode 100644 data/sql/updates/pending_db_world/hellfire-channeler-does-action-on-mag.sql diff --git a/data/sql/updates/pending_db_world/hellfire-channeler-does-action-on-mag.sql b/data/sql/updates/pending_db_world/hellfire-channeler-does-action-on-mag.sql new file mode 100644 index 000000000..aee6f56c7 --- /dev/null +++ b/data/sql/updates/pending_db_world/hellfire-channeler-does-action-on-mag.sql @@ -0,0 +1,12 @@ +-- +DELETE FROM `smart_scripts` WHERE `entryorguid` = 17256 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`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(17256, 0, 0, 0, 0, 0, 100, 0, 20900, 28200, 12100, 19400, 0, 11, 30510, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - In Combat - Cast \'Shadow Bolt Volley\''), +(17256, 0, 1, 0, 74, 0, 100, 0, 0, 50, 14500, 15000, 30, 11, 30528, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Friendly Between 0-50% Health - Cast \'Dark Mending\''), +(17256, 0, 2, 0, 0, 0, 100, 0, 6000, 12000, 17000, 28000, 0, 11, 30530, 0, 0, 0, 0, 0, 6, 30, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - In Combat - Cast \'Fear\''), +(17256, 0, 3, 0, 0, 0, 100, 0, 19650, 63350, 60000, 60000, 0, 11, 30511, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - In Combat - Cast \'Burning Abyssal\''), +(17256, 0, 4, 0, 1, 0, 100, 0, 3600, 3600, 3600, 3600, 0, 11, 30207, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - Out of Combat - Cast \'Shadow Grasp\''), +(17256, 0, 5, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 11, 30531, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Just Died - Cast \'Soul Transfer\''), +(17256, 0, 6, 0, 6, 0, 100, 512, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 10, 91254, 17257, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Just Died - Do Action on Magtheridon'), +(17256, 0, 7, 0, 4, 0, 100, 512, 0, 0, 0, 0, 0, 34, 10, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Aggro - Set Instance Data 10 to 1'), +(17256, 0, 8, 0, 25, 0, 100, 512, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Reset - Set Reactstate Defensive'); diff --git a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp index d537d9a50..45db5585b 100644 --- a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp @@ -59,7 +59,13 @@ enum Spells enum Groups { - GROUP_INTERRUPT_CHECK = 0 + GROUP_INTERRUPT_CHECK = 0, + GROUP_EARLY_RELEASE_CHECK = 1 +}; + +enum Actions +{ + ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT = 1 }; class DealDebrisDamage : public BasicEvent @@ -92,8 +98,10 @@ struct boss_magtheridon : public BossAI void Reset() override { BossAI::Reset(); + _channelersKilled = 0; _currentPhase = 0; _recentlySpoken = false; + _magReleased = false; _interruptScheduler.CancelAll(); scheduler.Schedule(90s, [this](TaskContext context) { @@ -154,60 +162,86 @@ struct boss_magtheridon : public BossAI BossAI::JustDied(killer); } + void ScheduleCombatEvents() + { + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToPC(false); + me->SetReactState(REACT_AGGRESSIVE); + instance->SetData(DATA_ACTIVATE_CUBES, 1); + me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE); + + scheduler.Schedule(9s, [this](TaskContext context) + { + DoCastVictim(SPELL_CLEAVE); + context.Repeat(1200ms, 16300ms); + }).Schedule(20s, [this](TaskContext context) + { + me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1); + context.Repeat(11s, 39s); + }).Schedule(40s, [this](TaskContext context) + { + DoCastSelf(SPELL_QUAKE); //needs fixes with custom spell + scheduler.Schedule(7s, [this](TaskContext /*context*/) + { + DoCastSelf(SPELL_BLAST_NOVA); + + _interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context) + { + if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5) + { + Talk(SAY_BANISH); + me->InterruptNonMeleeSpells(true); + scheduler.CancelGroup(GROUP_INTERRUPT_CHECK); + } + else + context.Repeat(50ms); + }).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/) + { + _interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK); + }); + }); + context.Repeat(53s, 56s); + }).Schedule(22min, [this](TaskContext /*context*/) + { + DoCastSelf(SPELL_BERSERK, true); + }); + } + + void DoAction(int32 action) override + { + if (action == ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT) + { + _channelersKilled++; + + if (_channelersKilled >= 5 && !_magReleased) + { + Talk(SAY_EMOTE_FREE); + Talk(SAY_FREE); + scheduler.CancelGroup(GROUP_EARLY_RELEASE_CHECK); //cancel regular countdown + scheduler.Schedule(3s, [this](TaskContext) + { + _magReleased = true; //redundancy + ScheduleCombatEvents(); + }); + } + } + } + void JustEngagedWith(Unit* who) override { BossAI::JustEngagedWith(who); Talk(SAY_EMOTE_BEGIN); - scheduler.Schedule(60s, [this](TaskContext /*context*/) + scheduler.Schedule(60s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/) { Talk(SAY_EMOTE_NEARLY); - }).Schedule(120s, [this](TaskContext /*context*/) + }).Schedule(120s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/) { Talk(SAY_EMOTE_FREE); - }).Schedule(123s, [this](TaskContext /*context*/) + Talk(SAY_FREE); + }).Schedule(123s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/) { - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToPC(false); - me->SetReactState(REACT_AGGRESSIVE); - instance->SetData(DATA_ACTIVATE_CUBES, 1); - me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE); - - scheduler.Schedule(9s, [this](TaskContext context) - { - DoCastVictim(SPELL_CLEAVE); - context.Repeat(1200ms, 16300ms); - }).Schedule(20s, [this](TaskContext context) - { - me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1); - context.Repeat(11s, 39s); - }).Schedule(40s, [this](TaskContext context) - { - DoCastSelf(SPELL_QUAKE); //needs fixes with custom spell - scheduler.Schedule(7s, [this](TaskContext /*context*/) - { - DoCastSelf(SPELL_BLAST_NOVA); - - _interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context) - { - if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5) - { - Talk(SAY_BANISH); - me->InterruptNonMeleeSpells(true); - scheduler.CancelGroup(GROUP_INTERRUPT_CHECK); - } - else - context.Repeat(50ms); - }).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/) - { - _interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK); - }); - }); - context.Repeat(53s, 56s); - }).Schedule(1320s, [this](TaskContext /*context*/) - { - DoCastSelf(SPELL_BERSERK, true); - }); + ScheduleCombatEvents(); }); } @@ -227,7 +261,9 @@ struct boss_magtheridon : public BossAI private: bool _recentlySpoken; + bool _magReleased; uint8 _currentPhase; + uint8 _channelersKilled; TaskScheduler _interruptScheduler; }; From 1b59645996321601584a99efaa1ca0173ad4f1bf Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Sun, 23 Jul 2023 06:29:33 +0000 Subject: [PATCH 19/19] chore(DB): import pending files Referenced commit(s): 338a5fe3080e8e606c58f4a2d2c1b5005ee177b9 --- .../2023_07_23_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/hellfire-channeler-does-action-on-mag.sql => db_world/2023_07_23_00.sql} (97%) diff --git a/data/sql/updates/pending_db_world/hellfire-channeler-does-action-on-mag.sql b/data/sql/updates/db_world/2023_07_23_00.sql similarity index 97% rename from data/sql/updates/pending_db_world/hellfire-channeler-does-action-on-mag.sql rename to data/sql/updates/db_world/2023_07_23_00.sql index aee6f56c7..3918be95c 100644 --- a/data/sql/updates/pending_db_world/hellfire-channeler-does-action-on-mag.sql +++ b/data/sql/updates/db_world/2023_07_23_00.sql @@ -1,3 +1,4 @@ +-- DB update 2023_07_22_00 -> 2023_07_23_00 -- DELETE FROM `smart_scripts` WHERE `entryorguid` = 17256 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`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES