mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
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)
(cherry picked from commit 5dd6163387)
# Conflicts:
# src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
This commit is contained in:
6
sql/updates/world/2016_01_15_05_world_2015_12_08_02.sql
Normal file
6
sql/updates/world/2016_01_15_05_world_2015_12_08_02.sql
Normal file
@@ -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");
|
||||
@@ -18,16 +18,26 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "PassiveAI.h"
|
||||
#include "SpellScript.h"
|
||||
#include "naxxramas.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_WEB_WRAP = 28622,
|
||||
SPELL_WEB_SPRAY = 29484,
|
||||
SPELL_WEB_SPRAY_10 = 29484,
|
||||
SPELL_WEB_SPRAY_25 = 54125,
|
||||
SPELL_POISON_SHOCK = 28741,
|
||||
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 +45,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 +65,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 +97,22 @@ public:
|
||||
|
||||
struct boss_maexxnaAI : public BossAI
|
||||
{
|
||||
boss_maexxnaAI(Creature* creature) : BossAI(creature, BOSS_MAEXXNA)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
enraged = false;
|
||||
}
|
||||
|
||||
bool enraged;
|
||||
boss_maexxnaAI(Creature* creature) : BossAI(creature, BOSS_MAEXXNA) { }
|
||||
|
||||
void EnterCombat(Unit* /*who*/) 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);
|
||||
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);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WEB_WRAP);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -94,10 +120,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 +132,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)
|
||||
{
|
||||
target->RemoveAura(SPELL_WEB_SPRAY);
|
||||
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 (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(RAID_MODE(SPELL_WEB_SPRAY_10, SPELL_WEB_SPRAY_25));
|
||||
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:
|
||||
DoCastAOE(SPELL_WEB_SPRAY);
|
||||
Talk(EMOTE_WEB_SPRAY);
|
||||
DoCastAOE(RAID_MODE(SPELL_WEB_SPRAY_10, SPELL_WEB_SPRAY_25));
|
||||
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 +198,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.IsEmpty())
|
||||
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.IsEmpty())
|
||||
if (!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 +249,6 @@ public:
|
||||
void AddSC_boss_maexxna()
|
||||
{
|
||||
new boss_maexxna();
|
||||
|
||||
new npc_webwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user