diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c207e3a9d73..3d2420870ea 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2847,17 +2847,10 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask) if (creature->GetCharmerGUID()) return NULL; - // not enemy - if (creature->IsHostileTo(this)) + // not unfriendly/hostile + if (creature->GetReactionTo(this) <= REP_UNFRIENDLY) return NULL; - // not unfriendly - if (FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(creature->getFaction())) - if (factionTemplate->faction) - if (FactionEntry const* faction = sFactionStore.LookupEntry(factionTemplate->faction)) - if (faction->reputationListID >= 0 && GetReputationMgr().GetRank(faction) <= REP_UNFRIENDLY) - return NULL; - // not too far if (!creature->IsWithinDistInMap(this, INTERACTION_DISTANCE)) return NULL; diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp index d3b0597e97d..2c9d88eac8a 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2015 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,8 +19,8 @@ #include "ScriptedCreature.h" #include "SpellScript.h" #include "SpellAuraEffects.h" -#include "nexus.h" #include "Player.h" +#include "nexus.h" enum Spells { @@ -31,15 +30,21 @@ enum Spells SPELL_CRYSTAL_CHAINS = 50997, SPELL_ENRAGE = 8599, SPELL_CRYSTALFIRE_BREATH = 48096, - H_SPELL_CRYSTALFIRE_BREATH = 57091, SPELL_CRYSTALIZE = 48179, SPELL_INTENSE_COLD = 48094, SPELL_INTENSE_COLD_TRIGGERED = 48095 }; +enum Events +{ + EVENT_CRYSTAL_FIRE_BREATH = 1, + EVENT_CRYSTAL_CHAINS_CRYSTALIZE, + EVENT_TAIL_SWEEP +}; + enum Yells { - //Yell + // Yell SAY_AGGRO = 0, SAY_SLAY = 1, SAY_ENRAGE = 2, @@ -51,163 +56,166 @@ enum Yells enum Misc { DATA_INTENSE_COLD = 1, - DATA_CONTAINMENT_SPHERES = 3, + DATA_CONTAINMENT_SPHERES = 3 }; class boss_keristrasza : public CreatureScript { -public: - boss_keristrasza() : CreatureScript("boss_keristrasza") { } + public: + boss_keristrasza() : CreatureScript("boss_keristrasza") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI(creature); - } - - struct boss_keristraszaAI : public ScriptedAI - { - boss_keristraszaAI(Creature* creature) : ScriptedAI(creature) + struct boss_keristraszaAI : public BossAI { - Initialize(); - instance = creature->GetInstanceScript(); - } - - void Initialize() - { - uiCrystalfireBreathTimer = 14 * IN_MILLISECONDS; - uiCrystalChainsCrystalizeTimer = DUNGEON_MODE(30 * IN_MILLISECONDS, 11 * IN_MILLISECONDS); - uiTailSweepTimer = 5 * IN_MILLISECONDS; - bEnrage = false; - - intenseCold = true; - } - - InstanceScript* instance; - - GuidList intenseColdList; - ObjectGuid auiContainmentSphereGUIDs[DATA_CONTAINMENT_SPHERES]; - uint32 uiCrystalfireBreathTimer; - uint32 uiCrystalChainsCrystalizeTimer; - uint32 uiTailSweepTimer; - bool intenseCold; - bool bEnrage; - - void Reset() override - { - Initialize(); - intenseColdList.clear(); - - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - - RemovePrison(CheckContainmentSpheres()); - - instance->SetBossState(DATA_KERISTRASZA, NOT_STARTED); - } - - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - DoCastAOE(SPELL_INTENSE_COLD); - - instance->SetBossState(DATA_KERISTRASZA, IN_PROGRESS); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - - instance->SetBossState(DATA_KERISTRASZA, DONE); - } - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - bool CheckContainmentSpheres(bool remove_prison = false) - { - auiContainmentSphereGUIDs[0] = instance->GetGuidData(ANOMALUS_CONTAINMET_SPHERE); - auiContainmentSphereGUIDs[1] = instance->GetGuidData(ORMOROKS_CONTAINMET_SPHERE); - auiContainmentSphereGUIDs[2] = instance->GetGuidData(TELESTRAS_CONTAINMET_SPHERE); - - GameObject* ContainmentSpheres[DATA_CONTAINMENT_SPHERES]; - - for (uint8 i = 0; i < DATA_CONTAINMENT_SPHERES; ++i) + boss_keristraszaAI(Creature* creature) : BossAI(creature, DATA_KERISTRASZA) { - ContainmentSpheres[i] = instance->instance->GetGameObject(auiContainmentSphereGUIDs[i]); - if (!ContainmentSpheres[i]) - return false; - if (ContainmentSpheres[i]->GetGoState() != GO_STATE_ACTIVE) - return false; - } - if (remove_prison) - RemovePrison(true); - return true; - } - - void RemovePrison(bool remove) - { - if (remove) - { - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if (me->HasAura(SPELL_FROZEN_PRISON)) - me->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON); - } - else - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoCast(me, SPELL_FROZEN_PRISON, false); - } - } - - void SetGUID(ObjectGuid guid, int32 id/* = 0 */) override - { - if (id == DATA_INTENSE_COLD) - intenseColdList.push_back(guid); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (!bEnrage && HealthBelowPct(25)) - { - Talk(SAY_ENRAGE); - Talk(SAY_FRENZY); - DoCast(me, SPELL_ENRAGE); - bEnrage = true; + Initialize(); } - if (uiCrystalfireBreathTimer <= diff) + void Initialize() { - DoCastVictim(SPELL_CRYSTALFIRE_BREATH); - uiCrystalfireBreathTimer = 14*IN_MILLISECONDS; - } else uiCrystalfireBreathTimer -= diff; + _enrage = false; + _intenseCold = true; + } - if (uiTailSweepTimer <= diff) + void Reset() override { - DoCast(me, SPELL_TAIL_SWEEP); - uiTailSweepTimer = 5*IN_MILLISECONDS; - } else uiTailSweepTimer -= diff; + Initialize(); + _intenseColdList.clear(); - if (uiCrystalChainsCrystalizeTimer <= diff) + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + + RemovePrison(CheckContainmentSpheres()); + _Reset(); + } + + void EnterCombat(Unit* /*who*/) override { - Talk(SAY_CRYSTAL_NOVA); - if (IsHeroic()) - DoCast(me, SPELL_CRYSTALIZE); - else if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - DoCast(target, SPELL_CRYSTAL_CHAINS); - uiCrystalChainsCrystalizeTimer = DUNGEON_MODE(30*IN_MILLISECONDS, 11*IN_MILLISECONDS); - } else uiCrystalChainsCrystalizeTimer -= diff; + Talk(SAY_AGGRO); + DoCastAOE(SPELL_INTENSE_COLD); + _EnterCombat(); - DoMeleeAttackIfReady(); + events.ScheduleEvent(EVENT_CRYSTAL_FIRE_BREATH, 14000); + events.ScheduleEvent(EVENT_CRYSTAL_CHAINS_CRYSTALIZE, DUNGEON_MODE(30000, 11000)); + events.ScheduleEvent(EVENT_TAIL_SWEEP, 5000); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _JustDied(); + } + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + bool CheckContainmentSpheres(bool remove_prison = false) + { + ContainmentSphereGUIDs[0] = instance->GetGuidData(ANOMALUS_CONTAINMET_SPHERE); + ContainmentSphereGUIDs[1] = instance->GetGuidData(ORMOROKS_CONTAINMET_SPHERE); + ContainmentSphereGUIDs[2] = instance->GetGuidData(TELESTRAS_CONTAINMET_SPHERE); + + GameObject* ContainmentSpheres[DATA_CONTAINMENT_SPHERES]; + + for (uint8 i = 0; i < DATA_CONTAINMENT_SPHERES; ++i) + { + ContainmentSpheres[i] = ObjectAccessor::GetGameObject(*me, ContainmentSphereGUIDs[i]); + if (!ContainmentSpheres[i]) + return false; + if (ContainmentSpheres[i]->GetGoState() != GO_STATE_ACTIVE) + return false; + } + if (remove_prison) + RemovePrison(true); + return true; + } + + void RemovePrison(bool remove) + { + if (remove) + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (me->HasAura(SPELL_FROZEN_PRISON)) + me->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON); + } + else + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoCast(me, SPELL_FROZEN_PRISON, false); + } + } + + void SetGUID(ObjectGuid guid, int32 id/* = 0 */) override + { + if (id == DATA_INTENSE_COLD) + _intenseColdList.push_back(guid); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (!_enrage && me->HealthBelowPctDamaged(25, damage)) + { + Talk(SAY_ENRAGE); + Talk(SAY_FRENZY); + DoCast(me, SPELL_ENRAGE); + _enrage = true; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CRYSTAL_FIRE_BREATH: + DoCastVictim(SPELL_CRYSTALFIRE_BREATH); + events.ScheduleEvent(EVENT_CRYSTAL_FIRE_BREATH, 14000); + break; + case EVENT_CRYSTAL_CHAINS_CRYSTALIZE: + DoCast(me, SPELL_TAIL_SWEEP); + events.ScheduleEvent(EVENT_CRYSTAL_CHAINS_CRYSTALIZE, 5000); + break; + case EVENT_TAIL_SWEEP: + Talk(SAY_CRYSTAL_NOVA); + if (IsHeroic()) + DoCast(me, SPELL_CRYSTALIZE); + else if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_CRYSTAL_CHAINS); + events.ScheduleEvent(EVENT_TAIL_SWEEP, DUNGEON_MODE(30000, 11000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + bool _intenseCold; + bool _enrage; + ObjectGuid ContainmentSphereGUIDs[DATA_CONTAINMENT_SPHERES]; + public: + GuidList _intenseColdList; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI(creature); } - }; - }; class containment_sphere : public GameObjectScript @@ -277,9 +285,9 @@ class achievement_intense_cold : public AchievementCriteriaScript if (!target) return false; - GuidList intenseColdList = ENSURE_AI(boss_keristrasza::boss_keristraszaAI, target->ToCreature()->AI())->intenseColdList; - if (!intenseColdList.empty()) - for (GuidList::iterator itr = intenseColdList.begin(); itr != intenseColdList.end(); ++itr) + GuidList _intenseColdList = ENSURE_AI(boss_keristrasza::boss_keristraszaAI, target->ToCreature()->AI())->_intenseColdList; + if (!_intenseColdList.empty()) + for (GuidList::iterator itr = _intenseColdList.begin(); itr != _intenseColdList.end(); ++itr) if (player->GetGUID() == *itr) return false; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index e7252deff59..1385d98c345 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -548,6 +548,11 @@ class boss_flame_leviathan : public CreatureScript if (me->isAttackReady()) { Unit* target = ObjectAccessor::GetUnit(*me, _pursueTarget); + + // Pursue was unable to acquire a valid target, so get the current victim as target. + if (!target && me->GetVictim()) + target = me->GetVictim(); + if (me->IsWithinCombatRange(target, 30.0f)) { DoCast(target, SPELL_BATTERING_RAM); @@ -1648,7 +1653,7 @@ class FlameLeviathanPursuedTargetSelector bool operator()(WorldObject* target) const { - //! No players, only vehicles (@todo check if blizzlike) + //! No players, only vehicles. Pursue is never cast on players. Creature* creatureTarget = target->ToCreature(); if (!creatureTarget) return true; @@ -1698,12 +1703,7 @@ class spell_pursue : public SpellScriptLoader void FilterTargets(std::list& targets) { targets.remove_if(FlameLeviathanPursuedTargetSelector(GetCaster())); - if (targets.empty()) - { - if (Creature* caster = GetCaster()->ToCreature()) - caster->AI()->EnterEvadeMode(); - } - else + if (!targets.empty()) { //! In the end, only one target should be selected _target = Trinity::Containers::SelectRandomContainerElement(targets); diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index c426ce381bd..97777cd5f6e 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -140,8 +140,8 @@ enum AncestralWolf { EMOTE_WOLF_LIFT_HEAD = 0, EMOTE_WOLF_HOWL = 1, - SAY_WOLF_WELCOME = 2, - SPELL_ANCESTRAL_WOLF_BUFF = 29981, + SAY_WOLF_WELCOME = 0, + SPELL_ANCESTRAL_WOLF_BUFF = 29938, NPC_RYGA = 17123 }; @@ -166,11 +166,16 @@ public: void Reset() override { ryga = NULL; + } + + // Override Evade Mode event, recast buff that was removed by standard handler + void EnterEvadeMode() override + { + npc_escortAI::EnterEvadeMode(); DoCast(me, SPELL_ANCESTRAL_WOLF_BUFF, true); } void MoveInLineOfSight(Unit* who) override - { if (!ryga && who->GetEntry() == NPC_RYGA && me->IsWithinDistInMap(who, 15.0f)) if (Creature* temp = who->ToCreature()) @@ -188,10 +193,48 @@ public: break; case 2: Talk(EMOTE_WOLF_HOWL); + DoCast(me, SPELL_ANCESTRAL_WOLF_BUFF, true); break; + // Move Ryga into position + case 48: + if (Creature* ryga = me->FindNearestCreature(NPC_RYGA,70)) + { + if (ryga->IsAlive() && !ryga->IsInCombat()) + { + ryga->SetWalk(true); + ryga->SetSpeed(MOVE_WALK, 1.5f); + ryga->GetMotionMaster()->MovePoint(0, 517.340698f, 3885.03975f, 190.455978f, true); + Reset(); + } + } + break; + // Ryga Kneels and welcomes spirit wolf case 50: - if (ryga && ryga->IsAlive() && !ryga->IsInCombat()) - ryga->AI()->Talk(SAY_WOLF_WELCOME); + if (Creature* ryga = me->FindNearestCreature(NPC_RYGA,70)) + { + if (ryga->IsAlive() && !ryga->IsInCombat()) + { + ryga->SetFacingTo(0.776773f); + ryga->SetStandState(UNIT_STAND_STATE_KNEEL); + ryga->AI()->Talk(SAY_WOLF_WELCOME); + Reset(); + } + } + break; + // Ryga returns to spawn point + case 51: + if (Creature* ryga = me->FindNearestCreature(NPC_RYGA,70)) + { + if (ryga->IsAlive() && !ryga->IsInCombat()) + { + float fRetX, fRetY, fRetZ, fRetO; + ryga->GetRespawnPosition(fRetX, fRetY, fRetZ, &fRetO); + ryga->SetHomePosition(fRetX, fRetY, fRetZ, fRetO); + ryga->SetStandState(UNIT_STAND_STATE_STAND); + ryga->GetMotionMaster()->MoveTargetedHome(); + Reset(); + } + } break; } } diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index c18ba2e20d6..07195a334b1 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -43,6 +43,7 @@ enum DeathKnightSpells SPELL_DK_DEATH_AND_DECAY_DAMAGE = 52212, SPELL_DK_DEATH_COIL_DAMAGE = 47632, SPELL_DK_DEATH_COIL_HEAL = 47633, + SPELL_DK_DEATH_GRIP = 49560, SPELL_DK_DEATH_STRIKE_HEAL = 45470, SPELL_DK_DEATH_STRIKE_ENABLER = 89832, SPELL_DK_FROST_FEVER = 55095, @@ -1556,6 +1557,50 @@ class spell_dk_will_of_the_necropolis : public SpellScriptLoader } }; +// 49576 - Death Grip Initial +class spell_dk_death_grip_initial : public SpellScriptLoader +{ +public: + spell_dk_death_grip_initial() : SpellScriptLoader("spell_dk_death_grip_initial") { } + + class spell_dk_death_grip_initial_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_death_grip_initial_SpellScript); + + SpellCastResult CheckCast() + { + Unit* caster = GetCaster(); + // Death Grip should not be castable while jumping/falling + if (caster->HasUnitState(UNIT_STATE_JUMPING) || caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING)) + return SPELL_FAILED_MOVING; + + // Patch 3.3.3 (2010-03-23): Minimum range has been changed to 8 yards in PvP. + Unit* target = GetExplTargetUnit(); + if (target && target->GetTypeId() == TYPEID_PLAYER) + if (caster->GetDistance(target) < 8.f) + return SPELL_FAILED_TOO_CLOSE; + + return SPELL_CAST_OK; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_DK_DEATH_GRIP, true); + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_dk_death_grip_initial_SpellScript::CheckCast); + OnEffectHitTarget += SpellEffectFn(spell_dk_death_grip_initial_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_dk_death_grip_initial_SpellScript(); + } +}; + void AddSC_deathknight_spell_scripts() { new spell_dk_anti_magic_shell_raid(); @@ -1585,4 +1630,5 @@ void AddSC_deathknight_spell_scripts() new spell_dk_scourge_strike(); new spell_dk_vampiric_blood(); new spell_dk_will_of_the_necropolis(); + new spell_dk_death_grip_initial(); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 73736e0a0c2..7bc981a522c 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -1076,9 +1076,12 @@ class spell_q14112_14145_chum_the_water: public SpellScriptLoader // http://old01.wowhead.com/quest=9452 - Red Snapper - Very Tasty! enum RedSnapperVeryTasty { - SPELL_CAST_NET = 29866, - ITEM_RED_SNAPPER = 23614, - SPELL_NEW_SUMMON_TEST = 49214, + ITEM_RED_SNAPPER = 23614, + + SPELL_CAST_NET = 29866, + SPELL_NEW_SUMMON_TEST = 49214, + + GO_SCHOOL_OF_RED_SNAPPER = 181616 }; class spell_q9452_cast_net: public SpellScriptLoader @@ -1095,6 +1098,15 @@ class spell_q9452_cast_net: public SpellScriptLoader return GetCaster()->GetTypeId() == TYPEID_PLAYER; } + SpellCastResult CheckCast() + { + GameObject* go = GetCaster()->FindNearestGameObject(GO_SCHOOL_OF_RED_SNAPPER, 3.0f); + if (!go || go->GetRespawnTime()) + return SPELL_FAILED_REQUIRES_SPELL_FOCUS; + + return SPELL_CAST_OK; + } + void HandleDummy(SpellEffIndex /*effIndex*/) { Player* caster = GetCaster()->ToPlayer(); @@ -1104,9 +1116,19 @@ class spell_q9452_cast_net: public SpellScriptLoader caster->CastSpell(caster, SPELL_NEW_SUMMON_TEST, true); } + void HandleActiveObject(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitGObj()->SetRespawnTime(roll_chance_i(50) ? 2 * MINUTE : 3 * MINUTE); + GetHitGObj()->Use(GetCaster()); + GetHitGObj()->SetLootState(GO_JUST_DEACTIVATED); + } + void Register() override { + OnCheckCast += SpellCheckCastFn(spell_q9452_cast_net_SpellScript::CheckCast); OnEffectHit += SpellEffectFn(spell_q9452_cast_net_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_q9452_cast_net_SpellScript::HandleActiveObject, EFFECT_1, SPELL_EFFECT_ACTIVATE_OBJECT); } };