mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-25 06:36:24 +00:00
Merge branch 'master' into Playerbot
This commit is contained in:
@@ -63,9 +63,9 @@ enum Events
|
||||
EVENT_PYROBLAST = 6,
|
||||
// Hack due to trigger spell not in dbc
|
||||
EVENT_FIRE_SHIELD = 7,
|
||||
// Make sure all players have aura from altar
|
||||
EVENT_PLAYER_CHECK = 8,
|
||||
EVENT_ENTER_COMBAT = 9
|
||||
EVENT_PRE_ENTER_COMBAT_1 = 8,
|
||||
EVENT_PRE_ENTER_COMBAT_2 = 9,
|
||||
EVENT_ENTER_COMBAT = 10
|
||||
};
|
||||
|
||||
class boss_pyroguard_emberseer : public CreatureScript
|
||||
@@ -101,7 +101,8 @@ public:
|
||||
switch (data)
|
||||
{
|
||||
case 1:
|
||||
events.ScheduleEvent(EVENT_PLAYER_CHECK, 5s);
|
||||
events.ScheduleEvent(EVENT_PRE_FIGHT_1, 2s);
|
||||
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS);
|
||||
break;
|
||||
case 2:
|
||||
// Close these two doors on Blackhand Incarcerators aggro
|
||||
@@ -153,14 +154,12 @@ public:
|
||||
|
||||
if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 20)
|
||||
{
|
||||
me->RemoveAura(SPELL_ENCAGED_EMBERSEER);
|
||||
me->RemoveAura(SPELL_FREEZE_ANIM);
|
||||
me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH);
|
||||
Talk(EMOTE_FREE_OF_BONDS);
|
||||
Talk(YELL_FREE_OF_BONDS);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetImmuneToPC(false);
|
||||
events.ScheduleEvent(EVENT_ENTER_COMBAT, 2s);
|
||||
events.CancelEvent(EVENT_FIRE_SHIELD); // temporarily cancel fire shield to keep it from interrupting combat start
|
||||
|
||||
// Schedule out the pre-combat scene
|
||||
events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_1, 0s);
|
||||
events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_2, 2s);
|
||||
events.ScheduleEvent(EVENT_ENTER_COMBAT, 5s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,7 +234,7 @@ public:
|
||||
if (Creature* creature = *itr)
|
||||
creature->AI()->SetData(1, 1);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_PRE_FIGHT_2, 32s);
|
||||
events.ScheduleEvent(EVENT_PRE_FIGHT_2, 2s);
|
||||
break;
|
||||
}
|
||||
case EVENT_PRE_FIGHT_2:
|
||||
@@ -248,25 +247,21 @@ public:
|
||||
DoCast(me, SPELL_FIRE_SHIELD);
|
||||
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s);
|
||||
break;
|
||||
case EVENT_PLAYER_CHECK:
|
||||
{
|
||||
// Check to see if all players in instance have aura SPELL_EMBERSEER_START before starting event
|
||||
bool _hasAura = false;
|
||||
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->HasAura(SPELL_EMBERSEER_OBJECT_VISUAL))
|
||||
_hasAura = true;
|
||||
|
||||
if (_hasAura)
|
||||
{
|
||||
events.ScheduleEvent(EVENT_PRE_FIGHT_1, 1s);
|
||||
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_PRE_ENTER_COMBAT_1:
|
||||
me->RemoveAura(SPELL_ENCAGED_EMBERSEER);
|
||||
me->RemoveAura(SPELL_FREEZE_ANIM);
|
||||
me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH);
|
||||
Talk(EMOTE_FREE_OF_BONDS);
|
||||
break;
|
||||
case EVENT_PRE_ENTER_COMBAT_2:
|
||||
Talk(YELL_FREE_OF_BONDS);
|
||||
break;
|
||||
case EVENT_ENTER_COMBAT:
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetImmuneToPC(false);
|
||||
DoZoneInCombat();
|
||||
// re-enable fire shield
|
||||
events.ScheduleEvent(EVENT_FIRE_SHIELD, 0s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -347,11 +342,6 @@ public:
|
||||
_fleedForAssistance = false;
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
me->DespawnOrUnsummon(10000);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
|
||||
{
|
||||
if (!_fleedForAssistance && me->HealthBelowPctDamaged(30, damage))
|
||||
@@ -392,7 +382,6 @@ public:
|
||||
}
|
||||
|
||||
_events.ScheduleEvent(EVENT_STRIKE, 8s, 16s);
|
||||
_events.ScheduleEvent(EVENT_ENCAGE, 10s, 20s);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
|
||||
@@ -34,107 +34,70 @@ enum Spells
|
||||
SPELL_DARK_SHELL = 32358
|
||||
};
|
||||
|
||||
enum Events
|
||||
enum Groups
|
||||
{
|
||||
EVENT_VOID_BLAST = 1,
|
||||
EVENT_DARK_SHELL
|
||||
GROUP_VOID_BLAST = 1
|
||||
};
|
||||
|
||||
class boss_pandemonius : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_pandemonius() : CreatureScript("boss_pandemonius") { }
|
||||
constexpr uint8 MAX_VOID_BLAST = 5;
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
struct boss_pandemonius : public BossAI
|
||||
{
|
||||
boss_pandemonius(Creature* creature) : BossAI(creature, DATA_PANDEMONIUS)
|
||||
{
|
||||
return GetManaTombsAI<boss_pandemoniusAI>(creature);
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_pandemoniusAI : public ScriptedAI
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
boss_pandemoniusAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
EventMap events;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
VoidBlastCounter = 0;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit*) override
|
||||
{
|
||||
me->SetInCombatWithZone();
|
||||
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
events.ScheduleEvent(EVENT_DARK_SHELL, 20000);
|
||||
events.ScheduleEvent(EVENT_VOID_BLAST, urand(8000, 23000));
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
scheduler.
|
||||
Schedule(20s, GROUP_VOID_BLAST, [this](TaskContext context)
|
||||
{
|
||||
case EVENT_VOID_BLAST:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_VOID_BLAST);
|
||||
++VoidBlastCounter;
|
||||
}
|
||||
if (me->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
}
|
||||
|
||||
if (VoidBlastCounter == 5)
|
||||
Talk(EMOTE_DARK_SHELL);
|
||||
DoCastSelf(SPELL_DARK_SHELL);
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(8s, 23s, [this](TaskContext context)
|
||||
{
|
||||
if (!(context.GetRepeatCounter() % (MAX_VOID_BLAST + 1)))
|
||||
{
|
||||
VoidBlastCounter = 0;
|
||||
events.RescheduleEvent(EVENT_VOID_BLAST, urand(15000, 25000));
|
||||
context.Repeat(15s, 25s);
|
||||
}
|
||||
else
|
||||
{
|
||||
events.RescheduleEvent(EVENT_VOID_BLAST, 500);
|
||||
events.DelayEvents(EVENT_DARK_SHELL, 500);
|
||||
}
|
||||
break;
|
||||
case EVENT_DARK_SHELL:
|
||||
if (me->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
DoCastRandomTarget(SPELL_VOID_BLAST);
|
||||
context.Repeat(500ms);
|
||||
context.DelayGroup(GROUP_VOID_BLAST, 500ms);
|
||||
}
|
||||
});
|
||||
|
||||
Talk(EMOTE_DARK_SHELL);
|
||||
DoCast(me, SPELL_DARK_SHELL);
|
||||
events.RescheduleEvent(EVENT_DARK_SHELL, 20000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
BossAI::JustEngagedWith(who);
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 VoidBlastCounter;
|
||||
};
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_pandemonius()
|
||||
{
|
||||
new boss_pandemonius();
|
||||
RegisterManaTombsCreatureAI(boss_pandemonius);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,14 @@ struct boss_talon_king_ikiss : public BossAI
|
||||
context.Repeat(7s, 12s);
|
||||
}).Schedule(8s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_POLYMORPH);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_POLYMORPH);
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* target) -> bool
|
||||
{
|
||||
return target && !target->IsImmunedToSpell(spellInfo);
|
||||
}))
|
||||
{
|
||||
DoCast(target, SPELL_POLYMORPH);
|
||||
}
|
||||
context.Repeat(15s, 17500ms);
|
||||
});
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ struct boss_grand_warlock_nethekurse : public BossAI
|
||||
|
||||
if (!_canAggro)
|
||||
{
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetImmuneToAll(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,11 +235,13 @@ struct boss_grand_warlock_nethekurse : public BossAI
|
||||
me->SetInCombatWithZone();
|
||||
return;
|
||||
}
|
||||
else if (action == ACTION_START_INTRO)
|
||||
else if (action == ACTION_START_INTRO && !_introStarted)
|
||||
{
|
||||
// Hack: Prevent from pulling from behind door
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetImmuneToAll(false);
|
||||
_canAggro = true;
|
||||
// Bit of a hack to make sure it can't be started with the areatrigger AND the door opening
|
||||
_introStarted = true;
|
||||
|
||||
std::list<Creature*> creatureList;
|
||||
GetCreatureListWithEntryInGrid(creatureList, me, NPC_PEON, 60.0f);
|
||||
@@ -247,7 +249,7 @@ struct boss_grand_warlock_nethekurse : public BossAI
|
||||
{
|
||||
if (creature)
|
||||
{
|
||||
creature->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
creature->SetImmuneToAll(false);
|
||||
}
|
||||
}
|
||||
IntroRP();
|
||||
@@ -258,6 +260,21 @@ struct boss_grand_warlock_nethekurse : public BossAI
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
|
||||
// this should never be called if the action to start intro has been called
|
||||
if (!_introStarted)
|
||||
{
|
||||
// find the door that is nearest to the entrance
|
||||
if (GameObject* nethekursedoor = GetClosestGameObjectWithEntry(me, GO_GRAND_WARLOCK_CHAMBER_DOOR_1, 100.0f))
|
||||
{
|
||||
// check if door is openened
|
||||
//this should only happen before the intro, if the door is picked by someone
|
||||
if(nethekursedoor->GetGoState() == 0)
|
||||
{
|
||||
DoAction(ACTION_START_INTRO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
@@ -272,6 +289,7 @@ private:
|
||||
uint8 PeonEngagedCount = 0;
|
||||
uint8 PeonKilledCount = 0;
|
||||
bool _canAggro = false;
|
||||
bool _introStarted = false;
|
||||
};
|
||||
|
||||
class spell_tsh_shadow_bolt : public SpellScript
|
||||
|
||||
@@ -54,6 +54,24 @@ struct boss_nethermancer_sepethrea : public BossAI
|
||||
});
|
||||
}
|
||||
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
{
|
||||
if (me->GetThreatMgr().GetThreatListSize() > 1)
|
||||
{
|
||||
ThreatContainer::StorageType::const_iterator lastRef = me->GetThreatMgr().GetOnlineContainer().GetThreatList().end();
|
||||
--lastRef;
|
||||
if (Unit* lastTarget = (*lastRef)->getTarget())
|
||||
{
|
||||
if (lastTarget != target)
|
||||
{
|
||||
return !target->HasAura(SPELL_DRAGONS_BREATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
|
||||
@@ -500,6 +500,31 @@ class spell_dru_glyph_of_starfire : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 34246 - Idol of the Emerald Queen
|
||||
// 60779 - Idol of Lush Moss
|
||||
class spell_dru_idol_lifebloom : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_dru_idol_lifebloom);
|
||||
|
||||
void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod)
|
||||
{
|
||||
if (!spellMod)
|
||||
{
|
||||
spellMod = new SpellModifier(GetAura());
|
||||
spellMod->op = SPELLMOD_DOT;
|
||||
spellMod->type = SPELLMOD_FLAT;
|
||||
spellMod->spellId = GetId();
|
||||
spellMod->mask = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].SpellClassMask;
|
||||
}
|
||||
spellMod->value = aurEff->GetAmount() / 7;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoEffectCalcSpellMod += AuraEffectCalcSpellModFn(spell_dru_idol_lifebloom::HandleEffectCalcSpellMod, EFFECT_0, SPELL_AURA_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
// 29166 - Innervate
|
||||
class spell_dru_innervate : public AuraScript
|
||||
{
|
||||
@@ -1158,6 +1183,7 @@ void AddSC_druid_spell_scripts()
|
||||
RegisterSpellScript(spell_dru_dash);
|
||||
RegisterSpellScript(spell_dru_enrage);
|
||||
RegisterSpellScript(spell_dru_glyph_of_starfire);
|
||||
RegisterSpellScript(spell_dru_idol_lifebloom);
|
||||
RegisterSpellScript(spell_dru_innervate);
|
||||
RegisterSpellScript(spell_dru_lifebloom);
|
||||
RegisterSpellScript(spell_dru_living_seed);
|
||||
|
||||
@@ -990,7 +990,7 @@ public:
|
||||
Reset();
|
||||
}
|
||||
|
||||
void PatientSaved(Creature* /*soldier*/, Player* player, Location* point)
|
||||
void PatientSaved(Creature* savedPatient, Player* player, Location* point)
|
||||
{
|
||||
if (player && PlayerGUID == player->GetGUID())
|
||||
{
|
||||
@@ -1004,8 +1004,9 @@ public:
|
||||
{
|
||||
for (ObjectGuid const& guid : Patients)
|
||||
{
|
||||
if (Creature* patient = ObjectAccessor::GetCreature(*me, guid))
|
||||
patient->setDeathState(JUST_DIED);
|
||||
if (guid != savedPatient->GetGUID()) // Don't kill the last guy we just saved
|
||||
if (Creature* patient = ObjectAccessor::GetCreature(*me, guid))
|
||||
patient->setDeathState(JUST_DIED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1069,6 +1070,9 @@ public:
|
||||
//no regen health
|
||||
me->SetUnitFlag(UNIT_FLAG_IN_COMBAT);
|
||||
|
||||
//prevent using normal bandages
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANDAGE, true);
|
||||
|
||||
//to make them lay with face down
|
||||
me->SetUInt32Value(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_DEAD);
|
||||
|
||||
@@ -1078,18 +1082,26 @@ public:
|
||||
{
|
||||
//lower max health
|
||||
case 12923:
|
||||
case 12938: //Injured Soldier
|
||||
me->SetHealth(me->CountPctFromMaxHealth(75));
|
||||
case 12938: //Injured Soldier, 65 seconds to die
|
||||
me->SetHealth(me->CountPctFromMaxHealth(65));
|
||||
break;
|
||||
case 12924:
|
||||
case 12936: //Badly injured Soldier
|
||||
me->SetHealth(me->CountPctFromMaxHealth(50));
|
||||
case 12936: //Badly injured Soldier, 35 seconds to die
|
||||
me->SetHealth(me->CountPctFromMaxHealth(35));
|
||||
break;
|
||||
case 12925:
|
||||
case 12937: //Critically injured Soldier
|
||||
case 12937: //Critically injured Soldier, 25 seconds to die
|
||||
me->SetHealth(me->CountPctFromMaxHealth(25));
|
||||
break;
|
||||
}
|
||||
|
||||
// Schedule health reduction every 1 second
|
||||
_scheduler.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
// Reduction of 1% per second, matching WotLK Classic timing
|
||||
me->ModifyHealth(me->CountPctFromMaxHealth(1) * -1);
|
||||
context.Repeat(1s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override { }
|
||||
@@ -1134,13 +1146,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//lower HP on every world tick makes it a useful counter, not officlone though
|
||||
if (me->IsAlive() && me->GetHealth() > 6)
|
||||
me->ModifyHealth(-5);
|
||||
|
||||
if (me->IsAlive() && me->GetHealth() <= 6)
|
||||
_scheduler.Update(diff);
|
||||
|
||||
if (me->IsAlive() && me->GetHealth() < me->CountPctFromMaxHealth(1))
|
||||
{
|
||||
me->RemoveUnitFlag(UNIT_FLAG_IN_COMBAT);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
@@ -1152,6 +1163,10 @@ public:
|
||||
CAST_AI(npc_doctor::npc_doctorAI, doctor->AI())->PatientDied(Coord);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -1162,7 +1177,7 @@ public:
|
||||
|
||||
void npc_doctor::npc_doctorAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (Event && SummonPatientCount >= 20)
|
||||
if (Event && SummonPatientCount >= 24) // Need to keep the event going long enough to save the last few patients
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
@@ -1170,7 +1185,7 @@ void npc_doctor::npc_doctorAI::UpdateAI(uint32 diff)
|
||||
|
||||
if (Event)
|
||||
{
|
||||
if (SummonPatientTimer <= diff)
|
||||
if (SummonPatientTimer <= diff || SummonPatientCount < 6) // Starts with 6 beds filled for both factions
|
||||
{
|
||||
if (Coordinates.empty())
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user