diff --git a/data/sql/updates/db_world/2022_09_14_00.sql b/data/sql/updates/db_world/2022_09_14_00.sql new file mode 100644 index 000000000..a79dc4b8c --- /dev/null +++ b/data/sql/updates/db_world/2022_09_14_00.sql @@ -0,0 +1,5 @@ +-- DB update 2022_09_13_03 -> 2022_09_14_00 +-- +UPDATE `spell_proc_event` SET `Cooldown`=0 WHERE `entry`=-16256; +UPDATE `spell_proc_event` SET `Cooldown`=500 WHERE `entry`=-16257; + diff --git a/data/sql/updates/db_world/2022_09_14_01.sql b/data/sql/updates/db_world/2022_09_14_01.sql new file mode 100644 index 000000000..5d9cc39f7 --- /dev/null +++ b/data/sql/updates/db_world/2022_09_14_01.sql @@ -0,0 +1,8 @@ +-- DB update 2022_09_14_00 -> 2022_09_14_01 +-- +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 12256; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 12256); +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 +(12256, 0, 0, 1, 8, 0, 100, 512, 19250, 0, 120000, 120000, 0, 33, 12247, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Mark of Detonation - On Spellhit - Kill Credit'), +(12256, 0, 1, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 41, 0, 120, 0, 0, 0, 0, 20, 177668, 0, 0, 0, 0, 0, 0, 0, 'Mark of Detonation - On Spellhit - Despawn Mark of Detonation'); diff --git a/data/sql/updates/db_world/2022_09_14_02.sql b/data/sql/updates/db_world/2022_09_14_02.sql new file mode 100644 index 000000000..40c27604b --- /dev/null +++ b/data/sql/updates/db_world/2022_09_14_02.sql @@ -0,0 +1,10 @@ +-- DB update 2022_09_14_01 -> 2022_09_14_02 +-- +UPDATE `creature_template` SET `ScriptName`='npc_obsidian_eradicator', `AiName`='' WHERE `entry`=15262; +DELETE FROM `smart_scripts` WHERE `entryorguid`=15262 AND `source_type`=0; + +DELETE FROM `spell_script_names` WHERE `spell_id`=25671; +INSERT INTO `spell_script_names` VALUES +(25671,'spell_drain_mana'); + +UPDATE `creature_template` SET `unit_flags2`=0 WHERE `entry`=15262; diff --git a/data/sql/updates/db_world/2022_09_14_03.sql b/data/sql/updates/db_world/2022_09_14_03.sql new file mode 100644 index 000000000..b3aa80bfc --- /dev/null +++ b/data/sql/updates/db_world/2022_09_14_03.sql @@ -0,0 +1,9 @@ +-- DB update 2022_09_14_02 -> 2022_09_14_03 +-- +DELETE FROM `creature_queststarter` WHERE `id` = 15738 AND `quest` = 8815; +INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES +(15738, 8815); + +DELETE FROM `creature_questender` WHERE `id` = 15378 AND `quest` = 8832; +INSERT INTO `creature_questender` (`id`, `quest`) VALUES +(15738, 8815); diff --git a/data/sql/updates/db_world/2022_09_14_04.sql b/data/sql/updates/db_world/2022_09_14_04.sql new file mode 100644 index 000000000..833b8d23d --- /dev/null +++ b/data/sql/updates/db_world/2022_09_14_04.sql @@ -0,0 +1,4 @@ +-- DB update 2022_09_14_03 -> 2022_09_14_04 +-- +UPDATE `creature_template` SET `AiName`='', `ScriptName`='npc_anubisath_warder' WHERE `entry`=15311; +DELETE FROM `smart_scripts` WHERE `entryorguid`=15311 AND `source_type`=0; diff --git a/data/sql/updates/db_world/2022_09_14_05.sql b/data/sql/updates/db_world/2022_09_14_05.sql new file mode 100644 index 000000000..b4c3c86ef --- /dev/null +++ b/data/sql/updates/db_world/2022_09_14_05.sql @@ -0,0 +1,3 @@ +-- DB update 2022_09_14_04 -> 2022_09_14_05 +-- +UPDATE `creature_template` SET `ScriptName`='npc_vekniss_stinger' WHERE `entry`=15235; diff --git a/data/sql/updates/db_world/2022_09_15_00.sql b/data/sql/updates/db_world/2022_09_15_00.sql new file mode 100644 index 000000000..df7d98253 --- /dev/null +++ b/data/sql/updates/db_world/2022_09_15_00.sql @@ -0,0 +1,17 @@ +-- DB update 2022_09_14_05 -> 2022_09_15_00 +-- Pathing for Razorspine Entry: 23841 +SET @NPC := 39309; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-2667.589,`position_y`=-4017.5479,`position_z`=1.7994823 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-2667.589,-4017.5479,1.7994823,NULL,0,0,0,100,0), +(@PATH,2,-2682.1023,-4013.1038,7.623457,NULL,0,0,0,100,0), +(@PATH,3,-2701.14,-4009.6328,17.22806,NULL,0,0,0,100,0), +(@PATH,4,-2722.923,-4008.8137,29.876986,NULL,0,0,0,100,0), +(@PATH,5,-2737.096,-4004.9934,33.11826,NULL,0,0,0,100,0), +(@PATH,6,-2722.923,-4008.8137,29.876986,NULL,0,0,0,100,0), +(@PATH,7,-2701.14,-4009.6328,17.22806,NULL,0,0,0,100,0), +(@PATH,8,-2682.1023,-4013.1038,7.623457,NULL,0,0,0,100,0); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 099e339d9..1d8751e46 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -8348,7 +8348,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Used in case when access to whole aura is needed // All procs should be handled like this... -bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 procEx, uint32 /*cooldown*/, bool* handled) +bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 procEx, uint32 cooldown, bool* handled) { SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); @@ -8521,6 +8521,24 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp } break; } + case SPELLFAMILY_SHAMAN: + { + // Flurry + if ((dummySpell->SpellFamilyFlags[1] & 0x00000200) != 0) + { + if (cooldown) + { + if (HasSpellCooldown(dummySpell->Id)) + { + *handled = true; + break; + } + + AddSpellCooldown(dummySpell->Id, 0, cooldown); + } + } + break; + } } return false; } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 145955832..38abbb126 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1549,7 +1549,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici // collision occured if (col || dcol || (overdistance > 0.0f && !map->IsInWater(phasemask, tstX, tstY, ground, collisionHeight)) || (fabs(prevZ - tstZ) > maxtravelDistZ && (tstZ > prevZ))) { - if ((overdistance > 0.0f) && (overdistance < step)) + if ((overdistance > 0.0f) && (overdistance < 1.f)) { destx = prevX + overdistance * cos(pos.GetOrientation()); desty = prevY + overdistance * sin(pos.GetOrientation()); @@ -1592,7 +1592,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici } //} - lastpos.Relocate(destx, desty, destz + 0.5f, pos.GetOrientation()); + lastpos.Relocate(destx, desty, destz, pos.GetOrientation()); dest = SpellDestination(lastpos); } else diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp index e01f1dc05..2b2866550 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp @@ -34,7 +34,8 @@ enum Spells SPELL_EARTH_SHOCK = 26194, SPELL_TRUE_FULFILLMENT = 785, SPELL_INITIALIZE_IMAGE = 3730, - SPELL_SUMMON_IMAGES = 747 + SPELL_SUMMON_IMAGES = 747, + SPELL_BIRTH = 34115 }; enum Events @@ -42,7 +43,9 @@ enum Events EVENT_ARCANE_EXPLOSION = 1, EVENT_FULLFILMENT = 2, EVENT_BLINK = 3, - EVENT_EARTH_SHOCK = 4 + EVENT_EARTH_SHOCK = 4, + EVENT_TELEPORT = 5, + EVENT_INIT_IMAGE = 6 }; uint32 const BlinkSpells[3] = { 4801, 8195, 20449 }; @@ -56,7 +59,9 @@ struct boss_skeram : public BossAI _Reset(); _flag = 0; _hpct = 75.0f; - me->SetVisible(true); + me->SetReactState(REACT_AGGRESSIVE); + me->SetImmuneToAll(false); + me->SetControlled(false, UNIT_STATE_ROOT); } void KilledUnit(Unit* /*victim*/) override @@ -72,6 +77,29 @@ struct boss_skeram : public BossAI } void JustSummoned(Creature* creature) override + { + BossAI::JustSummoned(creature); + + float ImageHealthPct = 0.f; + if (me->GetHealthPct() < 25.0f) + ImageHealthPct = 0.50f; + else if (me->GetHealthPct() < 50.0f) + ImageHealthPct = 0.20f; + else + ImageHealthPct = 0.10f; + + creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct); + creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f)); + + creature->CastSpell(creature, SPELL_BIRTH, true); + creature->SetControlled(true, UNIT_STATE_ROOT); + creature->SetReactState(REACT_PASSIVE); + creature->SetImmuneToAll(true); + + _copiesGUIDs.push_back(creature->GetGUID()); + } + + void DoTeleport(Creature* creature) { // Shift the boss and images (Get it? *Shift*?) uint8 rand = 0; @@ -86,24 +114,18 @@ struct boss_skeram : public BossAI while (_flag & (1 << rand)) rand = urand(0, 2); - creature->CastSpell(creature, BlinkSpells[rand]); + + creature->SetReactState(REACT_AGGRESSIVE); + creature->SetImmuneToAll(false); + creature->SetControlled(false, UNIT_STATE_ROOT); + creature->CastSpell(creature, BlinkSpells[rand], true); + _flag |= (1 << rand); if (_flag & (1 << 7)) _flag = 0; - float ImageHealthPct; - - if (me->GetHealthPct() < 25.0f) - ImageHealthPct = 0.50f; - else if (me->GetHealthPct() < 50.0f) - ImageHealthPct = 0.20f; - else - ImageHealthPct = 0.10f; - - creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct); - creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f)); - BossAI::JustSummoned(creature); + events.ScheduleEvent(EVENT_INIT_IMAGE, 400ms); } void JustDied(Unit* /*killer*/) override @@ -129,7 +151,10 @@ struct boss_skeram : public BossAI events.ScheduleEvent(EVENT_BLINK, 30s, 45s); events.ScheduleEvent(EVENT_EARTH_SHOCK, 1200ms); - Talk(SAY_AGGRO); + if (!me->IsSummon()) + { + Talk(SAY_AGGRO); + } } void UpdateAI(uint32 diff) override @@ -154,23 +179,42 @@ struct boss_skeram : public BossAI case EVENT_BLINK: DoCast(me, BlinkSpells[urand(0, 2)]); DoResetThreat(); - me->SetVisible(true); events.ScheduleEvent(EVENT_BLINK, 10s, 30s); break; case EVENT_EARTH_SHOCK: DoCastVictim(SPELL_EARTH_SHOCK); events.ScheduleEvent(EVENT_EARTH_SHOCK, 1200ms); break; + case EVENT_TELEPORT: + me->SetReactState(REACT_AGGRESSIVE); + me->SetImmuneToAll(false); + me->SetControlled(false, UNIT_STATE_ROOT); + for (ObjectGuid const& guid : _copiesGUIDs) + { + if (Creature* image = ObjectAccessor::GetCreature(*me, guid)) + { + DoTeleport(image); + } + } + DoResetThreat(); + events.RescheduleEvent(EVENT_BLINK, 10s, 30s); + break; + case EVENT_INIT_IMAGE: + me->CastSpell(me, SPELL_INITIALIZE_IMAGE, true); + break; } } if (!me->IsSummon() && me->GetHealthPct() < _hpct) { + _copiesGUIDs.clear(); DoCast(me, SPELL_SUMMON_IMAGES, true); + me->SetReactState(REACT_PASSIVE); + me->SetImmuneToAll(true); + me->SetControlled(true, UNIT_STATE_ROOT); Talk(SAY_SPLIT); _hpct -= 25.0f; - me->SetVisible(false); - events.RescheduleEvent(EVENT_BLINK, 2s); + events.ScheduleEvent(EVENT_TELEPORT, 2s); } if (Unit* myVictim = me->GetVictim()) @@ -193,6 +237,7 @@ struct boss_skeram : public BossAI private: float _hpct; uint8 _flag; + GuidVector _copiesGUIDs; }; class spell_skeram_arcane_explosion : public SpellScript diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.cpp index 925a943c7..e604bd9de 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.cpp @@ -15,6 +15,8 @@ * with this program. If not, see . */ +#include "MapReference.h" +#include "Player.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" @@ -23,22 +25,36 @@ enum Spells { + // Anubisath Defender SPELL_SHADOW_FROST_REFLECT = 19595, SPELL_FIRE_ARCANE_REFLECT = 13022, SPELL_METEOR = 26558, SPELL_PLAGUE = 26556, SPELL_SHADOW_STORM = 26555, SPELL_THUNDERCLAP = 26554, - SPELL_ENRAGE = 14204, SPELL_EXPLODE = 25699, - SPELL_SUMMON_WARRIOR = 17431, SPELL_SUMMON_SWARMGUARD = 17430, + SPELL_FEAR = 26070, + SPELL_ENTAGLING_ROOTS = 26071, + SPELL_SILENCE = 26069, + SPELL_DUST_CLOUD = 26072, + SPELL_FIRE_NOVA = 26073, + SPELL_SUMMON_LARGE_OBSIDIAN_CHUNK = 27630, // Server-side - TALK_ENRAGE = 0 + SPELL_SHOCK_BLAST = 26458, + SPELL_DRAIN_MANA = 25671, + SPELL_DRAIN_MANA_VISUAL = 26639, + + TALK_ENRAGE = 0, + + // Vekniss Stinger + SPELL_VEKNISS_CATALYST = 26078, + SPELL_STINGER_CHARGE_NORMAL = 26081, + SPELL_STINGER_CHARGE_BUFFED = 26082, }; struct npc_anubisath_defender : public ScriptedAI @@ -151,6 +167,59 @@ private: bool _enraged; }; +struct npc_vekniss_stinger : public ScriptedAI +{ + npc_vekniss_stinger(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() override + { + _scheduler.CancelAll(); + } + + void EnterCombat(Unit* who) override + { + DoCast(who ,who->HasAura(SPELL_VEKNISS_CATALYST) ? SPELL_STINGER_CHARGE_BUFFED : SPELL_STINGER_CHARGE_NORMAL, true); + + _scheduler.Schedule(6s, [this](TaskContext context) + { + Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) + { + return u && !u->IsPet() && u->IsWithinDist2d(me, 20.f) && u->HasAura(SPELL_VEKNISS_CATALYST); + }); + if (!target) + { + target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) + { + return u && !u->IsPet() && u->IsWithinDist2d(me, 20.f); + }); + } + + if (target) + { + DoCast(target, target->HasAura(SPELL_VEKNISS_CATALYST) ? SPELL_STINGER_CHARGE_BUFFED : SPELL_STINGER_CHARGE_NORMAL, true); + } + + context.Repeat(6s); + }); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + return; + } + + _scheduler.Update(diff, + std::bind(&ScriptedAI::DoMeleeAttackIfReady, this)); + } + +private: + TaskScheduler _scheduler; +}; + enum NPCs { NPC_VEKNISS_DRONE = 15300 @@ -183,8 +252,166 @@ class spell_aggro_drones : public SpellScript } }; +struct npc_obsidian_eradicator : public ScriptedAI +{ + npc_obsidian_eradicator(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() override + { + _scheduler.CancelAll(); + me->SetPower(POWER_MANA, 0); + _targets.clear(); + } + + void EnterCombat(Unit* /*who*/) override + { + _scheduler.Schedule(3500ms, [this](TaskContext context) + { + if (_targets.empty()) + { + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* player = itr->GetSource()) + { + if (player->IsAlive() && !player->IsGameMaster() && !player->IsSpectator() && player->GetPower(POWER_MANA) > 0) + { + _targets.push_back(player); + } + } + } + + Acore::Containers::RandomResize(_targets, 10); + } + + for (Unit* target : _targets) + { + DoCast(target, SPELL_DRAIN_MANA, true); + } + + if (me->GetPowerPct(POWER_MANA) >= 100.f) + { + DoCastAOE(SPELL_SHOCK_BLAST, true); + } + + context.Repeat(3500ms); + }); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + return; + } + + _scheduler.Update(diff, + std::bind(&ScriptedAI::DoMeleeAttackIfReady, this)); + } + +private: + TaskScheduler _scheduler; + std::list _targets; +}; + +class spell_drain_mana : public SpellScript +{ + PrepareSpellScript(spell_drain_mana); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + { + if (Unit* target = GetHitUnit()) + { + target->CastSpell(caster, SPELL_DRAIN_MANA_VISUAL, true); + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_drain_mana::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +struct npc_anubisath_warder : public ScriptedAI +{ + npc_anubisath_warder(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() override + { + _scheduler.CancelAll(); + } + + void EnterCombat(Unit* /*who*/) override + { + if (urand(0, 1)) + { + _scheduler.Schedule(5s, 5s, [this](TaskContext context) + { + DoCastAOE(SPELL_FEAR, true); + context.Repeat(20s, 20s); + }); + } + else + { + _scheduler.Schedule(5s, 5s, [this](TaskContext context) + { + DoCastAOE(SPELL_ENTAGLING_ROOTS, true); + context.Repeat(20s, 20s); + }); + } + + if (urand(0, 1)) + { + _scheduler.Schedule(4s, 4s, [this](TaskContext context) + { + DoCastAOE(SPELL_SILENCE, true); + context.Repeat(15s, 15s); + }); + } + else + { + _scheduler.Schedule(4s, 4s, [this](TaskContext context) + { + DoCastAOE(SPELL_DUST_CLOUD, true); + context.Repeat(15s, 15s); + }); + } + + _scheduler.Schedule(2s, 2s, [this](TaskContext context) + { + DoCastAOE(SPELL_FIRE_NOVA, true); + context.Repeat(8s, 15s); + }); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + return; + } + + _scheduler.Update(diff, + std::bind(&ScriptedAI::DoMeleeAttackIfReady, this)); + } + +private: + TaskScheduler _scheduler; +}; + void AddSC_temple_of_ahnqiraj() { RegisterTempleOfAhnQirajCreatureAI(npc_anubisath_defender); + RegisterTempleOfAhnQirajCreatureAI(npc_vekniss_stinger); RegisterSpellScript(spell_aggro_drones); + RegisterTempleOfAhnQirajCreatureAI(npc_obsidian_eradicator); + RegisterSpellScript(spell_drain_mana); + RegisterTempleOfAhnQirajCreatureAI(npc_anubisath_warder); }