mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-24 06:06:23 +00:00
Merge branch 'master' into Playerbot
This commit is contained in:
@@ -167,7 +167,7 @@ void AutobroadcastMgr::SendWorldAnnouncement(uint8 textId)
|
||||
// Get player's locale
|
||||
LocaleConstant locale = player->GetSession()->GetSessionDbLocaleIndex();
|
||||
|
||||
if (!_autobroadcasts.empty())
|
||||
if (!_autobroadcasts.contains(textId))
|
||||
return;
|
||||
|
||||
std::string_view localizedMessage = ObjectMgr::GetLocaleString(_autobroadcasts[textId], locale);
|
||||
@@ -188,7 +188,7 @@ void AutobroadcastMgr::SendNotificationAnnouncement(uint8 textId)
|
||||
// Retrieve player's locale
|
||||
LocaleConstant locale = player->GetSession()->GetSessionDbLocaleIndex();
|
||||
|
||||
if (!_autobroadcasts.count(textId))
|
||||
if (!_autobroadcasts.contains(textId))
|
||||
return;
|
||||
|
||||
// Get localized message
|
||||
|
||||
@@ -4537,7 +4537,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
|
||||
// trigger update zone for alive state zone updates
|
||||
uint32 newzone, newarea;
|
||||
GetZoneAndAreaId(newzone, newarea);
|
||||
UpdateZone(newzone, newarea);
|
||||
UpdateZone(newzone, newarea, true);
|
||||
sOutdoorPvPMgr->HandlePlayerResurrects(this, newzone);
|
||||
|
||||
if (Battleground* bg = GetBattleground())
|
||||
|
||||
@@ -1852,7 +1852,7 @@ public:
|
||||
itr->SetPvP(state);
|
||||
}
|
||||
void UpdatePvP(bool state, bool _override = false);
|
||||
void UpdateZone(uint32 newZone, uint32 newArea);
|
||||
void UpdateZone(uint32 newZone, uint32 newArea, bool force = false);
|
||||
void UpdateArea(uint32 newArea);
|
||||
void SetNeedZoneUpdate(bool needUpdate) { m_needZoneUpdate = needUpdate; }
|
||||
|
||||
|
||||
@@ -1250,17 +1250,20 @@ void Player::UpdateArea(uint32 newArea)
|
||||
RemoveRestFlag(REST_FLAG_IN_FACTION_AREA);
|
||||
}
|
||||
|
||||
void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
||||
void Player::UpdateZone(uint32 newZone, uint32 newArea, bool force)
|
||||
{
|
||||
if (!newZone)
|
||||
return;
|
||||
|
||||
if (m_zoneUpdateId != newZone)
|
||||
if (m_zoneUpdateId != newZone || force)
|
||||
{
|
||||
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sOutdoorPvPMgr->HandlePlayerEnterZone(this, newZone);
|
||||
sWorldState->HandlePlayerLeaveZone(this, static_cast<WorldStateZoneId>(m_zoneUpdateId));
|
||||
sWorldState->HandlePlayerEnterZone(this, static_cast<WorldStateZoneId>(newZone));
|
||||
}
|
||||
if (m_zoneUpdateId != newZone)
|
||||
{
|
||||
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sBattlefieldMgr->HandlePlayerEnterZone(this, newZone);
|
||||
SendInitWorldStates(newZone,
|
||||
|
||||
@@ -65,7 +65,10 @@ enum Misc
|
||||
|
||||
struct boss_brutallus : public BossAI
|
||||
{
|
||||
boss_brutallus(Creature* creature) : BossAI(creature, DATA_BRUTALLUS) { }
|
||||
boss_brutallus(Creature* creature) : BossAI(creature, DATA_BRUTALLUS)
|
||||
{
|
||||
me->SetCorpseDelay(360);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
|
||||
@@ -69,10 +69,12 @@ enum Spells
|
||||
SPELL_BLAZE_SUMMON = 45236
|
||||
};
|
||||
|
||||
enum Misc
|
||||
enum TwinPhases
|
||||
{
|
||||
ACTION_SISTER_DIED = 1,
|
||||
GROUP_SPECIAL_ABILITY = 1
|
||||
GROUP_SPECIAL_ABILITY = 1,
|
||||
GROUP_PYROGENICS = 2,
|
||||
GROUP_FLAME_SEAR = 3
|
||||
};
|
||||
|
||||
struct boss_sacrolash : public BossAI
|
||||
@@ -226,16 +228,29 @@ struct boss_alythess : public BossAI
|
||||
Talk(YELL_SISTER_SACROLASH_DEAD);
|
||||
me->CastSpell(me, SPELL_EMPOWER, true);
|
||||
|
||||
scheduler.CancelGroup(GROUP_SPECIAL_ABILITY);
|
||||
scheduler.CancelAll();
|
||||
|
||||
ScheduleTimedEvent(1s, [&] {
|
||||
DoCastVictim(SPELL_BLAZE);
|
||||
}, 3800ms);
|
||||
|
||||
scheduler.Schedule(16s, GROUP_PYROGENICS, [this](TaskContext context) {
|
||||
DoCastSelf(SPELL_PYROGENICS);
|
||||
context.Repeat(16s, 28s);
|
||||
});
|
||||
|
||||
ScheduleTimedEvent(8s, 10s, [&] {
|
||||
me->CastCustomSpell(SPELL_FLAME_SEAR, SPELLVALUE_MAX_TARGETS, urand(4, 5), me, TRIGGERED_NONE);
|
||||
}, 8s, 10s);
|
||||
|
||||
ScheduleTimedEvent(20s, 26s, [&] {
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
DoCast(target, SPELL_SHADOW_NOVA);
|
||||
|
||||
if (Creature * sacrolash = instance->GetCreature(DATA_SACROLASH))
|
||||
if (Creature* sacrolash = instance->GetCreature(DATA_SACROLASH))
|
||||
sacrolash->AI()->Talk(EMOTE_SHADOW_NOVA, target);
|
||||
|
||||
}, 20s, 26s);
|
||||
}
|
||||
}
|
||||
@@ -253,10 +268,13 @@ struct boss_alythess : public BossAI
|
||||
DoCastVictim(SPELL_BLAZE);
|
||||
}, 3800ms);
|
||||
|
||||
ScheduleTimedEvent(21s, 34s, [&] {
|
||||
// PYROGENICS Phase 1
|
||||
scheduler.Schedule(21s, GROUP_PYROGENICS, [this](TaskContext context) {
|
||||
DoCastSelf(SPELL_PYROGENICS);
|
||||
}, 21s, 34s);
|
||||
context.Repeat(21s, 34s);
|
||||
});
|
||||
|
||||
// FLAME_SEAR Phase 1
|
||||
ScheduleTimedEvent(10s, 15s, [&] {
|
||||
me->CastCustomSpell(SPELL_FLAME_SEAR, SPELLVALUE_MAX_TARGETS, urand(4, 5), me, TRIGGERED_NONE);
|
||||
}, 10s, 15s);
|
||||
|
||||
@@ -85,6 +85,7 @@ enum Misc
|
||||
|
||||
GROUP_START_INTRO = 0,
|
||||
GROUP_BREATH = 1,
|
||||
GROUP_TAKEOFF = 2,
|
||||
|
||||
NPC_FOG_TRIGGER = 23472,
|
||||
NPC_KALECGOS_FELMYST = 24844, // Same as Magister's Terrace
|
||||
@@ -214,19 +215,25 @@ struct boss_felmyst : public BossAI
|
||||
}, 7500ms);
|
||||
|
||||
ScheduleTimedEvent(13s, 30s, [&] {
|
||||
Talk(YELL_BREATH);
|
||||
DoCastVictim(SPELL_CORROSION);
|
||||
if (scheduler.GetNextGroupOccurrence(GROUP_TAKEOFF) > 2s)
|
||||
{
|
||||
Talk(YELL_BREATH);
|
||||
DoCastVictim(SPELL_CORROSION);
|
||||
}
|
||||
}, 30s, 39s);
|
||||
|
||||
ScheduleTimedEvent(18s, 43s, [&] {
|
||||
DoCastSelf(SPELL_GAS_NOVA);
|
||||
if (scheduler.GetNextGroupOccurrence(GROUP_TAKEOFF) > 2s)
|
||||
DoCastSelf(SPELL_GAS_NOVA);
|
||||
}, 18s, 43s);
|
||||
|
||||
ScheduleTimedEvent(26s, 53s, [&] {
|
||||
DoCastRandomTarget(SPELL_ENCAPSULATE_CHANNEL, 0, 50.0f);
|
||||
if (scheduler.GetNextGroupOccurrence(GROUP_TAKEOFF) > 9s)
|
||||
DoCastRandomTarget(SPELL_ENCAPSULATE_CHANNEL, 0, 50.0f);
|
||||
}, 26s, 53s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
scheduler.Schedule(1min, GROUP_TAKEOFF, [&](TaskContext)
|
||||
{
|
||||
Talk(YELL_TAKEOFF);
|
||||
scheduler.CancelAll();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
@@ -241,7 +248,7 @@ struct boss_felmyst : public BossAI
|
||||
SetInvincibility(true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->GetMotionMaster()->MovePoint(POINT_TAKEOFF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 20.0f);
|
||||
}, 1min);
|
||||
});
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 point) override
|
||||
|
||||
@@ -324,8 +324,14 @@ struct boss_kiljaeden : public BossAI
|
||||
});
|
||||
|
||||
ScheduleTimedEvent(15s, [&] {
|
||||
me->RemoveAurasDueToSpell(SPELL_ARMAGEDDON_PERIODIC);
|
||||
Talk(EMOTE_KJ_DARKNESS);
|
||||
DoCastAOE(SPELL_DARKNESS_OF_A_THOUSAND_SOULS);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]() {
|
||||
if (me->IsAlive() && me->IsInCombat())
|
||||
DoCastSelf(SPELL_ARMAGEDDON_PERIODIC, true);
|
||||
}, 9s);
|
||||
}, 45s);
|
||||
|
||||
ScheduleTimedEvent(10s, [&] {
|
||||
@@ -335,6 +341,19 @@ struct boss_kiljaeden : public BossAI
|
||||
|
||||
ScheduleHealthCheckEvent(25, [&] {
|
||||
_phase = PHASE_SACRIFICE;
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
Talk(SAY_KJ_REFLECTION);
|
||||
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
|
||||
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
|
||||
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
|
||||
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
|
||||
}, 1s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
DoCastSelf(SPELL_SHADOW_SPIKE);
|
||||
}, 2s);
|
||||
|
||||
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
|
||||
{
|
||||
kalec->AI()->Talk(SAY_KALECGOS_FOCUS, 8s);
|
||||
@@ -371,17 +390,15 @@ struct boss_kiljaeden : public BossAI
|
||||
|
||||
ScheduleBasicAbilities();
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
Talk(SAY_KJ_REFLECTION);
|
||||
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
|
||||
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
|
||||
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
|
||||
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
|
||||
}, 1s);
|
||||
|
||||
ScheduleTimedEvent(15s, [&] {
|
||||
ScheduleTimedEvent(25s, [&] {
|
||||
me->RemoveAurasDueToSpell(SPELL_ARMAGEDDON_PERIODIC);
|
||||
Talk(EMOTE_KJ_DARKNESS);
|
||||
DoCastAOE(SPELL_DARKNESS_OF_A_THOUSAND_SOULS);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]() {
|
||||
if (me->IsAlive() && me->IsInCombat())
|
||||
DoCastSelf(SPELL_ARMAGEDDON_PERIODIC, true);
|
||||
}, 9s);
|
||||
}, 25s);
|
||||
|
||||
ScheduleTimedEvent(1500ms, [&] {
|
||||
@@ -520,7 +537,7 @@ struct boss_kiljaeden : public BossAI
|
||||
summon->CastSpell(summon, SPELL_ARMAGEDDON_VISUAL, true);
|
||||
summon->SetPosition(summon->GetPositionX(), summon->GetPositionY(), summon->GetPositionZ() + 20.0f, 0.0f);
|
||||
summon->m_Events.AddEvent(new CastArmageddon(summon), summon->m_Events.CalculateTime(6000));
|
||||
summon->DespawnOrUnsummon(10000);
|
||||
summon->DespawnOrUnsummon(urand(8000, 10000));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1082,8 +1099,15 @@ class spell_kiljaeden_armageddon_periodic_aura : public AuraScript
|
||||
void HandlePeriodic(AuraEffect const* aurEff)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
if (Unit* target = GetUnitOwner()->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
|
||||
GetUnitOwner()->CastSpell(target, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true);
|
||||
Unit* caster = GetUnitOwner();
|
||||
|
||||
std::list<Creature*> armageddons;
|
||||
caster->GetCreatureListWithEntryInGrid(armageddons, NPC_ARMAGEDDON_TARGET, 100.0f);
|
||||
if (armageddons.size() >= 3)
|
||||
return;
|
||||
|
||||
if (Unit* target = caster->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
|
||||
caster->CastSpell(target, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -48,10 +48,17 @@ enum Spells
|
||||
|
||||
//Black Hole Spells
|
||||
SPELL_BLACK_HOLE_SUMMON_VISUAL = 46242,
|
||||
SPELL_BLACK_HOLE_SUMMON_VISUAL2 = 46248,
|
||||
SPELL_BLACK_HOLE_SUMMON_VISUAL2 = 46247,
|
||||
SPELL_BLACK_HOLE_VISUAL2 = 46235,
|
||||
SPELL_BLACK_HOLE_PASSIVE = 46228,
|
||||
SPELL_BLACK_HOLE_EFFECT = 46230
|
||||
SPELL_BLACK_HOLE_EFFECT = 46230,
|
||||
|
||||
// Dark Fiend Spells
|
||||
SPELL_DARK_FIEND_APPEARANCE = 45934,
|
||||
SPELL_DARK_FIEND_SECONDARY = 45936,
|
||||
SPELL_DARK_FIEND_TRIGGER = 45944
|
||||
// It is currently unkown why Dark Fiend Casts this or what it should do
|
||||
//SPELL_DARK_FIEND_TRIGGER_SINGLE = 45943
|
||||
};
|
||||
|
||||
struct boss_muru : public BossAI
|
||||
@@ -67,6 +74,17 @@ struct boss_muru : public BossAI
|
||||
me->m_Events.KillAllEvents(false);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
// Radius of room is ~38.5f this might need adjusting a bit
|
||||
// Radius ~36.0 is right inside
|
||||
// Radius 20.0 is outer circle
|
||||
if (!me->IsInCombat() && who->IsPlayer() && who->GetPositionZ() > 69.0f && me->IsWithinDistInMap(who, 25.0f))
|
||||
{
|
||||
me->SetInCombatWithZone();
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
@@ -169,10 +187,81 @@ struct boss_entropius : public ScriptedAI
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_dark_fiend : public ScriptedAI
|
||||
{
|
||||
npc_dark_fiend(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_lastVictimGUID.Clear();
|
||||
_spellCast = false;
|
||||
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
DoCast(me, SPELL_DARK_FIEND_APPEARANCE);
|
||||
DoCast(me, SPELL_DARK_FIEND_SECONDARY);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]() {
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
if (Unit* target = SelectTargetFromPlayerList(200.0f, 0, true))
|
||||
{
|
||||
AttackStart(target);
|
||||
me->AddThreat(target, 100000.0f);
|
||||
}
|
||||
}, 1s, 2s);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*schoolMask*/) override
|
||||
{
|
||||
if (damage >= me->GetHealth())
|
||||
damage = me->GetHealth() - me->GetMaxHealth() * 0.01f;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
{
|
||||
if (!me->HasAura(SPELL_DARK_FIEND_APPEARANCE))
|
||||
{
|
||||
me->DespawnOrUnsummon();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if victim has changed or disappeared
|
||||
Unit* currentVictim = me->GetVictim();
|
||||
ObjectGuid currentVictimGUID = currentVictim ? currentVictim->GetGUID() : ObjectGuid::Empty;
|
||||
|
||||
if (_lastVictimGUID != currentVictimGUID)
|
||||
{
|
||||
// If had a victim before but now it's gone
|
||||
if (!_lastVictimGUID.IsEmpty() && currentVictimGUID.IsEmpty())
|
||||
me->DespawnOrUnsummon();
|
||||
|
||||
_lastVictimGUID = currentVictimGUID;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!_spellCast && currentVictim && me->IsWithinMeleeRange(currentVictim, 2.0f))
|
||||
{
|
||||
DoCast(me, SPELL_DARK_FIEND_TRIGGER);
|
||||
_spellCast = true;
|
||||
me->m_Events.AddEventAtOffset([this]() {
|
||||
me->DespawnOrUnsummon();
|
||||
}, 1s);
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid _lastVictimGUID;
|
||||
bool _spellCast;
|
||||
};
|
||||
|
||||
struct npc_singularity : public NullCreatureAI
|
||||
{
|
||||
npc_singularity(Creature* creature) : NullCreatureAI(creature) { }
|
||||
@@ -180,34 +269,66 @@ struct npc_singularity : public NullCreatureAI
|
||||
void Reset() override
|
||||
{
|
||||
me->DespawnOrUnsummon(18000);
|
||||
DoCastSelf(SPELL_BLACK_HOLE_SUMMON_VISUAL, true);
|
||||
DoCastSelf(SPELL_BLACK_HOLE_SUMMON_VISUAL2, true);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
DoCastSelf(SPELL_BLACK_HOLE_SUMMON_VISUAL, true);
|
||||
}, 2s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
DoCastSelf(SPELL_BLACK_HOLE_SUMMON_VISUAL2, true);
|
||||
}, 4s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
DoCastSelf(SPELL_BLACK_HOLE_SUMMON_VISUAL, true);
|
||||
}, 6s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
DoCastSelf(SPELL_BLACK_HOLE_VISUAL2, true);
|
||||
DoCastSelf(SPELL_BLACK_HOLE_PASSIVE, true);
|
||||
|
||||
// Start following players after visuals are complete
|
||||
FindAndFollowTarget();
|
||||
}, 8s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
me->KillSelf();
|
||||
}, 17s);
|
||||
}
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
me->RemoveAurasDueToSpell(SPELL_BLACK_HOLE_SUMMON_VISUAL2);
|
||||
DoCastSelf(SPELL_BLACK_HOLE_VISUAL2, true);
|
||||
DoCastSelf(SPELL_BLACK_HOLE_PASSIVE, true);
|
||||
}, 3500ms);
|
||||
|
||||
scheduler.Schedule(5s, [this](TaskContext context)
|
||||
void FindAndFollowTarget()
|
||||
{
|
||||
scheduler.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
Player* target = nullptr;
|
||||
|
||||
auto const& playerList = me->GetMap()->GetPlayers();
|
||||
for (auto const& playerRef : playerList)
|
||||
{
|
||||
if (Player* player = playerRef.GetSource())
|
||||
if (me->GetDistance2d(player) < 15.0f && player->GetPositionZ() < 72.0f && player->IsAlive() && !player->HasAura(SPELL_BLACK_HOLE_EFFECT))
|
||||
{
|
||||
if (me->IsWithinLOSInMap(player) && player->IsAlive() && !player->HasAura(SPELL_BLACK_HOLE_EFFECT))
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(0, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), false, true);
|
||||
context.Repeat();
|
||||
return;
|
||||
target = player;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.Repeat(1s);
|
||||
if (target)
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);
|
||||
|
||||
scheduler.Schedule(6s, [this](TaskContext)
|
||||
{
|
||||
FindAndFollowTarget();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// No valid target found, check again soon
|
||||
context.Repeat(1s);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -260,7 +381,7 @@ class spell_muru_darkness_aura : public AuraScript
|
||||
|
||||
void OnPeriodic(AuraEffect const* aurEff)
|
||||
{
|
||||
if (aurEff->GetTickNumber() == 3)
|
||||
if (aurEff->GetTickNumber() == 2)
|
||||
for (uint8 i = 0; i < 8; ++i)
|
||||
GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_DARK_FIEND + i, true);
|
||||
}
|
||||
@@ -312,7 +433,9 @@ class spell_entropius_black_hole_effect : public SpellScript
|
||||
if (target->GetDistance(GetCaster()) < 5.0f)
|
||||
{
|
||||
float o = frand(0, 2 * M_PI);
|
||||
pos.Relocate(GetCaster()->GetPositionX() + 4.0f * cos(o), GetCaster()->GetPositionY() + 4.0f * std::sin(o), GetCaster()->GetPositionZ() + frand(10.0f, 15.0f));
|
||||
pos.Relocate(GetCaster()->GetPositionX() + 8.0f * cos(o),
|
||||
GetCaster()->GetPositionY() + 8.0f * std::sin(o),
|
||||
GetCaster()->GetPositionZ() + frand(2.0f, 5.0f));
|
||||
}
|
||||
else
|
||||
pos.Relocate(GetCaster()->GetPositionX(), GetCaster()->GetPositionY(), GetCaster()->GetPositionZ() + 1.0f);
|
||||
@@ -352,9 +475,9 @@ class spell_entropius_negative_energy_periodic : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_muru_blackhole : public SpellScript
|
||||
class spell_gen_summon_target_floor : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_muru_blackhole);
|
||||
PrepareSpellScript(spell_gen_summon_target_floor);
|
||||
|
||||
void ChangeSummonPos(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
@@ -362,7 +485,7 @@ class spell_muru_blackhole : public SpellScript
|
||||
return;
|
||||
|
||||
WorldLocation summonPos = *GetExplTargetDest();
|
||||
float destZ = summonPos.GetPositionZ() - GetCaster()->GetMapWaterOrGroundLevel(GetCaster()->GetPosition());
|
||||
float destZ = summonPos.GetPositionZ() - GetCaster()->GetMapWaterOrGroundLevel(summonPos);
|
||||
Position offset = { 0.0f, 0.0f, -destZ, 0.0f};
|
||||
summonPos.RelocateOffset(offset);
|
||||
SetExplTargetDest(summonPos);
|
||||
@@ -371,7 +494,7 @@ class spell_muru_blackhole : public SpellScript
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHit += SpellEffectFn(spell_muru_blackhole::ChangeSummonPos, EFFECT_0, SPELL_EFFECT_SUMMON);
|
||||
OnEffectHit += SpellEffectFn(spell_gen_summon_target_floor::ChangeSummonPos, EFFECT_0, SPELL_EFFECT_SUMMON);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -380,11 +503,12 @@ void AddSC_boss_muru()
|
||||
RegisterSunwellPlateauCreatureAI(boss_muru);
|
||||
RegisterSunwellPlateauCreatureAI(boss_entropius);
|
||||
RegisterSunwellPlateauCreatureAI(npc_singularity);
|
||||
RegisterSunwellPlateauCreatureAI(npc_dark_fiend);
|
||||
|
||||
RegisterSpellScript(spell_muru_summon_blood_elves_periodic_aura);
|
||||
RegisterSpellScript(spell_muru_darkness_aura);
|
||||
RegisterSpellScript(spell_entropius_void_zone_visual_aura);
|
||||
RegisterSpellScript(spell_entropius_black_hole_effect);
|
||||
RegisterSpellScript(spell_entropius_negative_energy_periodic);
|
||||
RegisterSpellScript(spell_muru_blackhole);
|
||||
RegisterSpellScript(spell_gen_summon_target_floor);
|
||||
}
|
||||
|
||||
@@ -282,10 +282,65 @@ private:
|
||||
uint32 _triggeredSpellId;
|
||||
};
|
||||
|
||||
enum SunbladeArchMageSpells
|
||||
{
|
||||
SPELL_ARCANE_EXPLOSION = 46553,
|
||||
SPELL_BLINK = 28401,
|
||||
SPELL_FROST_NOVA = 46555
|
||||
};
|
||||
|
||||
struct npc_sunblade_arch_mage : public ScriptedAI
|
||||
{
|
||||
npc_sunblade_arch_mage(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
scheduler.Schedule(6s, 12s, [this](TaskContext context)
|
||||
{
|
||||
DoCastAOE(SPELL_ARCANE_EXPLOSION);
|
||||
context.Repeat(12s, 18s);
|
||||
});
|
||||
|
||||
scheduler.Schedule(8s, 15s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_BLINK, true);
|
||||
DoCastAOE(SPELL_FROST_NOVA, true);
|
||||
}
|
||||
context.Repeat(20s, 25s);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler scheduler;
|
||||
};
|
||||
|
||||
void AddSC_instance_sunwell_plateau()
|
||||
{
|
||||
new instance_sunwell_plateau();
|
||||
RegisterSpellScript(spell_cataclysm_breath);
|
||||
RegisterSunwellPlateauCreatureAI(npc_sunblade_arch_mage);
|
||||
RegisterSunwellPlateauCreatureAI(npc_sunblade_scout);
|
||||
RegisterSpellScriptWithArgs(spell_sunwell_teleport, "spell_teleport_to_apex_point", SPELL_TELEPORT_TO_APEX_POINT);
|
||||
RegisterSpellScriptWithArgs(spell_sunwell_teleport, "spell_teleport_to_witchs_sanctum", SPELL_TELEPORT_TO_WITCHS_SANCTUM);
|
||||
|
||||
@@ -710,16 +710,23 @@ public:
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ADD_ARCANE_CHAINS:
|
||||
if (Player* summoner = me->ToTempSummon()->GetSummonerUnit()->ToPlayer())
|
||||
if (TempSummon* tempSummon = me->ToTempSummon())
|
||||
{
|
||||
summoner->CastSpell(summoner, SPELL_ARCANE_CHAINS_CHANNEL_II, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS & ~TRIGGERED_IGNORE_CAST_ITEM & ~TRIGGERED_IGNORE_POWER_AND_REAGENT_COST & ~TRIGGERED_IGNORE_GCD));
|
||||
_events.ScheduleEvent(EVENT_FOLLOW_PLAYER, 1s);
|
||||
if (Unit* summoner = tempSummon->GetSummonerUnit())
|
||||
{
|
||||
summoner->CastSpell(summoner, SPELL_ARCANE_CHAINS_CHANNEL_II, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS & ~TRIGGERED_IGNORE_CAST_ITEM & ~TRIGGERED_IGNORE_POWER_AND_REAGENT_COST & ~TRIGGERED_IGNORE_GCD));
|
||||
_events.ScheduleEvent(EVENT_FOLLOW_PLAYER, 1s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_FOLLOW_PLAYER:
|
||||
if (Player* summoner = me->ToTempSummon()->GetSummonerUnit()->ToPlayer())
|
||||
if (TempSummon* tempSummon = me->ToTempSummon())
|
||||
{
|
||||
StartFollow(summoner);
|
||||
if (Player* summoner = tempSummon->GetSummonerUnit()->ToPlayer())
|
||||
{
|
||||
StartFollow(summoner);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -979,37 +979,40 @@ class spell_mage_fingers_of_frost_proc_aura : public AuraScript
|
||||
{
|
||||
_chance = 100.f;
|
||||
_spell = eventInfo.GetProcSpell();
|
||||
_procSpellDelayMoment = std::nullopt;
|
||||
|
||||
if (!_spell || _spell->GetDelayMoment() <= 0)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
}
|
||||
|
||||
if (_spell)
|
||||
_procSpellDelayMoment = _spell->GetDelayMoment();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (eventInfo.GetSpellPhaseMask() == PROC_SPELL_PHASE_FINISH || ((_spell && _spell->GetDelayMoment() > 0) || !eventInfo.GetDamageInfo()))
|
||||
{
|
||||
if (eventInfo.GetSpellPhaseMask() == PROC_SPELL_PHASE_FINISH || (_procSpellDelayMoment.value_or(0) > 0 || !eventInfo.GetDamageInfo()))
|
||||
PreventDefaultAction();
|
||||
}
|
||||
|
||||
_chance = 0.f;
|
||||
_spell = nullptr;
|
||||
ResetProcState();
|
||||
}
|
||||
}
|
||||
|
||||
void HandleAfterEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
|
||||
{
|
||||
if (eventInfo.GetSpellPhaseMask() == PROC_SPELL_PHASE_HIT)
|
||||
switch (eventInfo.GetSpellPhaseMask())
|
||||
{
|
||||
_chance = 100.f;
|
||||
}
|
||||
else if (eventInfo.GetSpellPhaseMask() == PROC_SPELL_PHASE_FINISH)
|
||||
{
|
||||
_chance = 0.f;
|
||||
_spell = nullptr;
|
||||
case PROC_SPELL_PHASE_HIT: _chance = 100.f; break;
|
||||
case PROC_SPELL_PHASE_FINISH: ResetProcState(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void ResetProcState()
|
||||
{
|
||||
_chance = 0.f;
|
||||
_spell = nullptr;
|
||||
_procSpellDelayMoment = std::nullopt;
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_mage_fingers_of_frost_proc_aura::CheckProc);
|
||||
@@ -1019,10 +1022,15 @@ class spell_mage_fingers_of_frost_proc_aura : public AuraScript
|
||||
}
|
||||
|
||||
public:
|
||||
// May point to a deleted object.
|
||||
// Dereferencing is unsafe unless validity is guaranteed by the caller.
|
||||
Spell const* GetProcSpell() const { return _spell; }
|
||||
|
||||
private:
|
||||
float _chance = 0.f;
|
||||
std::optional<uint64> _procSpellDelayMoment = std::nullopt;
|
||||
|
||||
// May be dangling; points to memory that might no longer be valid.
|
||||
Spell const* _spell = nullptr;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user