aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortreeston <treeston.mmoc@gmail.com>2015-10-09 18:38:54 +0200
committertreeston <treeston.mmoc@gmail.com>2015-11-30 20:18:55 +0100
commit5dd61633872fc40d83dfa13aa58a1c7de717c012 (patch)
tree48221a430bb689be9195aa9d3a89dd5c9107a111
parentc1b4cd21f3debc2eb5e462c5adce659b558c7dc9 (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.sql6
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp151
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();
}