diff options
author | treeston <treeston.mmoc@gmail.com> | 2015-10-09 18:38:54 +0200 |
---|---|---|
committer | treeston <treeston.mmoc@gmail.com> | 2015-11-30 20:18:55 +0100 |
commit | 5dd61633872fc40d83dfa13aa58a1c7de717c012 (patch) | |
tree | 48221a430bb689be9195aa9d3a89dd5c9107a111 | |
parent | c1b4cd21f3debc2eb5e462c5adce659b558c7dc9 (diff) |
Scripts/Naxxramas: Maexxna cleanup:
- Improved Web Wrap target selection
- Added missing text
- Cleanup of web wrap positioning - two players will never be flung to the same position (25-man)
- Further improvement to web wrap spawn behavior - targetable web wrap now only spawns after the player has finished being flung to the respective position (blizzlike)
- Add additional web wrap positions (sniff)
-rw-r--r-- | sql/updates/world/2015_10_09_maexxna.sql | 6 | ||||
-rw-r--r-- | src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp | 151 |
2 files changed, 111 insertions, 46 deletions
diff --git a/sql/updates/world/2015_10_09_maexxna.sql b/sql/updates/world/2015_10_09_maexxna.sql new file mode 100644 index 00000000000..375d0941adb --- /dev/null +++ b/sql/updates/world/2015_10_09_maexxna.sql @@ -0,0 +1,6 @@ +-- maexxna cleanup +DELETE FROM `creature_text` WHERE `entry`=15952; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`probability`,`BroadcastTextId`,`TextRange`,`comment`) VALUES +(15952,0,0,"Spiderlings appear on the web!",41,100,32305,3,"Maexxna EMOTE_SPIDERS"), +(15952,1,0,"%s spins her web into a cocoon!",41,100,32303,3,"Maexxna EMOTE_WEB_WRAP"), +(15952,2,0,"%s sprays strands of web everywhere!",41,100,32304,3,"Maexxna EMOTE_WEB_SPRAY"); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index e52731d003e..5c4d0ad4560 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -18,6 +18,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "PassiveAI.h" +#include "SpellScript.h" #include "naxxramas.h" enum Spells @@ -28,6 +29,14 @@ enum Spells SPELL_NECROTIC_POISON = 28776, SPELL_FRENZY = 54123 }; +#define SPELL_FRENZY_HELPER RAID_MODE(54123,54124) + +enum Emotes +{ + EMOTE_SPIDERS = 0, + EMOTE_WEB_WRAP = 1, + EMOTE_WEB_SPRAY = 2 +}; enum Creatures { @@ -35,12 +44,16 @@ enum Creatures NPC_SPIDERLING = 17055, }; -#define MAX_POS_WRAP 3 -const Position PosWrap[MAX_POS_WRAP] = +#define MAX_WRAP_POSITION 7 +const Position WrapPositions[MAX_WRAP_POSITION] = { - {3546.796f, -3869.082f, 296.450f, 0.0f}, - {3531.271f, -3847.424f, 299.450f, 0.0f}, - {3497.067f, -3843.384f, 302.384f, 0.0f}, + {3453.818f, -3854.651f, 308.7581f, 4.362833f}, + {3535.042f, -3842.383f, 300.795f, 3.179324f}, + {3538.399f, -3846.088f, 299.964f, 4.310297f}, + {3548.464f, -3854.676f, 298.6075f, 4.546609f}, + {3557.663f, -3870.123f, 297.5027f, 3.756433f}, + {3560.546f, -3879.353f, 297.4843f, 2.508937f}, + {3562.535f, -3892.507f, 298.532f, 6.022466f}, }; enum Events @@ -51,7 +64,24 @@ enum Events EVENT_POISON, EVENT_WRAP, EVENT_SUMMON, - EVENT_FRENZY, +}; + +const float WEB_WRAP_MOVE_SPEED = 20.0f; + +struct WebTargetSelector : public std::unary_function<Unit*, bool> +{ + WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {} + bool operator()(Unit const* target) const + { + if (_maexxna->GetVictim() == target) // never target tank + return false; + if (target->HasAura(SPELL_WEB_WRAP)) // never target targets that are already webbed + return false; + return true; + } + + private: + const Unit* _maexxna; }; class boss_maexxna : public CreatureScript @@ -66,27 +96,22 @@ public: struct boss_maexxnaAI : public BossAI { - boss_maexxnaAI(Creature* creature) : BossAI(creature, BOSS_MAEXXNA) - { - Initialize(); - } + boss_maexxnaAI(Creature* creature) : BossAI(creature, BOSS_MAEXXNA) { } - void Initialize() + void EnterCombat(Unit* /*who*/) override { - enraged = false; + _EnterCombat(); + events.ScheduleEvent(EVENT_WRAP, 20 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SPRAY, 40 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SHOCK, urandms(5, 10)); + events.ScheduleEvent(EVENT_POISON, urandms(10, 15)); + events.ScheduleEvent(EVENT_SUMMON, 30 * IN_MILLISECONDS); } - bool enraged; - - void EnterCombat(Unit* /*who*/) override + void Reset() override { - _EnterCombat(); - Initialize(); - events.ScheduleEvent(EVENT_WRAP, 20000); - events.ScheduleEvent(EVENT_SPRAY, 40000); - events.ScheduleEvent(EVENT_SHOCK, urand(5000, 10000)); - events.ScheduleEvent(EVENT_POISON, urand(10000, 15000)); - events.ScheduleEvent(EVENT_SUMMON, 30000); + _Reset(); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WEB_WRAP); } void UpdateAI(uint32 diff) override @@ -94,10 +119,9 @@ public: if (!UpdateVictim() || !CheckInRoom()) return; - if (!enraged && HealthBelowPct(30)) + if (HealthBelowPct(30) && !me->HasAura(SPELL_FRENZY_HELPER)) { - enraged = true; - events.ScheduleEvent(EVENT_FRENZY, 0); // will be cast immediately + DoCast(SPELL_FRENZY); } events.Update(diff); @@ -107,41 +131,49 @@ public: switch (eventId) { case EVENT_WRAP: - /// @todo Add missing text - for (uint8 i = 0; i < RAID_MODE(1, 2); ++i) + { + std::list<Unit*> targets; + SelectTargetList(targets, WebTargetSelector(me), RAID_MODE(1, 2), SELECT_TARGET_RANDOM); + if (!targets.empty()) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true, -SPELL_WEB_WRAP)) + Talk(EMOTE_WEB_WRAP); + int8 wrapPos = -1; + for (Unit* target : targets) { + if (wrapPos == -1) // allow all positions on the first target + wrapPos = urand(0, MAX_WRAP_POSITION - 1); + else // on subsequent iterations, only allow positions that are not equal to the previous one (this is sufficient since we should only have two targets at most, ever) + wrapPos = (wrapPos + urand(1, MAX_WRAP_POSITION - 1)) % MAX_WRAP_POSITION; + target->RemoveAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_WEB_SPRAY, me)); - uint8 pos = rand32() % MAX_POS_WRAP; - target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20); - if (Creature* wrap = DoSummon(NPC_WEB_WRAP, PosWrap[pos], 0, TEMPSUMMON_CORPSE_DESPAWN)) - wrap->AI()->SetGUID(target->GetGUID()); + if (Creature* wrap = DoSummon(NPC_WEB_WRAP, WrapPositions[wrapPos], 70 * IN_MILLISECONDS, TEMPSUMMON_TIMED_DESPAWN)) + { + wrap->AI()->SetGUID(target->GetGUID()); // handles application of debuff + target->GetMotionMaster()->MoveJump(WrapPositions[wrapPos], WEB_WRAP_MOVE_SPEED, WEB_WRAP_MOVE_SPEED); // move after stun to avoid stun cancelling move + } } } events.ScheduleEvent(EVENT_WRAP, 40000); break; + } case EVENT_SPRAY: + Talk(EMOTE_WEB_SPRAY); DoCastAOE(SPELL_WEB_SPRAY); events.ScheduleEvent(EVENT_SPRAY, 40000); break; case EVENT_SHOCK: DoCastAOE(SPELL_POISON_SHOCK); - events.ScheduleEvent(EVENT_SHOCK, urand(10000, 20000)); + events.ScheduleEvent(EVENT_SHOCK, urandms(10, 20)); break; case EVENT_POISON: DoCastVictim(SPELL_NECROTIC_POISON); - events.ScheduleEvent(EVENT_POISON, urand(10000, 20000)); - break; - case EVENT_FRENZY: - DoCast(me, SPELL_FRENZY, true); - events.ScheduleEvent(EVENT_FRENZY, 600000); + events.ScheduleEvent(EVENT_POISON, urandms(10, 20)); break; case EVENT_SUMMON: - /// @todo Add missing text + Talk(EMOTE_SPIDERS); uint8 amount = urand(8, 10); for (uint8 i = 0; i < amount; ++i) - DoSummon(NPC_SPIDERLING, me, 0, TEMPSUMMON_CORPSE_DESPAWN); + DoSummon(NPC_SPIDERLING, me, 4.0f, 5 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN); events.ScheduleEvent(EVENT_SUMMON, 40000); break; } @@ -165,23 +197,49 @@ public: struct npc_webwrapAI : public NullCreatureAI { - npc_webwrapAI(Creature* creature) : NullCreatureAI(creature) { } + npc_webwrapAI(Creature* creature) : NullCreatureAI(creature), visibleTimer(0) { } ObjectGuid victimGUID; + uint32 visibleTimer; + + void InitializeAI() override + { + me->SetVisible(false); + } void SetGUID(ObjectGuid guid, int32 /*param*/) override { + if (!guid) + return; victimGUID = guid; - if (me->m_spells[0] && victimGUID) - if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID)) - victim->CastSpell(victim, me->m_spells[0], true, NULL, NULL, me->GetGUID()); + if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID)) + { + visibleTimer = (me->GetDistance2d(victim)/WEB_WRAP_MOVE_SPEED + 0.5f) * IN_MILLISECONDS; + victim->CastSpell(victim, SPELL_WEB_WRAP, true, NULL, NULL, me->GetGUID()); + } + } + + void UpdateAI(uint32 diff) override + { + if (!visibleTimer) + return; + + if (diff >= visibleTimer) + { + visibleTimer = 0; + me->SetVisible(true); + } + else + visibleTimer -= diff; } void JustDied(Unit* /*killer*/) override { - if (me->m_spells[0] && victimGUID) + if (victimGUID && !victimGUID.IsEmpty()) if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID)) - victim->RemoveAurasDueToSpell(me->m_spells[0], me->GetGUID()); + victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP, me->GetGUID()); + + me->DespawnOrUnsummon(5 * IN_MILLISECONDS); } }; @@ -190,5 +248,6 @@ public: void AddSC_boss_maexxna() { new boss_maexxna(); + new npc_webwrap(); } |