mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-18 11:25:42 +00:00
Merge branch 'master' into Playerbot
This commit is contained in:
@@ -264,7 +264,7 @@ void FollowerAI::MovementInform(uint32 motionType, uint32 pointId)
|
||||
}
|
||||
}
|
||||
|
||||
void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, const Quest* quest)
|
||||
void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, const Quest* quest, bool inheritWalkState, bool inheritSpeed)
|
||||
{
|
||||
if (me->GetVictim())
|
||||
{
|
||||
@@ -297,7 +297,7 @@ void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, const Qu
|
||||
|
||||
AddFollowState(STATE_FOLLOW_INPROGRESS);
|
||||
|
||||
me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_ACTIVE, inheritWalkState, inheritSpeed);
|
||||
|
||||
LOG_DEBUG("scripts.ai", "FollowerAI start follow {} ({})", player->GetName(), m_uiLeaderGUID.ToString());
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
void UpdateAI(uint32) override; //the "internal" update, calls UpdateFollowerAI()
|
||||
virtual void UpdateFollowerAI(uint32); //used when it's needed to add code in update (abilities, scripted events, etc)
|
||||
|
||||
void StartFollow(Player* player, uint32 factionForFollower = 0, const Quest* quest = nullptr);
|
||||
void StartFollow(Player* player, uint32 factionForFollower = 0, const Quest* quest = nullptr, bool inheritWalkState = true, bool inheritSpeed = true);
|
||||
|
||||
void SetFollowPaused(bool bPaused); //if special event require follow mode to hold/resume during the follow
|
||||
void SetFollowComplete(bool bWithEndEvent = false);
|
||||
|
||||
@@ -277,7 +277,7 @@ void MotionMaster::MoveTargetedHome(bool walk /*= false*/)
|
||||
if (target)
|
||||
{
|
||||
LOG_DEBUG("movement.motionmaster", "Following {} ({})", target->IsPlayer() ? "player" : "creature", target->GetGUID().ToString());
|
||||
Mutate(new FollowMovementGenerator<Creature>(target, PET_FOLLOW_DIST, _owner->GetFollowAngle(),true), MOTION_SLOT_ACTIVE);
|
||||
Mutate(new FollowMovementGenerator<Creature>(target, PET_FOLLOW_DIST, _owner->GetFollowAngle(), true, true), MOTION_SLOT_ACTIVE);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -406,7 +406,7 @@ void MotionMaster::MoveCircleTarget(Unit* target)
|
||||
/**
|
||||
* @brief The unit will follow this target. Doesn't work with UNIT_FLAG_DISABLE_MOVE
|
||||
*/
|
||||
void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlot slot, bool inheritWalkState)
|
||||
void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlot slot, bool inheritWalkState, bool inheritSpeed)
|
||||
{
|
||||
// ignore movement request if target not exist
|
||||
if (!target || target == _owner || _owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
|
||||
@@ -419,13 +419,13 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
|
||||
{
|
||||
LOG_DEBUG("movement.motionmaster", "Player ({}) follow to {} ({})",
|
||||
_owner->GetGUID().ToString(), target->IsPlayer() ? "player" : "creature", target->GetGUID().ToString());
|
||||
Mutate(new FollowMovementGenerator<Player>(target, dist, angle, inheritWalkState), slot);
|
||||
Mutate(new FollowMovementGenerator<Player>(target, dist, angle, inheritWalkState, inheritSpeed), slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("movement.motionmaster", "Creature ({}) follow to {} ({})",
|
||||
_owner->GetGUID().ToString(), target->IsPlayer() ? "player" : "creature", target->GetGUID().ToString());
|
||||
Mutate(new FollowMovementGenerator<Creature>(target, dist, angle, inheritWalkState), slot);
|
||||
Mutate(new FollowMovementGenerator<Creature>(target, dist, angle, inheritWalkState, inheritSpeed), slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
void MoveIdle();
|
||||
void MoveTargetedHome(bool walk = false);
|
||||
void MoveRandom(float wanderDistance = 0.0f);
|
||||
void MoveFollow(Unit* target, float dist, float angle, MovementSlot slot = MOTION_SLOT_ACTIVE, bool inheritWalkState = true);
|
||||
void MoveFollow(Unit* target, float dist, float angle, MovementSlot slot = MOTION_SLOT_ACTIVE, bool inheritWalkState = true, bool inheritSpeed = true);
|
||||
void MoveChase(Unit* target, std::optional<ChaseRange> dist = {}, std::optional<ChaseAngle> angle = {});
|
||||
void MoveChase(Unit* target, float dist, float angle) { MoveChase(target, ChaseRange(dist), ChaseAngle(angle)); }
|
||||
void MoveChase(Unit* target, float dist) { MoveChase(target, ChaseRange(dist)); }
|
||||
|
||||
@@ -539,8 +539,9 @@ bool FollowMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
if (_inheritWalkState)
|
||||
init.SetWalk(target->IsWalking() || target->movespline->isWalking());
|
||||
|
||||
if (Optional<float> velocity = GetVelocity(owner, target, i_path->GetActualEndPosition(), owner->IsGuardian()))
|
||||
init.SetVelocity(*velocity);
|
||||
if (_inheritSpeed)
|
||||
if (Optional<float> velocity = GetVelocity(owner, target, i_path->GetActualEndPosition(), owner->IsGuardian()))
|
||||
init.SetVelocity(*velocity);
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
|
||||
@@ -75,8 +75,8 @@ template<class T>
|
||||
class FollowMovementGenerator : public MovementGeneratorMedium<T, FollowMovementGenerator<T>>, public TargetedMovementGeneratorBase
|
||||
{
|
||||
public:
|
||||
FollowMovementGenerator(Unit* target, float range, ChaseAngle angle, bool inheritWalkState)
|
||||
: TargetedMovementGeneratorBase(target), i_path(nullptr), i_recheckPredictedDistanceTimer(0), i_recheckPredictedDistance(false), _range(range), _angle(angle),_inheritWalkState(inheritWalkState) {}
|
||||
FollowMovementGenerator(Unit* target, float range, ChaseAngle angle, bool inheritWalkState, bool inheritSpeed)
|
||||
: TargetedMovementGeneratorBase(target), i_path(nullptr), i_recheckPredictedDistanceTimer(0), i_recheckPredictedDistance(false), _range(range), _angle(angle),_inheritWalkState(inheritWalkState), _inheritSpeed(inheritSpeed) {}
|
||||
~FollowMovementGenerator() { }
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; }
|
||||
@@ -108,6 +108,7 @@ private:
|
||||
float _range;
|
||||
ChaseAngle _angle;
|
||||
bool _inheritWalkState;
|
||||
bool _inheritSpeed;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1431,7 +1431,16 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
|
||||
float destx = pos.GetPositionX() + distance * cos(pos.GetOrientation());
|
||||
float desty = pos.GetPositionY() + distance * sin(pos.GetOrientation());
|
||||
|
||||
float ground = map->GetHeight(phasemask, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
|
||||
// Added GROUND_HEIGHT_TOLERANCE to account for cases where, during a jump,
|
||||
// the Z position may be slightly below the vmap ground level.
|
||||
// Without this tolerance, a ray trace might incorrectly attempt to find ground
|
||||
// beneath the actual surface.
|
||||
//
|
||||
// Example:
|
||||
// actual vmap ground: -56.342392
|
||||
// Z position: -56.347195
|
||||
float searchGroundZPos = pos.GetPositionZ()+GROUND_HEIGHT_TOLERANCE;
|
||||
float ground = map->GetHeight(phasemask, pos.GetPositionX(), pos.GetPositionY(), searchGroundZPos);
|
||||
|
||||
bool isCasterInWater = m_caster->IsInWater();
|
||||
if (!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) || (pos.GetPositionZ() - ground < distance))
|
||||
|
||||
@@ -106,20 +106,29 @@ const Position LandingPos = { 1476.77f, 665.094f, 20.6423f };
|
||||
class CorruptTriggers : public BasicEvent
|
||||
{
|
||||
public:
|
||||
CorruptTriggers(Unit* caster) : _caster(caster) { }
|
||||
CorruptTriggers(Unit* caster, uint8 currentLane) : _caster(caster), _currentLane(currentLane) { }
|
||||
|
||||
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
|
||||
{
|
||||
std::list<Creature*> creatureList;
|
||||
_caster->GetCreaturesWithEntryInRange(creatureList, 70.0f, NPC_FOG_TRIGGER);
|
||||
for (auto const& creature : creatureList)
|
||||
{
|
||||
if (_caster->GetExactDist2d(creature) <= 11.0f)
|
||||
{
|
||||
creature->CastSpell(creature, SPELL_FOG_OF_CORRUPTION, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_currentLane && creature->GetPositionX() > 1510.0f)
|
||||
creature->CastSpell(creature, SPELL_FOG_OF_CORRUPTION, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Unit* _caster;
|
||||
uint8 _currentLane;
|
||||
};
|
||||
|
||||
struct boss_felmyst : public BossAI
|
||||
@@ -283,20 +292,20 @@ struct boss_felmyst : public BossAI
|
||||
me->GetMotionMaster()->MovePoint(POINT_LANE, RightSideLanes[_currentLane], false);
|
||||
else
|
||||
me->GetMotionMaster()->MovePoint(POINT_LANE, LeftSideLanes[_currentLane], false);
|
||||
}, 2s);
|
||||
}, 5s);
|
||||
break;
|
||||
case POINT_LANE:
|
||||
Talk(EMOTE_BREATH);
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(0));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(500));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(1000));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(1500));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(2000));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(2500));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(3000));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(3500));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(4000));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(0));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(500));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(1000));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(1500));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(2000));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(2500));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(3000));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(3500));
|
||||
me->m_Events.AddEvent(new CorruptTriggers(me, _currentLane), me->m_Events.CalculateTime(4000));
|
||||
}, 5s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
@@ -360,57 +369,63 @@ struct boss_felmyst : public BossAI
|
||||
|
||||
struct npc_demonic_vapor : public NullCreatureAI
|
||||
{
|
||||
npc_demonic_vapor(Creature* creature) : NullCreatureAI(creature) { }
|
||||
npc_demonic_vapor(Creature* creature) : NullCreatureAI(creature), _timer{1} { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_SPAWN_TRIGGER, true);
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_PERIODIC, true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
void IsSummonedBy(WorldObject* summoner) override
|
||||
{
|
||||
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
|
||||
if (!summoner || !summoner->ToUnit())
|
||||
return;
|
||||
|
||||
me->m_Events.AddEventAtOffset([this, summoner] {
|
||||
me->GetMotionMaster()->MoveFollow(summoner->ToUnit(), 0.0f, 0.0f, MOTION_SLOT_CONTROLLED);
|
||||
}, 2s);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (_timer)
|
||||
{
|
||||
Map::PlayerList const& players = me->GetMap()->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
if (me->GetDistance2d(itr->GetSource()) < 20.0f && itr->GetSource()->IsAlive())
|
||||
{
|
||||
me->GetMotionMaster()->MoveFollow(itr->GetSource(), 0.0f, 0.0f, MOTION_SLOT_CONTROLLED);
|
||||
break;
|
||||
}
|
||||
_timer += diff;
|
||||
if (_timer >= 2000)
|
||||
{
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_PERIODIC, true);
|
||||
_timer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
uint32 _timer;
|
||||
};
|
||||
|
||||
struct npc_demonic_vapor_trail : public NullCreatureAI
|
||||
{
|
||||
npc_demonic_vapor_trail(Creature* creature) : NullCreatureAI(creature)
|
||||
{
|
||||
timer = 1;
|
||||
}
|
||||
npc_demonic_vapor_trail(Creature* creature) : NullCreatureAI(creature), _timer{1} { }
|
||||
|
||||
uint32 timer;
|
||||
void Reset() override
|
||||
{
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_TRAIL_PERIODIC, true);
|
||||
me->DespawnOrUnsummon(20000);
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit*, SpellInfo const* spellInfo) override
|
||||
void SpellHitTarget(Unit* /*unit*/, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_DEMONIC_VAPOR)
|
||||
me->CastSpell(me, SPELL_SUMMON_BLAZING_DEAD, true);
|
||||
if (spellInfo->Id == SPELL_DEMONIC_VAPOR && !_timer)
|
||||
_timer = 1;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (timer)
|
||||
if (_timer)
|
||||
{
|
||||
timer += diff;
|
||||
if (timer >= 6000)
|
||||
_timer += diff;
|
||||
if (_timer >= 5000)
|
||||
{
|
||||
timer = 0;
|
||||
_timer = 0;
|
||||
me->CastSpell(me, SPELL_SUMMON_BLAZING_DEAD, true);
|
||||
}
|
||||
}
|
||||
@@ -421,6 +436,8 @@ struct npc_demonic_vapor_trail : public NullCreatureAI
|
||||
summon->SetInCombatWithZone();
|
||||
summon->AI()->AttackStart(summon->AI()->SelectTarget(SelectTargetMethod::Random, 0, 100.0f));
|
||||
}
|
||||
private:
|
||||
uint32 _timer;
|
||||
};
|
||||
|
||||
class spell_felmyst_fog_of_corruption : public SpellScript
|
||||
|
||||
@@ -47,32 +47,36 @@ enum Yells
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SPECTRAL_EXHAUSTION = 44867,
|
||||
SPELL_SPECTRAL_BLAST = 44869,
|
||||
SPELL_SPECTRAL_BLAST_PORTAL = 44866,
|
||||
SPELL_SPECTRAL_BLAST_AA = 46648,
|
||||
SPELL_TELEPORT_SPECTRAL = 46019,
|
||||
SPELL_SPECTRAL_EXHAUSTION = 44867,
|
||||
SPELL_SPECTRAL_BLAST = 44869,
|
||||
SPELL_SPECTRAL_BLAST_PORTAL = 44866,
|
||||
SPELL_SPECTRAL_BLAST_AA = 46648,
|
||||
SPELL_TELEPORT_SPECTRAL = 46019,
|
||||
|
||||
SPELL_TELEPORT_NORMAL_REALM = 46020,
|
||||
SPELL_SPECTRAL_REALM = 46021,
|
||||
SPELL_SPECTRAL_INVISIBILITY = 44801,
|
||||
SPELL_DEMONIC_VISUAL = 44800,
|
||||
SPELL_TELEPORT_NORMAL_REALM = 46020,
|
||||
SPELL_SPECTRAL_REALM = 46021,
|
||||
SPELL_SPECTRAL_INVISIBILITY = 44801,
|
||||
SPELL_DEMONIC_VISUAL = 44800,
|
||||
|
||||
SPELL_ARCANE_BUFFET = 45018,
|
||||
SPELL_FROST_BREATH = 44799,
|
||||
SPELL_TAIL_LASH = 45122,
|
||||
SPELL_ARCANE_BUFFET = 45018,
|
||||
SPELL_FROST_BREATH = 44799,
|
||||
SPELL_TAIL_LASH = 45122,
|
||||
|
||||
SPELL_BANISH = 44836,
|
||||
SPELL_TRANSFORM_KALEC = 44670,
|
||||
SPELL_CRAZED_RAGE = 44807,
|
||||
SPELL_BANISH = 44836,
|
||||
SPELL_TRANSFORM_KALEC = 44670,
|
||||
SPELL_CRAZED_RAGE = 44807,
|
||||
|
||||
SPELL_CORRUPTION_STRIKE = 45029,
|
||||
SPELL_CURSE_OF_BOUNDLESS_AGONY = 45032,
|
||||
SPELL_CURSE_OF_BOUNDLESS_AGONY_PLR = 45034,
|
||||
SPELL_SHADOW_BOLT = 45031,
|
||||
SPELL_CORRUPTION_STRIKE = 45029,
|
||||
SPELL_CURSE_OF_BOUNDLESS_AGONY = 45032,
|
||||
SPELL_CURSE_OF_BOUNDLESS_AGONY_PLR = 45034,
|
||||
SPELL_CURSE_OF_BOUNDLESS_AGONY_REMOVE = 45050,
|
||||
SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_1 = 45083,
|
||||
SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_2 = 45085,
|
||||
SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_3 = 45084,
|
||||
SPELL_SHADOW_BOLT = 45031,
|
||||
|
||||
SPELL_HEROIC_STRIKE = 45026,
|
||||
SPELL_REVITALIZE = 45027
|
||||
SPELL_HEROIC_STRIKE = 45026,
|
||||
SPELL_REVITALIZE = 45027
|
||||
};
|
||||
|
||||
enum SWPActions
|
||||
@@ -244,7 +248,7 @@ struct boss_kalecgos : public BossAI
|
||||
DoCastAOE(SPELL_SPECTRAL_BLAST);
|
||||
}, 20s, 30s);
|
||||
|
||||
scheduler.Schedule(16s, [this](TaskContext)
|
||||
scheduler.Schedule(9s, [this](TaskContext)
|
||||
{
|
||||
if (Creature* kalec = me->SummonCreature(NPC_KALEC, 1702.21f, 931.7f, -74.56f, 5.07f, TEMPSUMMON_MANUAL_DESPAWN))
|
||||
kalec->CastSpell(kalec, SPELL_SPECTRAL_INVISIBILITY, true);
|
||||
@@ -388,6 +392,7 @@ struct boss_sathrovarr : public ScriptedAI
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
DoCastSelf(SPELL_CURSE_OF_BOUNDLESS_AGONY_REMOVE, true);
|
||||
Talk(SAY_SATH_DEATH);
|
||||
}
|
||||
|
||||
@@ -464,10 +469,10 @@ class spell_kalecgos_curse_of_boundless_agony_aura : public AuraScript
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_CURSE_OF_BOUNDLESS_AGONY_PLR });
|
||||
return ValidateSpellInfo({ SPELL_CURSE_OF_BOUNDLESS_AGONY_PLR, SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_1, SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_2, SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_3 });
|
||||
}
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (InstanceScript* instance = GetUnitOwner()->GetInstanceScript())
|
||||
if (instance->IsEncounterInProgress())
|
||||
@@ -476,8 +481,18 @@ class spell_kalecgos_curse_of_boundless_agony_aura : public AuraScript
|
||||
|
||||
void OnPeriodic(AuraEffect const* aurEff)
|
||||
{
|
||||
if (aurEff->GetTickNumber() > 1 && aurEff->GetTickNumber() % 5 == 1)
|
||||
uint32 tickNumber = aurEff->GetTickNumber();
|
||||
if (tickNumber > 1 && tickNumber % 5 == 1)
|
||||
GetAura()->GetEffect(aurEff->GetEffIndex())->SetAmount(aurEff->GetAmount() * 2);
|
||||
|
||||
uint32 spellId = 0;
|
||||
if (tickNumber <= 10)
|
||||
spellId = SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_1;
|
||||
else if (tickNumber <= 20)
|
||||
spellId = SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_2;
|
||||
else
|
||||
spellId = SPELL_CURSE_OF_BOUNDLESS_AGONY_DUMMY_3;
|
||||
GetTarget()->CastSpell(GetTarget(), spellId, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -184,7 +184,10 @@ struct npc_sunblade_scout : public ScriptedAI
|
||||
protectors.remove_if([](Creature* trigger) {return !trigger->HasAura(SPELL_COSMETIC_STUN_IMMUNE_PERMANENT);});
|
||||
protectors.sort(Acore::ObjectDistanceOrderPred(me));
|
||||
if (protectors.empty())
|
||||
{
|
||||
ScheduleCombat();
|
||||
return;
|
||||
}
|
||||
Creature* closestProtector = protectors.front();
|
||||
me->GetMotionMaster()->MoveFollow(closestProtector, 0.0f, 0.0f);
|
||||
_protectorGUID = closestProtector->GetGUID();
|
||||
|
||||
@@ -757,7 +757,10 @@ struct npc_amanishi_scout : public ScriptedAI
|
||||
triggers.remove_if([](Creature* trigger) {return !IsDrum(trigger);});
|
||||
triggers.sort(Acore::ObjectDistanceOrderPred(me));
|
||||
if (triggers.empty())
|
||||
{
|
||||
ScheduleCombat();
|
||||
return;
|
||||
}
|
||||
Creature* closestDrum = triggers.front();
|
||||
me->GetMotionMaster()->MoveFollow(closestDrum, 0.0f, 0.0f);
|
||||
_drumGUID = closestDrum->GetGUID();
|
||||
|
||||
@@ -33,7 +33,6 @@ enum Spells
|
||||
// INSANITY
|
||||
SPELL_INSANITY = 57496, //Dummy
|
||||
INSANITY_VISUAL = 57561,
|
||||
SPELL_INSANITY_TARGET = 57508,
|
||||
SPELL_CLONE_PLAYER = 57507, //casted on player during insanity
|
||||
SPELL_INSANITY_PHASING_1 = 57508,
|
||||
SPELL_INSANITY_PHASING_2 = 57509,
|
||||
@@ -362,15 +361,13 @@ class spell_herald_volzaj_insanity : public SpellScript
|
||||
{
|
||||
targets.remove_if([this](WorldObject* targetObj) -> bool
|
||||
{
|
||||
return !targetObj || !targetObj->IsPlayer() || !targetObj->ToPlayer()->IsInCombatWith(GetCaster()) ||
|
||||
return !targetObj || !targetObj->IsPlayer() || !GetCaster()->IsInCombatWith(targetObj->ToPlayer()) ||
|
||||
targetObj->GetDistance(GetCaster()) >= (MAX_VISIBILITY_DISTANCE * 2);
|
||||
});
|
||||
}
|
||||
|
||||
if (targets.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Start channel visual and set self as unnattackable
|
||||
caster->ToCreature()->AI()->Talk(SAY_INSANITY);
|
||||
@@ -387,16 +384,12 @@ class spell_herald_volzaj_insanity : public SpellScript
|
||||
{
|
||||
WorldObject* targetObj = *itr;
|
||||
if (!targetObj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Player* plrTarget = targetObj->ToPlayer();
|
||||
// This should never happen, spell has attribute SPELL_ATTR3_ONLY_TARGET_PLAYERS
|
||||
if (!plrTarget)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// phase mask
|
||||
plrTarget->CastSpell(plrTarget, InsanitySpells.at(insanityCounter), true);
|
||||
@@ -405,19 +398,17 @@ class spell_herald_volzaj_insanity : public SpellScript
|
||||
for (std::list<WorldObject*>::const_iterator itr2 = targets.begin(); itr2 != targets.end(); ++itr2)
|
||||
{
|
||||
// Should not make clone of current player target
|
||||
Player const* plrClone = *itr2 ? (*itr2)->ToPlayer() : nullptr;
|
||||
if (!plrClone || plrClone == plrTarget)
|
||||
{
|
||||
Player* plrClone = *itr2 ? (*itr2)->ToPlayer() : nullptr;
|
||||
if (!plrClone || plrClone == plrTarget || !plrClone->IsAlive())
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Unit* summon = caster->SummonCreature(NPC_TWISTED_VISAGE, plrClone->GetPosition(), TEMPSUMMON_CORPSE_DESPAWN, 0))
|
||||
{
|
||||
plrClone->CastSpell(summon, SPELL_CLONE_PLAYER, true);
|
||||
|
||||
summon->AddThreat(plrTarget, 0.0f);
|
||||
summon->SetInCombatWith(plrTarget);
|
||||
plrTarget->SetInCombatWith(summon);
|
||||
|
||||
plrTarget->CastSpell(summon, SPELL_CLONE_PLAYER, true);
|
||||
summon->SetPhaseMask(1 | (1 << (4 + insanityCounter)), true);
|
||||
summon->SetUInt32Value(UNIT_FIELD_MINDAMAGE, plrClone->GetUInt32Value(UNIT_FIELD_MINDAMAGE));
|
||||
summon->SetUInt32Value(UNIT_FIELD_MAXDAMAGE, plrClone->GetUInt32Value(UNIT_FIELD_MAXDAMAGE));
|
||||
|
||||
@@ -94,6 +94,8 @@ struct boss_magus_telestra : public BossAI
|
||||
|
||||
if (IsHeroic() && sGameEventMgr->IsActiveEvent(GAME_EVENT_WINTER_VEIL) && !me->HasAura(SPELL_WEAR_CHRISTMAS_HAT))
|
||||
me->AddAura(SPELL_WEAR_CHRISTMAS_HAT, me);
|
||||
|
||||
SetInvincibility(false);
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 data) const override
|
||||
@@ -184,6 +186,7 @@ struct boss_magus_telestra : public BossAI
|
||||
case EVENT_MAGUS_HEALTH2:
|
||||
if (me->HealthBelowPct(11))
|
||||
{
|
||||
SetInvincibility(true);
|
||||
me->CastSpell(me, SPELL_START_SUMMON_CLONES, false);
|
||||
events.ScheduleEvent(EVENT_MAGUS_RELOCATE, 3500ms);
|
||||
Talk(SAY_SPLIT);
|
||||
@@ -214,6 +217,7 @@ struct boss_magus_telestra : public BossAI
|
||||
me->CastSpell(me, SPELL_TELESTRA_BACK, true);
|
||||
me->RemoveAllAuras();
|
||||
Talk(SAY_MERGE);
|
||||
SetInvincibility(false);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -474,6 +474,92 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## Quest 11881: Load'er Up
|
||||
######*/
|
||||
|
||||
// NPC 25969: Jenny
|
||||
enum Jenny
|
||||
{
|
||||
EVENT_JENNY_START_FOLLOW = 1,
|
||||
EVENT_JENNY_MOVE_TO_FEZZIX = 2,
|
||||
EVENT_JENNY_DESPAWN = 3,
|
||||
SPELL_CRATES_CARRIED = 46340,
|
||||
SPELL_DROP_CRATE = 46342,
|
||||
SPELL_GIVE_JENNY_CREDIT = 46358,
|
||||
NPC_FEZZIX_GEARTWIST = 25849
|
||||
};
|
||||
|
||||
struct npc_jenny : public FollowerAI
|
||||
{
|
||||
npc_jenny(Creature* creature) : FollowerAI(creature)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->CastSpell(me, SPELL_CRATES_CARRIED);
|
||||
|
||||
// can't update follow here, call later
|
||||
_events.ScheduleEvent(EVENT_JENNY_START_FOLLOW, 1s);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
|
||||
{
|
||||
if (me->HasAura(SPELL_CRATES_CARRIED))
|
||||
me->CastSpell(me, SPELL_DROP_CRATE);
|
||||
else
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void UpdateFollowerAI(uint32 diff) override
|
||||
{
|
||||
_events.Update(diff);
|
||||
|
||||
if (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_JENNY_START_FOLLOW:
|
||||
// This NPC only moves at its fixed speed_run rate in the db
|
||||
// and does not inherit the speed of the target
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
if (Unit* summonerUnit = summon->GetSummonerUnit())
|
||||
if (Player* summoner = summonerUnit->ToPlayer())
|
||||
StartFollow(summoner, 0, nullptr, true, false);
|
||||
break;
|
||||
case EVENT_JENNY_MOVE_TO_FEZZIX:
|
||||
me->SetWalk(true);
|
||||
me->GetMotionMaster()->MovePoint(0, _fezzix);
|
||||
_events.ScheduleEvent(EVENT_JENNY_DESPAWN, 7s);
|
||||
break;
|
||||
case EVENT_JENNY_DESPAWN:
|
||||
me->DespawnOrUnsummon();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (who->GetEntry() == NPC_FEZZIX_GEARTWIST && me->IsWithinDistInMap(who, 15.0f))
|
||||
{
|
||||
if (TempSummon* s = me->ToTempSummon())
|
||||
if (Unit* u = s->GetSummonerUnit())
|
||||
if (Player* p = u->ToPlayer())
|
||||
me->CastSpell(p, SPELL_GIVE_JENNY_CREDIT);
|
||||
SetFollowComplete(true);
|
||||
_fezzix = who->GetPosition();
|
||||
_events.ScheduleEvent(EVENT_JENNY_MOVE_TO_FEZZIX, 1s);
|
||||
}
|
||||
}
|
||||
private:
|
||||
EventMap _events;
|
||||
Position _fezzix;
|
||||
};
|
||||
|
||||
/*######
|
||||
## Quest 11590: Abduction
|
||||
######*/
|
||||
@@ -2059,4 +2145,5 @@ void AddSC_borean_tundra()
|
||||
new npc_hidden_cultist();
|
||||
RegisterSpellScript(spell_q11719_bloodspore_ruination_45997);
|
||||
new npc_bloodmage_laurith();
|
||||
RegisterCreatureAI(npc_jenny);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "ScriptedGossip.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
// Ours
|
||||
@@ -240,6 +242,7 @@ enum overlordDrakuru
|
||||
SPELL_THROW_BRIGHT_CRYSTAL = 54087,
|
||||
SPELL_TELEPORT_EFFECT = 52096,
|
||||
SPELL_SCOURGE_DISGUISE = 51966,
|
||||
SPELL_SCOURGE_DISGUISE_INSTANT_CAST = 52192,
|
||||
SPELL_BLIGHT_FOG = 54104,
|
||||
SPELL_THROW_PORTAL_CRYSTAL = 54209,
|
||||
SPELL_ARTHAS_PORTAL = 51807,
|
||||
@@ -866,6 +869,51 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum ScourgeDisguiseInstability
|
||||
{
|
||||
SCOURGE_DISGUISE_FAILING_MESSAGE_1 = 28552, // Scourge Disguise Failing! Find a safe place!
|
||||
SCOURGE_DISGUISE_FAILING_MESSAGE_2 = 28758, // Scourge Disguise Failing! Run for cover!
|
||||
SCOURGE_DISGUISE_FAILING_MESSAGE_3 = 28759, // Scourge Disguise Failing! Hide quickly!
|
||||
};
|
||||
std::vector<uint32> const scourgeDisguiseTextIDs = { SCOURGE_DISGUISE_FAILING_MESSAGE_1, SCOURGE_DISGUISE_FAILING_MESSAGE_2, SCOURGE_DISGUISE_FAILING_MESSAGE_3 };
|
||||
|
||||
class spell_scourge_disguise_instability : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_scourge_disguise_instability);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_SCOURGE_DISGUISE_EXPIRING });
|
||||
}
|
||||
|
||||
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
SetDuration(urand(3 * MINUTE * IN_MILLISECONDS, 5 * MINUTE * IN_MILLISECONDS));
|
||||
}
|
||||
|
||||
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Player* player = caster->ToPlayer())
|
||||
{
|
||||
if (player->HasAnyAuras(SPELL_SCOURGE_DISGUISE, SPELL_SCOURGE_DISGUISE_INSTANT_CAST))
|
||||
{
|
||||
uint32 textId = Acore::Containers::SelectRandomContainerElement(scourgeDisguiseTextIDs);
|
||||
player->Unit::Whisper(textId, player, true);
|
||||
player->CastSpell(player, SPELL_SCOURGE_DISGUISE_EXPIRING, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectApply += AuraEffectApplyFn(spell_scourge_disguise_instability::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_scourge_disguise_instability::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_zuldrak()
|
||||
{
|
||||
// Ours
|
||||
@@ -880,4 +928,6 @@ void AddSC_zuldrak()
|
||||
new npc_crusade_recruit();
|
||||
new go_scourge_enclosure();
|
||||
new npc_storm_cloud();
|
||||
|
||||
RegisterSpellScript(spell_scourge_disguise_instability);
|
||||
}
|
||||
|
||||
@@ -899,6 +899,74 @@ class spell_warr_retaliation : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 29707 - Heroic Strike (Rank 10)
|
||||
// 30324 - Heroic Strike (Rank 11)
|
||||
// 47449 - Heroic Strike (Rank 12)
|
||||
// 47450 - Heroic Strike (Rank 13)
|
||||
enum DazeSpells
|
||||
{
|
||||
ICON_GENERIC_DAZE = 15,
|
||||
SPELL_GENERIC_AFTERMATH = 18118,
|
||||
};
|
||||
|
||||
class spell_warr_heroic_strike : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_warr_heroic_strike);
|
||||
|
||||
void HandleOnHit()
|
||||
{
|
||||
Unit* target = GetHitUnit();
|
||||
if (!target)
|
||||
return;
|
||||
std::list<AuraEffect*> AuraEffectList = target->GetAuraEffectsByType(SPELL_AURA_MOD_DECREASE_SPEED);
|
||||
bool bonusDamage = false;
|
||||
for (AuraEffect* eff : AuraEffectList)
|
||||
{
|
||||
const SpellInfo* spellInfo = eff->GetSpellInfo();
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
// Warrior Spells: Piercing Howl or Dazed (29703)
|
||||
if (spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && (spellInfo->SpellFamilyFlags[1] & (0x20 | 0x200000)))
|
||||
{
|
||||
bonusDamage = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Generic Daze: icon 15 with mechanic daze or snare
|
||||
if ((spellInfo->SpellIconID == ICON_GENERIC_DAZE)
|
||||
&& ((spellInfo->Mechanic == MECHANIC_DAZE || spellInfo->HasEffectMechanic(MECHANIC_DAZE))
|
||||
|| (spellInfo->Mechanic == MECHANIC_SNARE || spellInfo->HasEffectMechanic(MECHANIC_SNARE))
|
||||
)
|
||||
)
|
||||
{
|
||||
bonusDamage = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((spellInfo->Id == SPELL_GENERIC_AFTERMATH)
|
||||
|| (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->SpellFamilyFlags[1] & 0x40)) // Blast Wave
|
||||
|| (spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && (spellInfo->SpellFamilyFlags[2] & 0x4000)) // Avenger's Shield
|
||||
)
|
||||
{
|
||||
bonusDamage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bonusDamage)
|
||||
{
|
||||
int32 damage = GetHitDamage();
|
||||
AddPct(damage, 35); // "Causes ${0.35*$m1} additional damage against Dazed targets."
|
||||
SetHitDamage(damage);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnHit += SpellHitFn(spell_warr_heroic_strike::HandleOnHit);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_warrior_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_warr_mocking_blow);
|
||||
@@ -925,4 +993,5 @@ void AddSC_warrior_spell_scripts()
|
||||
RegisterSpellScript(spell_warr_vigilance);
|
||||
RegisterSpellScript(spell_warr_vigilance_trigger);
|
||||
RegisterSpellScript(spell_warr_t3_prot_8p_bonus);
|
||||
RegisterSpellScript(spell_warr_heroic_strike);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user