diff options
| author | Vincent-Michael <Vincent_Michael@gmx.de> | 2014-07-20 03:06:03 +0200 |
|---|---|---|
| committer | Vincent-Michael <Vincent_Michael@gmx.de> | 2014-07-20 03:06:03 +0200 |
| commit | e68d3b0937e205c94c17d7cb1a53194b6d169fe8 (patch) | |
| tree | 326d69976375006fe244df6e858bd20e83fcae90 /src/server/scripts | |
| parent | abe8dd7abf70b3589ad0cbba19f91bd4f743bf3e (diff) | |
| parent | 0531f52008cfc4ecb28c0b3cd67504e06452ab75 (diff) | |
Merge branch 'master' of github.com:TrinityCore/TrinityCore into 4.3.4
Conflicts:
src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp
src/server/scripts/Northrend/zone_dalaran.cpp
src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp
Diffstat (limited to 'src/server/scripts')
6 files changed, 376 insertions, 369 deletions
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp index d6c0f95f967..d34123c58b2 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,13 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Selin_Fireheart -SD%Complete: 90 -SDComment: Heroic and Normal Support. Needs further testing. -SDCategory: Magister's Terrace -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "magisters_terrace.h" @@ -39,321 +31,264 @@ enum Says enum Spells { - //Crystal effect spells - SPELL_FEL_CRYSTAL_COSMETIC = 44374, + // Crystal effect spells SPELL_FEL_CRYSTAL_DUMMY = 44329, - SPELL_FEL_CRYSTAL_VISUAL = 44355, SPELL_MANA_RAGE = 44320, // This spell triggers 44321, which changes scale and regens mana Requires an entry in spell_script_target - //Selin's spells + // Selin's spells SPELL_DRAIN_LIFE = 44294, SPELL_FEL_EXPLOSION = 44314, SPELL_DRAIN_MANA = 46153 // Heroic only }; +enum Phases +{ + PHASE_NORMAL = 1, + PHASE_DRAIN = 2 +}; + +enum Events +{ + EVENT_FEL_EXPLOSION = 1, + EVENT_DRAIN_CRYSTAL, + EVENT_DRAIN_MANA, + EVENT_DRAIN_LIFE, + EVENT_EMPOWER +}; + enum Misc { - CRYSTALS_NUMBER = 5, - DATA_CRYSTALS = 6, - CREATURE_FEL_CRYSTAL = 24722 + ACTION_SWITCH_PHASE = 1 }; class boss_selin_fireheart : public CreatureScript { -public: - boss_selin_fireheart() : CreatureScript("boss_selin_fireheart") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_selin_fireheartAI>(creature); - }; + public: + boss_selin_fireheart() : CreatureScript("boss_selin_fireheart") { } - struct boss_selin_fireheartAI : public ScriptedAI - { - boss_selin_fireheartAI(Creature* creature) : ScriptedAI(creature) + struct boss_selin_fireheartAI : public BossAI { - instance = creature->GetInstanceScript(); - - Crystals.clear(); - //GUIDs per instance is static, so we only need to load them once. - uint32 size = instance->GetData(DATA_FEL_CRYSTAL_SIZE); - for (uint8 i = 0; i < size; ++i) + boss_selin_fireheartAI(Creature* creature) : BossAI(creature, DATA_SELIN) { - instance->SetData64(DATA_FEL_CRYSTAL, i); - uint64 guid = instance->GetData64(DATA_FEL_CRYSTAL); - TC_LOG_DEBUG("scripts", "Selin: Adding Fel Crystal " UI64FMTD " to list", guid); - Crystals.push_back(guid); + CrystalGUID = 0; + _scheduledEvents = false; } - } - - InstanceScript* instance; - - std::list<uint64> Crystals; - uint32 DrainLifeTimer; - uint32 DrainManaTimer; - uint32 FelExplosionTimer; - uint32 DrainCrystalTimer; - uint32 EmpowerTimer; - - bool IsDraining; - bool DrainingCrystal; - - uint64 CrystalGUID; // This will help us create a pointer to the crystal we are draining. We store GUIDs, never units in case unit is deleted/offline (offline if player of course). - - void Reset() override - { - //for (uint8 i = 0; i < CRYSTALS_NUMBER; ++i) - for (std::list<uint64>::const_iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) + void Reset() override { - //Unit* unit = ObjectAccessor::GetUnit(*me, FelCrystals[i]); - if (Creature* creature = ObjectAccessor::GetCreature(*me, *itr)) + Crystals.clear(); + me->GetCreatureListWithEntryInGrid(Crystals, NPC_FEL_CRYSTAL, 250.0f); + + for (Creature* creature : Crystals) { if (!creature->IsAlive()) - creature->Respawn(); // Let the core handle setting death state, etc. + creature->Respawn(); - // Only need to set unselectable flag. You can't attack unselectable units so non_attackable flag is not necessary here. creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - } - // Set Inst data for encounter - instance->SetBossState(DATA_SELIN, NOT_STARTED); - - DrainLifeTimer = urand(3000, 7000); - DrainManaTimer = DrainLifeTimer + 5000; - FelExplosionTimer = 2100; - if (IsHeroic()) - DrainCrystalTimer = urand(10000, 15000); - else - DrainCrystalTimer = urand(20000, 25000); - EmpowerTimer = 10000; - - IsDraining = false; - DrainingCrystal = false; - CrystalGUID = 0; - } + _Reset(); + CrystalGUID = 0; + _scheduledEvents = false; + } - void SelectNearestCrystal() - { - if (Crystals.empty()) - return; - - //float ShortestDistance = 0; - CrystalGUID = 0; - Unit* pCrystal = NULL; - Unit* CrystalChosen = NULL; - //for (uint8 i = 0; i < CRYSTALS_NUMBER; ++i) - for (std::list<uint64>::const_iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) + void DoAction(int32 action) override { - pCrystal = NULL; - //pCrystal = ObjectAccessor::GetUnit(*me, FelCrystals[i]); - pCrystal = ObjectAccessor::GetUnit(*me, *itr); - if (pCrystal && pCrystal->IsAlive()) + switch (action) { - // select nearest - if (!CrystalChosen || me->GetDistanceOrder(pCrystal, CrystalChosen, false)) - { - CrystalGUID = pCrystal->GetGUID(); - CrystalChosen = pCrystal; // Store a copy of pCrystal so we don't need to recreate a pointer to closest crystal for the movement and yell. - } + case ACTION_SWITCH_PHASE: + events.SetPhase(PHASE_NORMAL); + events.ScheduleEvent(EVENT_FEL_EXPLOSION, 2000, 0, PHASE_NORMAL); + AttackStart(me->GetVictim()); + me->GetMotionMaster()->MoveChase(me->GetVictim()); + break; + default: + break; } } - if (CrystalChosen) + + void SelectNearestCrystal() { - Talk(SAY_ENERGY); - Talk(EMOTE_CRYSTAL); + if (Crystals.empty()) + return; - CrystalChosen->CastSpell(CrystalChosen, SPELL_FEL_CRYSTAL_COSMETIC, true); + Crystals.sort(Trinity::ObjectDistanceOrderPred(me)); + if (Creature* CrystalChosen = Crystals.front()) + { + Talk(SAY_ENERGY); + Talk(EMOTE_CRYSTAL); - float x, y, z; // coords that we move to, close to the crystal. - CrystalChosen->GetClosePoint(x, y, z, me->GetObjectSize(), CONTACT_DISTANCE); + DoCast(CrystalChosen, SPELL_FEL_CRYSTAL_DUMMY); + CrystalGUID = CrystalChosen->GetGUID(); + Crystals.remove(CrystalChosen); - me->SetWalk(false); - me->GetMotionMaster()->MovePoint(1, x, y, z); - DrainingCrystal = true; - } - } + float x, y, z; + CrystalChosen->GetClosePoint(x, y, z, me->GetObjectSize(), CONTACT_DISTANCE); - void ShatterRemainingCrystals() - { - if (Crystals.empty()) - return; + events.SetPhase(PHASE_DRAIN); + me->SetWalk(false); + me->GetMotionMaster()->MovePoint(1, x, y, z); + } + } - //for (uint8 i = 0; i < CRYSTALS_NUMBER; ++i) - for (std::list<uint64>::const_iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) + void ShatterRemainingCrystals() { - //Creature* pCrystal = (ObjectAccessor::GetCreature(*me, FelCrystals[i])); - Creature* pCrystal = ObjectAccessor::GetCreature(*me, *itr); - if (pCrystal && pCrystal->IsAlive()) - pCrystal->Kill(pCrystal); + if (Crystals.empty()) + return; + + for (Creature* crystal : Crystals) + { + if (crystal && crystal->IsAlive()) + crystal->Kill(crystal); + } } - } - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - instance->SetBossState(DATA_SELIN, IN_PROGRESS); - } + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _EnterCombat(); - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_KILL); - } + events.SetPhase(PHASE_NORMAL); + events.ScheduleEvent(EVENT_FEL_EXPLOSION, 2100, 0, PHASE_NORMAL); + } - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE && id == 1) + void KilledUnit(Unit* victim) override { - Unit* CrystalChosen = ObjectAccessor::GetUnit(*me, CrystalGUID); - if (CrystalChosen && CrystalChosen->IsAlive()) - { - // Make the crystal attackable - // We also remove NON_ATTACKABLE in case the database has it set. - CrystalChosen->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); - CrystalChosen->CastSpell(me, SPELL_MANA_RAGE, true); - IsDraining = true; - } - else + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_KILL); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE && id == 1) { - // Make an error message in case something weird happened here - TC_LOG_ERROR("scripts", "Selin Fireheart unable to drain crystal as the crystal is either dead or despawned"); - DrainingCrystal = false; + Unit* CrystalChosen = ObjectAccessor::GetUnit(*me, CrystalGUID); + if (CrystalChosen && CrystalChosen->IsAlive()) + { + CrystalChosen->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + CrystalChosen->CastSpell(me, SPELL_MANA_RAGE, true); + events.ScheduleEvent(EVENT_EMPOWER, 10000, PHASE_DRAIN); + } } } - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - instance->SetBossState(DATA_SELIN, DONE); // Encounter complete! - ShatterRemainingCrystals(); - } + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _JustDied(); - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + ShatterRemainingCrystals(); + } - if (!DrainingCrystal) + void UpdateAI(uint32 diff) override { - uint32 maxPowerMana = me->GetMaxPower(POWER_MANA); - if (maxPowerMana && ((me->GetPower(POWER_MANA)*100 / maxPowerMana) < 10)) - { - if (DrainLifeTimer <= diff) - { - DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_DRAIN_LIFE); - DrainLifeTimer = 10000; - } else DrainLifeTimer -= diff; + if (!UpdateVictim()) + return; + + events.Update(diff); - // Heroic only - if (IsHeroic()) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - if (DrainManaTimer <= diff) + case EVENT_FEL_EXPLOSION: + DoCastAOE(SPELL_FEL_EXPLOSION); + events.ScheduleEvent(EVENT_FEL_EXPLOSION, 2000, 0, PHASE_NORMAL); + break; + case EVENT_DRAIN_CRYSTAL: + SelectNearestCrystal(); + _scheduledEvents = false; + break; + case EVENT_DRAIN_MANA: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true)) + DoCast(target, SPELL_DRAIN_MANA); + events.ScheduleEvent(EVENT_DRAIN_MANA, 10000, 0, PHASE_NORMAL); + break; + case EVENT_DRAIN_LIFE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true)) + DoCast(target, SPELL_DRAIN_LIFE); + events.ScheduleEvent(EVENT_DRAIN_LIFE, 10000, 0, PHASE_NORMAL); + break; + case EVENT_EMPOWER: { - DoCast(SelectTarget(SELECT_TARGET_RANDOM, 1), SPELL_DRAIN_MANA); - DrainManaTimer = 10000; - } else DrainManaTimer -= diff; + Talk(SAY_EMPOWERED); + + Creature* CrystalChosen = ObjectAccessor::GetCreature(*me, CrystalGUID); + if (CrystalChosen && CrystalChosen->IsAlive()) + CrystalChosen->Kill(CrystalChosen); + + CrystalGUID = 0; + + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveChase(me->GetVictim()); + break; + } + default: + break; } } - if (FelExplosionTimer <= diff) + if (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10) { - if (!me->IsNonMeleeSpellCast(false)) + if (events.IsInPhase(PHASE_NORMAL) && !_scheduledEvents) { - DoCast(me, SPELL_FEL_EXPLOSION); - FelExplosionTimer = 2000; - } - } else FelExplosionTimer -= diff; + _scheduledEvents = true; + uint32 timer = urand(3000, 7000); + events.ScheduleEvent(EVENT_DRAIN_LIFE, timer, 0, PHASE_NORMAL); - // If below 10% mana, start recharging - maxPowerMana = me->GetMaxPower(POWER_MANA); - if (maxPowerMana && ((me->GetPower(POWER_MANA)*100 / maxPowerMana) < 10)) - { - if (DrainCrystalTimer <= diff) - { - SelectNearestCrystal(); if (IsHeroic()) - DrainCrystalTimer = urand(10000, 15000); + { + events.ScheduleEvent(EVENT_DRAIN_CRYSTAL, urand(10000, 15000), 0, PHASE_NORMAL); + events.ScheduleEvent(EVENT_DRAIN_MANA, timer + 5000, 0, PHASE_NORMAL); + } else - DrainCrystalTimer = urand(20000, 25000); - } else DrainCrystalTimer -= diff; + events.ScheduleEvent(EVENT_DRAIN_CRYSTAL, urand(20000, 25000), 0, PHASE_NORMAL); + } } - }else - { - if (IsDraining) - { - if (EmpowerTimer <= diff) - { - IsDraining = false; - DrainingCrystal = false; - - Talk(SAY_EMPOWERED); - - Unit* CrystalChosen = ObjectAccessor::GetUnit(*me, CrystalGUID); - if (CrystalChosen && CrystalChosen->IsAlive()) - // Use Deal Damage to kill it, not setDeathState. - CrystalChosen->Kill(CrystalChosen); - - CrystalGUID = 0; - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveChase(me->GetVictim()); - } else EmpowerTimer -= diff; - } + DoMeleeAttackIfReady(); } - DoMeleeAttackIfReady(); // No need to check if we are draining crystal here, as the spell has a stun. - } - }; + private: + std::list<Creature*> Crystals; + uint64 CrystalGUID; + bool _scheduledEvents; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_selin_fireheartAI>(creature); + }; }; class npc_fel_crystal : public CreatureScript { -public: - npc_fel_crystal() : CreatureScript("npc_fel_crystal") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_fel_crystalAI(creature); - }; + public: + npc_fel_crystal() : CreatureScript("npc_fel_crystal") { } - struct npc_fel_crystalAI : public ScriptedAI - { - npc_fel_crystalAI(Creature* creature) : ScriptedAI(creature) { } - - void Reset() override { } - void EnterCombat(Unit* /*who*/) override { } - void AttackStart(Unit* /*who*/) override { } - void MoveInLineOfSight(Unit* /*who*/) override { } - - void UpdateAI(uint32 /*diff*/) override { } - - void JustDied(Unit* /*killer*/) override + struct npc_fel_crystalAI : public ScriptedAI { - if (InstanceScript* instance = me->GetInstanceScript()) + npc_fel_crystalAI(Creature* creature) : ScriptedAI(creature) { } + + void JustDied(Unit* /*killer*/) override { - Creature* Selin = (ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SELIN))); - if (Selin && Selin->IsAlive()) + if (InstanceScript* instance = me->GetInstanceScript()) { - if (CAST_AI(boss_selin_fireheart::boss_selin_fireheartAI, Selin->AI())->CrystalGUID == me->GetGUID()) - { - // Set this to false if we are the Creature that Selin is draining so his AI flows properly - CAST_AI(boss_selin_fireheart::boss_selin_fireheartAI, Selin->AI())->DrainingCrystal = false; - CAST_AI(boss_selin_fireheart::boss_selin_fireheartAI, Selin->AI())->IsDraining = false; - CAST_AI(boss_selin_fireheart::boss_selin_fireheartAI, Selin->AI())->EmpowerTimer = 10000; - if (Selin->GetVictim()) - { - Selin->AI()->AttackStart(Selin->GetVictim()); - Selin->GetMotionMaster()->MoveChase(Selin->GetVictim()); - } - } + Creature* Selin = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SELIN)); + if (Selin && Selin->IsAlive()) + Selin->AI()->DoAction(ACTION_SWITCH_PHASE); } } - } - }; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_fel_crystalAI>(creature); + }; }; void AddSC_boss_selin_fireheart() diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp index 950d3c3d8f6..65b3553fd87 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp @@ -48,13 +48,11 @@ class instance_magisters_terrace : public InstanceMapScript SetBossNumber(EncounterCount); LoadDoorData(doorData); - FelCrystals.clear(); DelrissaDeathCount = 0; SelinGUID = 0; DelrissaGUID = 0; EscapeOrbGUID = 0; - FelCristalIndex = 0; memset(KaelStatue, 0, 2 * sizeof(uint64)); } @@ -65,8 +63,6 @@ class instance_magisters_terrace : public InstanceMapScript { case DATA_DELRISSA_DEATH_COUNT: return DelrissaDeathCount; - case DATA_FEL_CRYSTAL_SIZE: - return uint32(FelCrystals.size()); default: break; } @@ -102,9 +98,6 @@ class instance_magisters_terrace : public InstanceMapScript case NPC_DELRISSA: DelrissaGUID = creature->GetGUID(); break; - case NPC_FELCRYSTALS: - FelCrystals.push_back(creature->GetGUID()); - break; default: break; } @@ -224,35 +217,18 @@ class instance_magisters_terrace : public InstanceMapScript return KaelStatue[1]; case DATA_ESCAPE_ORB: return EscapeOrbGUID; - case DATA_FEL_CRYSTAL: - if (FelCrystals.size() < FelCristalIndex) - { - TC_LOG_ERROR("scripts", "Magisters Terrace: No Fel Crystals loaded in Inst Data"); - return 0; - } - - return FelCrystals.at(FelCristalIndex); default: break; } return 0; } - void SetData64(uint32 type, uint64 value) override - { - if (type == DATA_FEL_CRYSTAL) - FelCristalIndex = value; - } - protected: - std::vector<uint64> FelCrystals; - uint64 SelinGUID; uint64 DelrissaGUID; uint64 KaelStatue[2]; uint64 EscapeOrbGUID; uint32 DelrissaDeathCount; - uint8 FelCristalIndex; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h index d3517dfccf6..8b8d7d5b875 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h @@ -28,8 +28,6 @@ enum DataTypes DATA_DELRISSA, DATA_KAELTHAS, - DATA_FEL_CRYSTAL, - DATA_FEL_CRYSTAL_SIZE, DATA_KAEL_STATUE_LEFT, DATA_KAEL_STATUE_RIGHT, @@ -42,7 +40,7 @@ enum CreatureIds { NPC_SELIN = 24723, NPC_DELRISSA = 24560, - NPC_FELCRYSTALS = 24722 + NPC_FEL_CRYSTAL = 24722 }; enum GameObjectIds diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp index f415eeacc78..d4dc5efb6d5 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp @@ -17,6 +17,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellAuras.h" #include "SpellScript.h" #include "ahnkahet.h" @@ -31,14 +32,16 @@ enum Yells enum Spells { + // Elder Nadox SPELL_BROOD_PLAGUE = 56130, H_SPELL_BROOD_RAGE = 59465, SPELL_ENRAGE = 26662, // Enraged if too far away from home SPELL_SUMMON_SWARMERS = 56119, // 2x 30178 -- 2x every 10secs - SPELL_SUMMON_SWARM_GUARD = 56120, // 1x 30176 -- every 25% - // Spells Adds - SPELL_SPRINT = 56354, - SPELL_GUARDIAN_AURA = 56151 + SPELL_SUMMON_SWARM_GUARD = 56120, // 1x 30176 + + // Adds + SPELL_SWARM_BUFF = 56281, + SPELL_SPRINT = 56354 }; enum Events @@ -63,7 +66,7 @@ class boss_elder_nadox : public CreatureScript void Reset() override { _Reset(); - AmountHealthModifier = 1; + GuardianSummoned = false; GuardianDied = false; } @@ -128,6 +131,7 @@ class boss_elder_nadox : public CreatureScript events.ScheduleEvent(EVENT_RAGE, urand(10 * IN_MILLISECONDS, 50 * IN_MILLISECONDS)); break; case EVENT_SUMMON_SWARMER: + /// @todo: summoned by egg DoCast(me, SPELL_SUMMON_SWARMERS); if (urand(1, 3) == 3) // 33% chance of dialog Talk(SAY_EGG_SAC); @@ -145,19 +149,20 @@ class boss_elder_nadox : public CreatureScript } } - if (me->HealthBelowPct(100 - AmountHealthModifier* 25)) + if (!GuardianSummoned && me->HealthBelowPct(50)) { + /// @todo: summoned by egg Talk(EMOTE_HATCHES, me); DoCast(me, SPELL_SUMMON_SWARM_GUARD); - ++AmountHealthModifier; + GuardianSummoned = true; } DoMeleeAttackIfReady(); } private: + bool GuardianSummoned; bool GuardianDied; - uint8 AmountHealthModifier; }; CreatureAI* GetAI(Creature* creature) const override @@ -175,20 +180,10 @@ class npc_ahnkahar_nerubian : public CreatureScript { npc_ahnkahar_nerubianAI(Creature* creature) : ScriptedAI(creature) { } - EventMap events; - void Reset() override { - if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN) - DoCast(me, SPELL_GUARDIAN_AURA, true); - - events.ScheduleEvent(EVENT_SPRINT, 13 * IN_MILLISECONDS); - } - - void JustDied(Unit* /*killer*/) override - { - if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN) - me->RemoveAurasDueToSpell(SPELL_GUARDIAN_AURA); + _events.Reset(); + _events.ScheduleEvent(EVENT_SPRINT, 13 * IN_MILLISECONDS); } void UpdateAI(uint32 diff) override @@ -196,23 +191,27 @@ class npc_ahnkahar_nerubian : public CreatureScript if (!UpdateVictim()) return; - events.Update(diff); + _events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { - case EVENT_SPRINT: - DoCast(me, SPELL_SPRINT); - events.ScheduleEvent(EVENT_SPRINT, 20 * IN_MILLISECONDS); - break; + case EVENT_SPRINT: + DoCast(me, SPELL_SPRINT); + _events.ScheduleEvent(EVENT_SPRINT, 20 * IN_MILLISECONDS); + break; } } + DoMeleeAttackIfReady(); } + + private: + EventMap _events; }; CreatureAI* GetAI(Creature* creature) const override @@ -221,95 +220,81 @@ class npc_ahnkahar_nerubian : public CreatureScript } }; -//HACK: No, AI. Replace with proper db content? -class npc_nadox_eggs : public CreatureScript +// 56159 - Swarm +class spell_ahn_kahet_swarm : public SpellScriptLoader { -public: - npc_nadox_eggs() : CreatureScript("npc_nadox_eggs") { } + public: + spell_ahn_kahet_swarm() : SpellScriptLoader("spell_ahn_kahet_swarm") { } - struct npc_nadox_eggsAI : public ScriptedAI - { - npc_nadox_eggsAI(Creature* creature) : ScriptedAI(creature) + class spell_ahn_kahet_swarm_SpellScript : public SpellScript { - creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - } + PrepareSpellScript(spell_ahn_kahet_swarm_SpellScript); - void Reset() override { } - void EnterCombat(Unit* /*who*/) override { } - void AttackStart(Unit* /*victim*/) override { } - void MoveInLineOfSight(Unit* /*who*/) override { } - - void UpdateAI(uint32 /*diff*/) override { } - }; + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SWARM_BUFF)) + return false; + return true; + } - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_nadox_eggsAI(creature); - } -}; + bool Load() override + { + _targetCount = 0; + return true; + } -class GuardianCheck -{ -public: - bool operator()(const WorldObject* target) const - { - if (target->GetEntry() == NPC_AHNKAHAR_GUARDIAN) - return true; - - return false; - } -}; + void CountTargets(std::list<WorldObject*>& targets) + { + _targetCount = targets.size(); + } -class spell_elder_nadox_guardian : public SpellScriptLoader -{ -public: - spell_elder_nadox_guardian() : SpellScriptLoader("spell_elder_nadox_guardian") { } + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (_targetCount) + { + if (Aura* aura = GetCaster()->GetAura(SPELL_SWARM_BUFF)) + { + aura->SetStackAmount(_targetCount); + aura->RefreshDuration(); + } + else + GetCaster()->CastCustomSpell(SPELL_SWARM_BUFF, SPELLVALUE_AURA_STACK, _targetCount, GetCaster(), TRIGGERED_FULL_MASK); + } + else + GetCaster()->RemoveAurasDueToSpell(SPELL_SWARM_BUFF); + } - class spell_elder_nadox_guardian_SpellScript : public SpellScript - { - PrepareSpellScript(spell_elder_nadox_guardian_SpellScript); + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ahn_kahet_swarm_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + OnEffectHit += SpellEffectFn(spell_ahn_kahet_swarm_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } - void FilterTargets(std::list<WorldObject*>& targets) - { - targets.remove_if (GuardianCheck()); - } + private: + uint32 _targetCount; + }; - void Register() override + SpellScript* GetSpellScript() const override { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_elder_nadox_guardian_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_elder_nadox_guardian_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ALLY); + return new spell_ahn_kahet_swarm_SpellScript(); } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_elder_nadox_guardian_SpellScript(); - } }; class achievement_respect_your_elders : public AchievementCriteriaScript { -public: - achievement_respect_your_elders() : AchievementCriteriaScript("achievement_respect_your_elders") { } - - bool OnCheck(Player* /*player*/, Unit* target) override - { - if (!target) - return false; - - if (Creature* Nadox = target->ToCreature()) - if (Nadox->AI()->GetData(DATA_RESPECT_YOUR_ELDERS)) - return true; + public: + achievement_respect_your_elders() : AchievementCriteriaScript("achievement_respect_your_elders") { } - return false; - } + bool OnCheck(Player* /*player*/, Unit* target) override + { + return target && target->GetAI()->GetData(DATA_RESPECT_YOUR_ELDERS); + } }; void AddSC_boss_elder_nadox() { new boss_elder_nadox(); new npc_ahnkahar_nerubian(); - new npc_nadox_eggs(); - new spell_elder_nadox_guardian(); + new spell_ahn_kahet_swarm(); new achievement_respect_your_elders(); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index 022c43f4395..d0ad42d38e1 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -961,9 +961,11 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript if (Creature* lichking = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING_ESCAPE))) { + me->CastSpell(lichking, SPELL_TAUNT_ARTHAS, true); + lichking->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + lichking->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); AttackStart(lichking); lichking->AI()->AttackStart(me); - me->CastSpell(lichking, SPELL_TAUNT_ARTHAS, true); } me->SetHealth(JAINA_SYLVANAS_MAX_HEALTH); me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp index 2d5028bac05..0897131eaf8 100644 --- a/src/server/scripts/Northrend/zone_dalaran.cpp +++ b/src/server/scripts/Northrend/zone_dalaran.cpp @@ -128,7 +128,118 @@ public: } }; +enum MinigobData +{ + ZONE_DALARAN = 4395, + + SPELL_MANABONKED = 61834, + SPELL_TELEPORT_VISUAL = 51347, + SPELL_IMPROVED_BLINK = 61995, + + EVENT_SELECT_TARGET = 1, + EVENT_BLINK = 2, + EVENT_DESPAWN_VISUAL = 3, + EVENT_DESPAWN = 4, + + MAIL_MINIGOB_ENTRY = 264, + MAIL_DELIVER_DELAY_MIN = 5*MINUTE, + MAIL_DELIVER_DELAY_MAX = 15*MINUTE +}; + +class npc_minigob_manabonk : public CreatureScript +{ + public: + npc_minigob_manabonk() : CreatureScript("npc_minigob_manabonk") {} + + struct npc_minigob_manabonkAI : public ScriptedAI + { + npc_minigob_manabonkAI(Creature* creature) : ScriptedAI(creature) + { + me->setActive(true); + } + + void Reset() + { + me->SetVisible(false); + events.ScheduleEvent(EVENT_SELECT_TARGET, IN_MILLISECONDS); + } + + Player* SelectTargetInDalaran() + { + std::list<Player*> PlayerInDalaranList; + PlayerInDalaranList.clear(); + + Map::PlayerList const &players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->GetSource()->ToPlayer()) + if (player->GetZoneId() == ZONE_DALARAN && !player->IsFlying() && !player->IsMounted() && !player->IsGameMaster()) + PlayerInDalaranList.push_back(player); + + if (PlayerInDalaranList.empty()) + return NULL; + return Trinity::Containers::SelectRandomContainerElement(PlayerInDalaranList); + } + + void SendMailToPlayer(Player* player) + { + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + int16 deliverDelay = irand(MAIL_DELIVER_DELAY_MIN, MAIL_DELIVER_DELAY_MAX); + MailDraft(MAIL_MINIGOB_ENTRY, true).SendMailTo(trans, MailReceiver(player), MailSender(MAIL_CREATURE, me->GetEntry()), MAIL_CHECK_MASK_NONE, deliverDelay); + CharacterDatabase.CommitTransaction(trans); + } + + void UpdateAI(uint32 diff) + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SELECT_TARGET: + me->SetVisible(true); + DoCast(me, SPELL_TELEPORT_VISUAL); + if (Player* player = SelectTargetInDalaran()) + { + me->NearTeleportTo(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0.0f); + DoCast(player, SPELL_MANABONKED); + SendMailToPlayer(player); + } + events.ScheduleEvent(EVENT_BLINK, 3*IN_MILLISECONDS); + break; + case EVENT_BLINK: + { + DoCast(me, SPELL_IMPROVED_BLINK); + Position pos = me->GetRandomNearPosition(frand(15, 40)); + me->GetMotionMaster()->MovePoint(0, pos.m_positionX, pos.m_positionY, pos.m_positionZ); + events.ScheduleEvent(EVENT_DESPAWN, 3 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_DESPAWN_VISUAL, 2.5*IN_MILLISECONDS); + break; + } + case EVENT_DESPAWN_VISUAL: + DoCast(me, SPELL_TELEPORT_VISUAL); + break; + case EVENT_DESPAWN: + me->DespawnOrUnsummon(); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_minigob_manabonkAI(creature); + } +}; + void AddSC_dalaran() { - new npc_mageguard_dalaran; + new npc_mageguard_dalaran(); + new npc_minigob_manabonk(); } |
