Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-06-27 09:06:46 -06:00
committed by GitHub
29 changed files with 459 additions and 129 deletions

View File

@@ -982,7 +982,7 @@ struct npc_drakonid_spawner : public ScriptedAI
{
if (Creature* construct = ObjectAccessor::GetCreature(*me, summonGuid))
{
construct->UpdateEntry(NPC_BONE_CONSTRUCT);
construct->UpdateEntry(NPC_BONE_CONSTRUCT, true);
construct->SetReactState(REACT_PASSIVE);
construct->SetStandState(UNIT_STAND_STATE_DEAD);
construct->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);

View File

@@ -105,7 +105,8 @@ public:
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
me->SetWalk(false);
me->GetMotionMaster()->MovePoint(0, PosMoveOnSpawn[0]);
me->SetHomePosition(PosMoveOnSpawn[0]);
me->GetMotionMaster()->MoveTargetedHome();
}
void JustDied(Unit* /*killer*/) override
@@ -131,31 +132,37 @@ public:
{
uint8 sideA = 0;
uint8 sideB = 0;
for (std::list<Creature*>::const_iterator itr = triggerList.begin(); itr != triggerList.end(); ++itr)
for (auto const& trigger : triggerList)
{
if (Creature* trigger = *itr)
if (trigger->GetPositionY() < -1625.0f)
{
if (trigger->GetPositionY() < -1625.0f)
{
_triggersSideAGUID[sideA] = trigger->GetGUID();
++sideA;
}
else
{
_triggersSideBGUID[sideB] = trigger->GetGUID();
++sideB;
}
_triggersSideAGUID[sideA] = trigger->GetGUID();
++sideA;
}
else
{
_triggersSideBGUID[sideB] = trigger->GetGUID();
++sideB;
}
}
}
}
void JustReachedHome() override
{
if (GameObject* object = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_GONG_OF_BETHEKK)))
object->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
me->DespawnOrUnsummon();
}
void EnterEvadeMode(EvadeReason why) override
{
BossAI::EnterEvadeMode(why);
if (GameObject* object = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_GONG_OF_BETHEKK)))
object->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
me->DespawnOrUnsummon(4000);
std::list<Creature*> panthers;
GetCreatureListWithEntryInGrid(panthers, me, NPC_ZULIAN_PROWLER, 200.f);
for (auto const& panther : panthers)
panther->DespawnOrUnsummon();
}
void SetData(uint32 id, uint32 /*value*/) override
@@ -221,33 +228,27 @@ public:
}
case EVENT_TRANSFORM:
{
DoCast(me, SPELL_PANTHER_TRANSFORM); // SPELL_AURA_TRANSFORM
DoCastSelf(SPELL_PANTHER_TRANSFORM); // SPELL_AURA_TRANSFORM
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(EQUIP_UNEQUIP));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(EQUIP_UNEQUIP));
/*
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->AttackStop();
DoResetThreat();
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
DoCast(me, SPELL_VANISH_VISUAL);
DoCast(me, SPELL_VANISH);
DoCastSelf(SPELL_VANISH_VISUAL);
DoCastSelf(SPELL_VANISH);
events.ScheduleEvent(EVENT_VANISH, 1000, 0, PHASE_ONE);
break;
}
case EVENT_VANISH:
DoCast(me, SPELL_SUPER_INVIS);
DoCastSelf(SPELL_SUPER_INVIS);
me->SetWalk(false);
me->GetMotionMaster()->MovePoint(0, frand(-11551.0f, -11508.0f), frand(-1638.0f, -1617.0f), me->GetPositionZ());
events.ScheduleEvent(EVENT_VANISH_2, 9000, 0, PHASE_ONE);
break;
case EVENT_VANISH_2:
DoCast(me, SPELL_VANISH);
DoCast(me, SPELL_SUPER_INVIS);
DoCastSelf(SPELL_VANISH);
DoCastSelf(SPELL_SUPER_INVIS);
events.ScheduleEvent(EVENT_VISIBLE, urand(7000, 10000), 0, PHASE_ONE);
break;
case EVENT_VISIBLE:
@@ -272,12 +273,6 @@ public:
DoCast(me, SPELL_VANISH_VISUAL);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
/*
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(4000, 7000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE);
@@ -322,11 +317,6 @@ enum ZulianProwlerEvents
EVENT_ATTACK = 1
};
/*Position const PosProwlerCenter[1] =
{
{ -11556.7f, -1631.344f, 41.2994f, 0.0f }
};*/
class npc_zulian_prowler : public CreatureScript
{
public:
@@ -361,7 +351,9 @@ public:
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
if (spell->Id == SPELL_MARK_OF_ARLOKK_TRIGGER) // Should only hit if line of sight
me->Attack(caster, true);
{
AttackStart(caster);
}
}
void JustDied(Unit* /*killer*/) override
@@ -390,7 +382,9 @@ public:
{
case EVENT_ATTACK:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0.0f, 100, false))
me->Attack(target, true);
{
AttackStart(target);
}
break;
default:
break;

View File

@@ -38,7 +38,8 @@ enum Events
EVENT_AVATAR = 1,
EVENT_GROUND_TREMOR = 2,
EVENT_START_PURSUIT = 3,
EVENT_ENTANGLING_ROOTS = 4
EVENT_STOP_PURSUIT = 4,
EVENT_ENTANGLING_ROOTS = 5
};
class boss_grilek : public CreatureScript // grilek
@@ -52,6 +53,12 @@ public:
{
}
void Reset() override
{
_pursuitTargetGUID.Clear();
BossAI::Reset();
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
@@ -75,10 +82,15 @@ public:
switch (eventId)
{
case EVENT_AVATAR:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
_pursuitTargetGUID = target->GetGUID();
}
DoCast(me, SPELL_AVATAR);
DoResetThreat();
me->SetReactState(REACT_PASSIVE);
DoResetThreat();
events.ScheduleEvent(EVENT_START_PURSUIT, 2s);
events.ScheduleEvent(EVENT_STOP_PURSUIT, 15s);
events.ScheduleEvent(EVENT_AVATAR, 45s, 50s);
break;
case EVENT_GROUND_TREMOR:
@@ -87,6 +99,17 @@ public:
break;
case EVENT_START_PURSUIT:
me->SetReactState(REACT_AGGRESSIVE);
if (Unit* pursuitTarget = ObjectAccessor::GetUnit(*me, _pursuitTargetGUID))
{
me->GetThreatMgr().addThreat(pursuitTarget, 1000000.f);
}
break;
case EVENT_STOP_PURSUIT:
if (Unit* pursuitTarget = ObjectAccessor::GetUnit(*me, _pursuitTargetGUID))
{
_pursuitTargetGUID.Clear();
me->GetThreatMgr().addThreat(pursuitTarget, -1000000.f);
}
break;
case EVENT_ENTANGLING_ROOTS:
DoCastVictim(SPELL_ENTANGLING_ROOTS);
@@ -99,6 +122,9 @@ public:
DoMeleeAttackIfReady();
}
private:
ObjectGuid _pursuitTargetGUID;
};
CreatureAI* GetAI(Creature* creature) const override

View File

@@ -25,22 +25,26 @@ Category: Zul'Gurub
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "zulgurub.h"
enum Says
{
SAY_AGGRO = 0,
SAY_FLEEING = 1,
SAY_MINION_DESTROY = 2,
SAY_PROTECT_ALTAR = 3
SAY_AGGRO = 0,
SAY_FLEEING = 1,
SAY_MINION_DESTROY = 2,
SAY_PROTECT_ALTAR = 3,
SAY_PROTECT_GURUBASHI_EMPIRE = 4
};
enum Spells
{
SPELL_BLOOD_SIPHON = 24322, // Buggy ?
SPELL_POISONOUS_BLOOD = 24321,
SPELL_BLOOD_SIPHON_HEAL = 24322,
SPELL_BLOOD_SIPHON_DMG = 24323,
SPELL_BLOOD_SIPHON = 24324,
SPELL_CORRUPTED_BLOOD = 24328,
SPELL_CAUSE_INSANITY = 24327,
SPELL_WILL_OF_HAKKAR = 24178,
SPELL_ENRAGE = 24318,
// The Aspects of all High Priests spells
SPELL_ASPECT_OF_JEKLIK = 24687,
@@ -55,14 +59,13 @@ enum Events
EVENT_BLOOD_SIPHON = 1,
EVENT_CORRUPTED_BLOOD = 2,
EVENT_CAUSE_INSANITY = 3,
EVENT_WILL_OF_HAKKAR = 4,
EVENT_ENRAGE = 5,
EVENT_ENRAGE = 4,
// The Aspects of all High Priests events
EVENT_ASPECT_OF_JEKLIK = 6,
EVENT_ASPECT_OF_VENOXIS = 7,
EVENT_ASPECT_OF_MARLI = 8,
EVENT_ASPECT_OF_THEKAL = 9,
EVENT_ASPECT_OF_ARLOKK = 10
EVENT_ASPECT_OF_JEKLIK = 5,
EVENT_ASPECT_OF_VENOXIS = 6,
EVENT_ASPECT_OF_MARLI = 7,
EVENT_ASPECT_OF_THEKAL = 8,
EVENT_ASPECT_OF_ARLOKK = 9
};
class boss_hakkar : public CreatureScript
@@ -74,6 +77,16 @@ public:
{
boss_hakkarAI(Creature* creature) : BossAI(creature, DATA_HAKKAR) { }
bool CheckInRoom() override
{
if (me->GetPositionZ() < 52.f || me->GetPositionZ() > 57.28f)
{
BossAI::EnterEvadeMode(EVADE_REASON_BOUNDARY);
return false;
}
return true;
}
void Reset() override
{
_Reset();
@@ -90,7 +103,6 @@ public:
events.ScheduleEvent(EVENT_BLOOD_SIPHON, 90000);
events.ScheduleEvent(EVENT_CORRUPTED_BLOOD, 25000);
events.ScheduleEvent(EVENT_CAUSE_INSANITY, 17000);
events.ScheduleEvent(EVENT_WILL_OF_HAKKAR, 17000);
events.ScheduleEvent(EVENT_ENRAGE, 600000);
if (instance->GetBossState(DATA_JEKLIK) != DONE)
events.ScheduleEvent(EVENT_ASPECT_OF_JEKLIK, 4000);
@@ -107,7 +119,7 @@ public:
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
if (!UpdateVictim() || !CheckInRoom())
return;
events.Update(diff);
@@ -120,7 +132,7 @@ public:
switch (eventId)
{
case EVENT_BLOOD_SIPHON:
DoCastVictim(SPELL_BLOOD_SIPHON, true);
DoCastAOE(SPELL_BLOOD_SIPHON, true);
events.ScheduleEvent(EVENT_BLOOD_SIPHON, 90000);
break;
case EVENT_CORRUPTED_BLOOD:
@@ -128,20 +140,15 @@ public:
events.ScheduleEvent(EVENT_CORRUPTED_BLOOD, urand(30000, 45000));
break;
case EVENT_CAUSE_INSANITY:
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0))
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 30.f, true))
{
DoCast(victim, SPELL_CAUSE_INSANITY, true);
DoCast(victim, SPELL_CAUSE_INSANITY);
}
events.ScheduleEvent(EVENT_CAUSE_INSANITY, urand(35000, 45000));
break;
case EVENT_WILL_OF_HAKKAR:
// Xinef: Skip Tank
DoCast(SelectTarget(SelectTargetMethod::Random, 1, 100, true), SPELL_WILL_OF_HAKKAR);
events.ScheduleEvent(EVENT_WILL_OF_HAKKAR, urand(25000, 35000));
break;
case EVENT_ENRAGE:
if (!me->HasAura(SPELL_ENRAGE))
DoCast(me, SPELL_ENRAGE);
DoCastSelf(SPELL_ENRAGE);
events.ScheduleEvent(EVENT_ENRAGE, 90000);
break;
case EVENT_ASPECT_OF_JEKLIK:
@@ -153,7 +160,11 @@ public:
events.ScheduleEvent(EVENT_ASPECT_OF_VENOXIS, 8000);
break;
case EVENT_ASPECT_OF_MARLI:
DoCastVictim(SPELL_ASPECT_OF_MARLI, true);
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 5.f, true))
{
DoCast(victim, SPELL_ASPECT_OF_MARLI, true);
me->GetThreatMgr().modifyThreatPercent(victim, -100.f);
}
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 10000);
break;
case EVENT_ASPECT_OF_THEKAL:
@@ -161,7 +172,11 @@ public:
events.ScheduleEvent(EVENT_ASPECT_OF_THEKAL, 15000);
break;
case EVENT_ASPECT_OF_ARLOKK:
DoCastVictim(SPELL_ASPECT_OF_ARLOKK, true);
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 5.f, true))
{
DoCast(victim, SPELL_ASPECT_OF_ARLOKK, true);
me->GetThreatMgr().modifyThreatPercent(victim, -100.f);
}
events.ScheduleEvent(EVENT_ASPECT_OF_ARLOKK, urand(10000, 15000));
break;
default:
@@ -195,6 +210,28 @@ public:
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
{
hakkar->setActive(true);
if (hakkar->GetAI())
{
hakkar->AI()->Talk(SAY_PROTECT_GURUBASHI_EMPIRE);
}
}
return false;
}
return false;
}
};
class at_zulgurub_bridge_speech : public OnlyOnceAreaTriggerScript
{
public:
at_zulgurub_bridge_speech() : OnlyOnceAreaTriggerScript("at_zulgurub_bridge_speech") {}
bool _OnTrigger(Player* player, const AreaTrigger* /*at*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
{
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
{
if (hakkar->GetAI())
{
hakkar->AI()->Talk(SAY_PROTECT_ALTAR);
@@ -228,9 +265,39 @@ public:
}
};
class spell_hakkar_blood_siphon : public SpellScript
{
PrepareSpellScript(spell_hakkar_blood_siphon);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_BLOOD_SIPHON_HEAL, SPELL_BLOOD_SIPHON_DMG });
}
void OnSpellHit()
{
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (!caster || !target)
return;
if (target->HasAura(SPELL_POISONOUS_BLOOD))
target->CastSpell(caster, SPELL_BLOOD_SIPHON_DMG, true);
else
target->CastSpell(caster, SPELL_BLOOD_SIPHON_HEAL, true);
}
void Register() override
{
OnHit += SpellHitFn(spell_hakkar_blood_siphon::OnSpellHit);
}
};
void AddSC_boss_hakkar()
{
new boss_hakkar();
new at_zulgurub_entrance_speech();
new at_zulgurub_bridge_speech();
new at_zulgurub_temple_speech();
RegisterSpellScript(spell_hakkar_blood_siphon);
}

View File

@@ -97,6 +97,13 @@ Position const SpawnBat[6] =
{ -12293.6220f, -1380.2640f, 144.8304f, 5.483f }
};
enum Misc
{
PATH_JEKLIK_INTRO = 145170
};
Position const homePosition = { -12291.9f, -1380.08f, 144.902f, 2.28638f };
struct boss_jeklik : public BossAI
{
boss_jeklik(Creature* creature) : BossAI(creature, DATA_JEKLIK) { }
@@ -106,7 +113,9 @@ struct boss_jeklik : public BossAI
DoCastSelf(SPELL_GREEN_CHANNELING);
me->SetHover(false);
me->SetDisableGravity(false);
me->SetReactState(REACT_PASSIVE);
_Reset();
SetCombatMovement(false);
}
void JustDied(Unit* /*killer*/) override
@@ -117,22 +126,31 @@ struct boss_jeklik : public BossAI
void EnterEvadeMode(EvadeReason why) override
{
const Position homePos = me->GetHomePosition();
me->NearTeleportTo(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), homePos.GetOrientation());
me->GetMotionMaster()->Clear();
me->SetHomePosition(homePosition);
me->NearTeleportTo(homePosition.GetPositionX(), homePosition.GetPositionY(), homePosition.GetPositionZ(), homePosition.GetOrientation());
BossAI::EnterEvadeMode(why);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
me->RemoveAurasDueToSpell(SPELL_GREEN_CHANNELING);
me->SetHover(true);
me->SetDisableGravity(true);
me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING);
DoCastSelf(SPELL_BAT_FORM);
events.SetPhase(PHASE_ONE);
DoCastSelf(SPELL_BAT_FORM, true);
me->GetMotionMaster()->MovePath(PATH_JEKLIK_INTRO, false);
}
void PathEndReached(uint32 /*pathId*/) override
{
me->SetHover(false);
me->SetDisableGravity(false);
_EnterCombat();
SetCombatMovement(true);
me->SetReactState(REACT_AGGRESSIVE);
events.SetPhase(PHASE_ONE);
events.ScheduleEvent(EVENT_CHARGE_JEKLIK, urand(10000, 20000), PHASE_ONE);
events.ScheduleEvent(EVENT_PIERCE_ARMOR, urand(5000, 15000), PHASE_ONE);
events.ScheduleEvent(EVENT_BLOOD_LEECH, urand(5000, 15000), PHASE_ONE);
@@ -146,8 +164,6 @@ struct boss_jeklik : public BossAI
if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(50))
{
me->RemoveAurasDueToSpell(SPELL_BAT_FORM);
me->SetHover(false);
me->SetDisableGravity(false);
DoResetThreat();
events.SetPhase(PHASE_TWO);
events.CancelEventGroup(PHASE_ONE);

View File

@@ -80,7 +80,8 @@ enum Misc
MODEL_OHGAN_MOUNT = 15271,
PATH_MANDOKIR = 492861,
POINT_MANDOKIR_END = 24,
CHAINED_SPIRIT_COUNT = 20
CHAINED_SPIRIT_COUNT = 20,
ACTION_CHARGE = 1
};
Position const PosSummonChainedSpirits[CHAINED_SPIRIT_COUNT] =
@@ -169,6 +170,7 @@ public:
me->Mount(MODEL_OHGAN_MOUNT);
reviveGUID.Clear();
_useExecute = false;
_chargeTarget.first.Clear();
}
void JustDied(Unit* /*killer*/) override
@@ -226,9 +228,44 @@ public:
}
}
void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
void DoAction(int32 action) override
{
reviveGUID = guid;
if (action == ACTION_START_REVIVE)
{
std::list<Creature*> creatures;
GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f);
if (creatures.empty())
return;
for (std::list<Creature*>::iterator itr = creatures.begin(); itr != creatures.end(); ++itr)
{
if (Creature* chainedSpirit = ObjectAccessor::GetCreature(*me, (*itr)->GetGUID()))
{
chainedSpirit->AI()->SetGUID(reviveGUID);
chainedSpirit->AI()->DoAction(ACTION_REVIVE);
reviveGUID.Clear();
}
}
}
}
void SetGUID(ObjectGuid const guid, int32 type) override
{
if (type == ACTION_CHARGE)
{
if (_chargeTarget.first == guid && _chargeTarget.second > 0.f)
{
if (Unit* target = ObjectAccessor::GetUnit(*me, _chargeTarget.first))
{
me->RemoveAurasDueToSpell(SPELL_WHIRLWIND);
DoCast(target, SPELL_WATCH_CHARGE, true);
}
}
}
else
{
reviveGUID = guid;
}
}
void MovementInform(uint32 type, uint32 id) override
@@ -244,6 +281,18 @@ public:
}
}
void CalculateThreat(Unit* hatedUnit, float& threat, SpellInfo const* threatSpell) override
{
if (_chargeTarget.first == hatedUnit->GetGUID())
{
// Do not count DOTs/HOTs
if (!threatSpell || !threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT))
{
_chargeTarget.second += threat;
}
}
}
void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/) override
{
if (doneTo && doneTo == me->GetVictim())
@@ -264,6 +313,43 @@ public:
}
}
void DoMeleeAttackIfReady(bool ignoreCasting)
{
if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
Unit* victim = me->GetVictim();
if (!victim || !victim->IsInWorld())
return;
if (!me->IsWithinMeleeRange(victim))
return;
//Make sure our attack is ready and we aren't currently casting before checking distance
if (me->isAttackReady())
{
// xinef: prevent base and off attack in same time, delay attack at 0.2 sec
if (me->haveOffhandWeapon())
if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
me->AttackerStateUpdate(victim, BASE_ATTACK, false, ignoreCasting);
me->resetAttackTimer();
}
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
{
// xinef: delay main hand attack if both will hit at the same time (players code)
if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
me->setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY);
me->AttackerStateUpdate(victim, OFF_ATTACK, false, ignoreCasting);
me->resetAttackTimer(OFF_ATTACK);
}
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
@@ -299,7 +385,14 @@ public:
}
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING))
{
if (me->GetCurrentSpellCastTime(SPELL_WATCH) >= 0)
{
DoMeleeAttackIfReady(true);
}
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
@@ -339,6 +432,7 @@ public:
{
DoCast(player, SPELL_WATCH);
Talk(SAY_WATCH, player);
_chargeTarget = std::make_pair(player->GetGUID(), 0.f);
}
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
break;
@@ -393,13 +487,14 @@ public:
}
}
DoMeleeAttackIfReady();
DoMeleeAttackIfReady(false);
}
private:
uint8 killCount;
ObjectGuid reviveGUID;
bool _useExecute;
std::pair<ObjectGuid, float> _chargeTarget;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -614,13 +709,16 @@ public:
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* caster = GetCaster())
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
{
if (Unit* target = GetTarget())
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
if (Creature* caster = GetCaster()->ToCreature())
{
caster->CastSpell(target, SPELL_WATCH_CHARGE, true);
if (caster->IsAIEnabled)
{
caster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE);
}
}
}
}
@@ -656,6 +754,29 @@ class spell_mandokir_charge : public SpellScript
}
};
class spell_threatening_gaze_charge : public SpellScript
{
PrepareSpellScript(spell_threatening_gaze_charge)
void PreventLaunchHit(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
}
void LaunchHit(SpellEffIndex effIndex)
{
if (Unit* caster = GetCaster())
if (Unit* target = GetHitUnit())
caster->CastSpell(target, GetSpellInfo()->Effects[effIndex].TriggerSpell, true);
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_threatening_gaze_charge::PreventLaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
OnEffectHitTarget += SpellEffectFn(spell_threatening_gaze_charge::LaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
}
};
void AddSC_boss_mandokir()
{
new boss_mandokir();
@@ -664,4 +785,5 @@ void AddSC_boss_mandokir()
RegisterZulGurubCreatureAI(npc_vilebranch_speaker);
new spell_threatening_gaze();
RegisterSpellScript(spell_mandokir_charge);
RegisterSpellScript(spell_threatening_gaze_charge);
}

View File

@@ -212,9 +212,15 @@ public:
DoCast(target, SPELL_THOUSAND_BLADES, false);
}
_thousandBladesTargets.erase(itr);
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 500ms);
if (_thousandBladesTargets.erase(itr) != _thousandBladesTargets.end())
{
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 500ms);
}
else
{
_thousandBladesCount = urand(2, 5);
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 15s, 22s);
}
}
else
{

View File

@@ -15,12 +15,18 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AreaBoundary.h"
#include "CreatureAIImpl.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "obsidian_sanctum.h"
BossBoundaryData const boundaries =
{
{ DATA_SARTHARION, new RectangleBoundary(3218.86f, 3275.69f, 484.68f, 572.4f) }
};
class instance_obsidian_sanctum : public InstanceMapScript
{
public:
@@ -36,6 +42,7 @@ public:
instance_obsidian_sanctum_InstanceMapScript(Map* pMap) : InstanceScript(pMap), portalCount(0)
{
SetBossNumber(MAX_ENCOUNTERS);
LoadBossBoundaries(boundaries);
}
bool IsEncounterInProgress() const override