Merge branch 'master' into Playerbot
This commit is contained in:
@@ -20,15 +20,7 @@
|
||||
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 107000
|
||||
#define BasicDeadlineTimerThirdTemplateArg , boost::asio::io_context::executor_type
|
||||
#elif BOOST_VERSION >= 106600
|
||||
#define BasicDeadlineTimerThirdTemplateArg
|
||||
#else
|
||||
#define BasicDeadlineTimerThirdTemplateArg , boost::asio::deadline_timer_service<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime>>
|
||||
#endif
|
||||
|
||||
#define DeadlineTimerBase boost::asio::basic_deadline_timer<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime> BasicDeadlineTimerThirdTemplateArg>
|
||||
#define DeadlineTimerBase boost::asio::basic_deadline_timer<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::io_context::executor_type>
|
||||
|
||||
namespace Acore::Asio
|
||||
{
|
||||
|
||||
@@ -20,16 +20,10 @@
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 106600
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#define IoContextBaseNamespace boost::asio
|
||||
#define IoContextBase io_context
|
||||
#else
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#define IoContextBaseNamespace boost::asio
|
||||
#define IoContextBase io_service
|
||||
#endif
|
||||
|
||||
namespace Acore::Asio
|
||||
{
|
||||
@@ -45,9 +39,7 @@ namespace Acore::Asio
|
||||
std::size_t run() { return _impl.run(); }
|
||||
void stop() { _impl.stop(); }
|
||||
|
||||
#if BOOST_VERSION >= 106600
|
||||
boost::asio::io_context::executor_type get_executor() noexcept { return _impl.get_executor(); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
IoContextBaseNamespace::IoContextBase _impl;
|
||||
@@ -56,21 +48,13 @@ namespace Acore::Asio
|
||||
template<typename T>
|
||||
inline decltype(auto) post(IoContextBaseNamespace::IoContextBase& ioContext, T&& t)
|
||||
{
|
||||
#if BOOST_VERSION >= 106600
|
||||
return boost::asio::post(ioContext, std::forward<T>(t));
|
||||
#else
|
||||
return ioContext.post(std::forward<T>(t));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline decltype(auto) get_io_context(T&& ioObject)
|
||||
{
|
||||
#if BOOST_VERSION >= 106600
|
||||
return ioObject.get_executor().context();
|
||||
#else
|
||||
return ioObject.get_io_service();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,21 +23,9 @@
|
||||
|
||||
namespace Acore::Net
|
||||
{
|
||||
#if BOOST_VERSION >= 106600
|
||||
using boost::asio::ip::make_address;
|
||||
using boost::asio::ip::make_address_v4;
|
||||
inline uint32 address_to_uint(boost::asio::ip::address_v4 const& address) { return address.to_uint(); }
|
||||
#else
|
||||
inline boost::asio::ip::address make_address(char const* str) { return boost::asio::ip::address::from_string(str); }
|
||||
inline boost::asio::ip::address make_address(char const* str, boost::system::error_code& ec) { return boost::asio::ip::address::from_string(str, ec); }
|
||||
inline boost::asio::ip::address make_address(std::string const& str) { return boost::asio::ip::address::from_string(str); }
|
||||
inline boost::asio::ip::address make_address(std::string const& str, boost::system::error_code& ec) { return boost::asio::ip::address::from_string(str, ec); }
|
||||
inline boost::asio::ip::address_v4 make_address_v4(char const* str) { return boost::asio::ip::address_v4::from_string(str); }
|
||||
inline boost::asio::ip::address_v4 make_address_v4(char const* str, boost::system::error_code& ec) { return boost::asio::ip::address_v4::from_string(str, ec); }
|
||||
inline boost::asio::ip::address_v4 make_address_v4(std::string const& str) { return boost::asio::ip::address_v4::from_string(str); }
|
||||
inline boost::asio::ip::address_v4 make_address_v4(std::string const& str, boost::system::error_code& ec) { return boost::asio::ip::address_v4::from_string(str, ec); }
|
||||
inline uint32 address_to_uint(boost::asio::ip::address_v4 const& address) { return address.to_ulong(); }
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // IpAddress_h__
|
||||
|
||||
@@ -20,24 +20,16 @@
|
||||
|
||||
#include "Define.h"
|
||||
#include "IpAddress.h"
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 106600
|
||||
#include <boost/asio/ip/network_v4.hpp>
|
||||
#include <boost/asio/ip/network_v6.hpp>
|
||||
#endif
|
||||
|
||||
namespace Acore::Net
|
||||
{
|
||||
inline bool IsInNetwork(boost::asio::ip::address_v4 const& networkAddress, boost::asio::ip::address_v4 const& mask, boost::asio::ip::address_v4 const& clientAddress)
|
||||
{
|
||||
#if BOOST_VERSION >= 106600
|
||||
boost::asio::ip::network_v4 network = boost::asio::ip::make_network_v4(networkAddress, mask);
|
||||
boost::asio::ip::address_v4_range hosts = network.hosts();
|
||||
return hosts.find(clientAddress) != hosts.end();
|
||||
#else
|
||||
return (clientAddress.to_ulong() & mask.to_ulong()) == (networkAddress.to_ulong() & mask.to_ulong());
|
||||
#endif
|
||||
}
|
||||
|
||||
inline boost::asio::ip::address_v4 GetDefaultNetmaskV4(boost::asio::ip::address_v4 const& networkAddress)
|
||||
@@ -59,16 +51,9 @@ namespace Acore::Net
|
||||
|
||||
inline bool IsInNetwork(boost::asio::ip::address_v6 const& networkAddress, uint16 prefixLength, boost::asio::ip::address_v6 const& clientAddress)
|
||||
{
|
||||
#if BOOST_VERSION >= 106600
|
||||
boost::asio::ip::network_v6 network = boost::asio::ip::make_network_v6(networkAddress, prefixLength);
|
||||
boost::asio::ip::address_v6_range hosts = network.hosts();
|
||||
return hosts.find(clientAddress) != hosts.end();
|
||||
#else
|
||||
(void)networkAddress;
|
||||
(void)prefixLength;
|
||||
(void)clientAddress;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,23 +35,12 @@ namespace Acore::Asio
|
||||
Optional<boost::asio::ip::tcp::endpoint> Resolve(boost::asio::ip::tcp const& protocol, std::string const& host, std::string const& service)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
#if BOOST_VERSION >= 106600
|
||||
boost::asio::ip::resolver_base::flags flagsResolver = boost::asio::ip::resolver_base::all_matching;
|
||||
boost::asio::ip::tcp::resolver::results_type results = _impl.resolve(protocol, host, service, flagsResolver, ec);
|
||||
if (results.begin() == results.end() || ec)
|
||||
return {};
|
||||
|
||||
return results.begin()->endpoint();
|
||||
#else
|
||||
boost::asio::ip::resolver_query_base::flags flagsQuery = boost::asio::ip::tcp::resolver::query::all_matching;
|
||||
boost::asio::ip::tcp::resolver::query query(std::move(protocol), std::move(host), std::move(service), flagsQuery);
|
||||
boost::asio::ip::tcp::resolver::iterator itr = _impl.resolve(query, ec);
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if (itr == end || ec)
|
||||
return {};
|
||||
|
||||
return itr->endpoint();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -19,11 +19,8 @@
|
||||
#define Strand_h__
|
||||
|
||||
#include "IoContext.h"
|
||||
#include <boost/asio/strand.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 106600
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#endif
|
||||
#include <boost/asio/strand.hpp>
|
||||
|
||||
namespace Acore::Asio
|
||||
{
|
||||
@@ -36,15 +33,7 @@ namespace Acore::Asio
|
||||
Strand(IoContext& ioContext) : IoContextBaseNamespace::IoContextBase::strand(ioContext) { }
|
||||
};
|
||||
|
||||
#if BOOST_VERSION >= 106600
|
||||
using boost::asio::bind_executor;
|
||||
#else
|
||||
template<typename T>
|
||||
inline decltype(auto) bind_executor(Strand& strand, T&& t)
|
||||
{
|
||||
return strand.wrap(std::forward<T>(t));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // Strand_h__
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Duration.h"
|
||||
#include "Log.h"
|
||||
#include "MotdMgr.h"
|
||||
#include "QueryResult.h"
|
||||
#include "SRP6.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
|
||||
@@ -781,6 +781,7 @@ Logger.spells.scripts=2,Console Errors
|
||||
#Logger.spells=4,Console Server
|
||||
#Logger.sql.dev=4,Console Server
|
||||
#Logger.sql.driver=4,Console Server
|
||||
#Logger.sql.updates=4,Console Server
|
||||
#Logger.vehicles=4,Console Server
|
||||
#Logger.warden=4,Console Server
|
||||
#Logger.weather=4,Console Server
|
||||
|
||||
@@ -194,6 +194,7 @@ ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature),
|
||||
{
|
||||
_isHeroic = me->GetMap()->IsHeroic();
|
||||
_difficulty = Difficulty(me->GetMap()->GetSpawnMode());
|
||||
_invincible = false;
|
||||
}
|
||||
|
||||
void ScriptedAI::AttackStartNoMove(Unit* who)
|
||||
@@ -222,6 +223,12 @@ void ScriptedAI::UpdateAI(uint32 /*diff*/)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void ScriptedAI::DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/)
|
||||
{
|
||||
if (IsInvincible() && damage >= me->GetHealth())
|
||||
damage = me->GetHealth() - 1;
|
||||
}
|
||||
|
||||
void ScriptedAI::DoStartMovement(Unit* victim, float distance, float angle)
|
||||
{
|
||||
if (victim)
|
||||
@@ -732,8 +739,10 @@ void BossAI::UpdateAI(uint32 diff)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void BossAI::DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/)
|
||||
void BossAI::DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask)
|
||||
{
|
||||
ScriptedAI::DamageTaken(attacker, damage, damagetype, damageSchoolMask);
|
||||
|
||||
if (_nextHealthCheck._valid)
|
||||
if (me->HealthBelowPctDamaged(_nextHealthCheck._healthPct, damage))
|
||||
{
|
||||
|
||||
@@ -198,7 +198,7 @@ struct ScriptedAI : public CreatureAI
|
||||
void AttackStartNoMove(Unit* target);
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override {}
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override;
|
||||
|
||||
//Called at World update tick
|
||||
void UpdateAI(uint32 diff) override;
|
||||
@@ -438,9 +438,14 @@ struct ScriptedAI : public CreatureAI
|
||||
|
||||
Player* SelectTargetFromPlayerList(float maxdist, uint32 excludeAura = 0, bool mustBeInLOS = false) const;
|
||||
|
||||
// Allows dropping to 1 HP but prevents creature from dying.
|
||||
void SetInvincibility(bool apply) { _invincible = apply; };
|
||||
[[nodiscard]] bool IsInvincible() const { return _invincible; };
|
||||
|
||||
private:
|
||||
Difficulty _difficulty;
|
||||
bool _isHeroic;
|
||||
bool _invincible;
|
||||
std::unordered_set<uint32> _uniqueTimedEvents;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "SmartAI.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Vehicle.h"
|
||||
#include "WorldState.h"
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
// however, for some reasons removing it would cause a damn linking issue
|
||||
@@ -696,6 +697,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
if (isWithinLOSInMap && isWithinMeleeRange && isRangedAttack && isTargetRooted && canCastSpell && !me->IsVehicle())
|
||||
{
|
||||
failedSpellCast = true; // Mark spellcast as failed so we can retry it later
|
||||
|
||||
if (me->IsRooted()) // Rooted inhabit type, never move/reposition
|
||||
continue;
|
||||
|
||||
float minDistance = std::max(meleeRange, spellMinRange) - distanceToTarget + NOMINAL_MELEE_RANGE;
|
||||
CAST_AI(SmartAI, me->AI())->MoveAway(std::min(minDistance, spellMaxRange));
|
||||
continue;
|
||||
@@ -705,12 +710,20 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
if (distanceToTarget > spellMaxRange && isWithinLOSInMap)
|
||||
{
|
||||
failedSpellCast = true;
|
||||
|
||||
if (me->IsRooted()) // Rooted inhabit type, never move/reposition
|
||||
continue;
|
||||
|
||||
CAST_AI(SmartAI, me->AI())->SetCombatMove(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
|
||||
continue;
|
||||
}
|
||||
else if (distanceToTarget < spellMinRange || !(isWithinLOSInMap || isSpellIgnoreLOS))
|
||||
{
|
||||
failedSpellCast = true;
|
||||
|
||||
if (me->IsRooted()) // Rooted inhabit type, never move/reposition
|
||||
continue;
|
||||
|
||||
CAST_AI(SmartAI, me->AI())->SetCombatMove(true);
|
||||
continue;
|
||||
}
|
||||
@@ -3257,6 +3270,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_WORLD_SCRIPT:
|
||||
{
|
||||
sWorldState->HandleExternalEvent(static_cast<WorldStateEvent>(e.action.worldStateScript.eventId), e.action.worldStateScript.param);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
break;
|
||||
@@ -5061,7 +5079,7 @@ void SmartScript::GetScript()
|
||||
|
||||
if (CreatureTemplate const* cInfo = me->GetCreatureTemplate())
|
||||
{
|
||||
if (cInfo->HasFlagsExtra(CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI))
|
||||
if (cInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_DONT_OVERRIDE_ENTRY_SAI))
|
||||
{
|
||||
e = sSmartScriptMgr->GetScript((int32)me->GetEntry(), mScriptType);
|
||||
FillScript(e, me, nullptr);
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#ifndef ACORE_SMARTSCRIPT_H
|
||||
#define ACORE_SMARTSCRIPT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "SmartScriptMgr.h"
|
||||
#include "Spell.h"
|
||||
|
||||
@@ -777,6 +777,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_MOVEMENT_STOP: return NO_PARAMS;
|
||||
case SMART_ACTION_MOVEMENT_PAUSE: return sizeof(SmartAction::move);
|
||||
case SMART_ACTION_MOVEMENT_RESUME: return sizeof(SmartAction::move);
|
||||
case SMART_ACTION_WORLD_SCRIPT: return sizeof(SmartAction::worldStateScript);
|
||||
default:
|
||||
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
@@ -1960,6 +1961,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_MOVEMENT_STOP:
|
||||
case SMART_ACTION_MOVEMENT_PAUSE:
|
||||
case SMART_ACTION_MOVEMENT_RESUME:
|
||||
case SMART_ACTION_WORLD_SCRIPT:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
|
||||
@@ -20,12 +20,11 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "DBCStores.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Optional.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Unit.h"
|
||||
#include <limits>
|
||||
|
||||
typedef uint32 SAIBool;
|
||||
@@ -727,8 +726,9 @@ enum SMART_ACTION
|
||||
SMART_ACTION_MOVEMENT_STOP = 234, //
|
||||
SMART_ACTION_MOVEMENT_PAUSE = 235, // timer
|
||||
SMART_ACTION_MOVEMENT_RESUME = 236, // timerOverride
|
||||
SMART_ACTION_WORLD_SCRIPT = 237, // eventId, param
|
||||
|
||||
SMART_ACTION_AC_END = 237, // placeholder
|
||||
SMART_ACTION_AC_END = 238, // placeholder
|
||||
};
|
||||
|
||||
enum class SmartActionSummonCreatureFlags
|
||||
@@ -1472,6 +1472,12 @@ struct SmartAction
|
||||
{
|
||||
uint32 timer;
|
||||
} move;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 eventId;
|
||||
uint32 param;
|
||||
} worldStateScript;
|
||||
//! Note for any new future actions
|
||||
//! All parameters must have type uint32
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "Battlefield.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "World.h"
|
||||
|
||||
class Group;
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
#define __BATTLEGROUNDQUEUE_H
|
||||
|
||||
#include "Battleground.h"
|
||||
#include "Common.h"
|
||||
#include "DBCEnums.h"
|
||||
#include "EventProcessor.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "SharedDefines.h"
|
||||
#include <array>
|
||||
|
||||
constexpr auto COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME = 10;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#ifndef _CHANNEL_H
|
||||
#define _CHANNEL_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include <string>
|
||||
|
||||
@@ -506,6 +506,9 @@ bool Acore::Impl::ChatCommands::ChatCommandNode::IsInvokerVisible(ChatHandler co
|
||||
if (!_invoker)
|
||||
return false;
|
||||
|
||||
if (!sScriptMgr->OnBeforeIsInvokerVisible(_name, _permission, who))
|
||||
return true;
|
||||
|
||||
if (who.IsConsole() && (_permission.AllowConsole == Acore::ChatCommands::Console::No))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "SharedDefines.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "World.h"
|
||||
|
||||
using namespace Acore::Hyperlinks;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "Spell.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "WorldState.h"
|
||||
|
||||
// Checks if object meets the condition
|
||||
// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI)
|
||||
@@ -570,6 +571,11 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
|
||||
condMeets = unit->IsCharmed();
|
||||
break;
|
||||
}
|
||||
case CONDITION_WORLD_SCRIPT:
|
||||
{
|
||||
condMeets = sWorldState->IsConditionFulfilled(static_cast<WorldStateCondition>(ConditionValue1), static_cast<WorldStateConditionState>(ConditionValue2));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
condMeets = false;
|
||||
break;
|
||||
@@ -770,6 +776,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition()
|
||||
case CONDITION_CHARMED:
|
||||
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
|
||||
break;
|
||||
case CONDITION_WORLD_SCRIPT:
|
||||
mask |= GRID_MAP_TYPE_MASK_ALL;
|
||||
break;
|
||||
default:
|
||||
ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
|
||||
break;
|
||||
|
||||
@@ -86,7 +86,9 @@ enum ConditionTypes
|
||||
CONDITION_AC_START = 100,
|
||||
CONDITION_QUEST_SATISFY_EXCLUSIVE = 101, // quest_id 0 0 true if satisfied exclusive group
|
||||
CONDITION_HAS_AURA_TYPE = 102, // aura_type 0 0 true if has aura type
|
||||
CONDITION_AC_END = 103 // placeholder
|
||||
CONDITION_WORLD_SCRIPT = 103, // conditionId state 0 true if WorldState::IsConditionFulfilled returns true
|
||||
|
||||
CONDITION_AC_END = 104 // placeholder
|
||||
};
|
||||
|
||||
/*! Documentation on implementing a new ConditionSourceType:
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#ifndef _LFGQUEUE_H
|
||||
#define _LFGQUEUE_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "LFG.h"
|
||||
|
||||
namespace lfg
|
||||
|
||||
@@ -22,10 +22,8 @@
|
||||
#include "CharmInfo.h"
|
||||
#include "Common.h"
|
||||
#include "CreatureData.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "LootMgr.h"
|
||||
#include "Unit.h"
|
||||
#include "World.h"
|
||||
#include <list>
|
||||
|
||||
class SpellInfo;
|
||||
|
||||
@@ -69,7 +69,7 @@ enum CreatureFlagsExtra : uint32
|
||||
CREATURE_FLAG_EXTRA_MODULE = 0x01000000,
|
||||
CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE = 0x02000000, // Prevent creatures from calling for assistance on initial aggro
|
||||
CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS = 0x04000000, // Prevents creature from responding to assistance calls
|
||||
CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI = 0x08000000, // Load both ENTRY and GUID specific SAI
|
||||
CREATURE_FLAG_EXTRA_DONT_OVERRIDE_ENTRY_SAI = 0x08000000, // Load both ENTRY and GUID specific SAI
|
||||
CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)
|
||||
CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000, // creature ignore pathfinding
|
||||
CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK = 0x40000000, // creature is immune to knockback effects
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "Log.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "QueryResult.h"
|
||||
#include "WaypointMgr.h"
|
||||
|
||||
FormationMgr::~FormationMgr()
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define _FORMATIONS_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Unit.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "NPCHandler.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "QuestDef.h"
|
||||
#include <map>
|
||||
|
||||
class WorldSession;
|
||||
class ObjectGuid;
|
||||
|
||||
@@ -58,7 +58,7 @@ AC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
|
||||
case CREATURE_FLAG_EXTRA_MODULE: return { "CREATURE_FLAG_EXTRA_MODULE", "CREATURE_FLAG_EXTRA_MODULE", "" };
|
||||
case CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE: return { "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "Prevent creatures from calling for assistance on initial aggro" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS: return { "CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS", "CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS", "Prevents creature from responding to assistance calls" };
|
||||
case CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI: return { "CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI", "CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI", "Load both ENTRY and GUID specific SAI" };
|
||||
case CREATURE_FLAG_EXTRA_DONT_OVERRIDE_ENTRY_SAI: return { "CREATURE_FLAG_EXTRA_DONT_OVERRIDE_ENTRY_SAI", "CREATURE_FLAG_EXTRA_DONT_OVERRIDE_ENTRY_SAI", "Load both ENTRY and GUID specific SAI" };
|
||||
case CREATURE_FLAG_EXTRA_DUNGEON_BOSS: return { "CREATURE_FLAG_EXTRA_DUNGEON_BOSS", "CREATURE_FLAG_EXTRA_DUNGEON_BOSS", "creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING: return { "CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING", "CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING", "creature ignore pathfinding" };
|
||||
case CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK: return { "CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK", "CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK", "creature is immune to knockback effects" };
|
||||
@@ -102,7 +102,7 @@ AC_API_EXPORT CreatureFlagsExtra EnumUtils<CreatureFlagsExtra>::FromIndex(std::s
|
||||
case 24: return CREATURE_FLAG_EXTRA_MODULE;
|
||||
case 25: return CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE;
|
||||
case 26: return CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS;
|
||||
case 27: return CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI;
|
||||
case 27: return CREATURE_FLAG_EXTRA_DONT_OVERRIDE_ENTRY_SAI;
|
||||
case 28: return CREATURE_FLAG_EXTRA_DUNGEON_BOSS;
|
||||
case 29: return CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING;
|
||||
case 30: return CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK;
|
||||
@@ -143,7 +143,7 @@ AC_API_EXPORT std::size_t EnumUtils<CreatureFlagsExtra>::ToIndex(CreatureFlagsEx
|
||||
case CREATURE_FLAG_EXTRA_MODULE: return 24;
|
||||
case CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE: return 25;
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS: return 26;
|
||||
case CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI: return 27;
|
||||
case CREATURE_FLAG_EXTRA_DONT_OVERRIDE_ENTRY_SAI: return 27;
|
||||
case CREATURE_FLAG_EXTRA_DUNGEON_BOSS: return 28;
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING: return 29;
|
||||
case CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK: return 30;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#define AZEROTHCORE_GAMEOBJECT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "G3D/Quat.h"
|
||||
#include "GameObjectData.h"
|
||||
#include "LootMgr.h"
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
#define GAMEOBJECTDATA_H
|
||||
|
||||
#include "SharedDefines.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#define MAX_GAMEOBJECT_QUEST_ITEMS 6
|
||||
#define MAX_GO_STATE 3
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Util.h"
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "ByteBuffer.h"
|
||||
#include "Geometry.h"
|
||||
#include "GridDefines.h"
|
||||
#include "Random.h"
|
||||
#include <G3D/g3dmath.h>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#define CinematicMgr_h__
|
||||
|
||||
#include "Define.h"
|
||||
#include "Object.h"
|
||||
#include "Position.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include <vector>
|
||||
|
||||
constexpr auto CINEMATIC_UPDATEDIFF = 500;
|
||||
constexpr auto CINEMATIC_LOOKAHEAD = 2000;
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldState.h"
|
||||
#include <cmath>
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
@@ -1722,6 +1723,7 @@ void Player::RemoveFromWorld()
|
||||
m_session->DoLootRelease(lguid);
|
||||
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sWorldState->HandlePlayerLeaveZone(this, static_cast<WorldStateZoneId>(m_zoneUpdateId));
|
||||
}
|
||||
|
||||
// Remove items from world before self - player must be found in Item::RemoveFromObjectUpdate
|
||||
@@ -6930,7 +6932,7 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
|
||||
float maxDamage = proto->Damage[i].DamageMax;
|
||||
|
||||
// If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
|
||||
if (ssv)
|
||||
if (ssv && i == 0) // scaling stats only for first damage
|
||||
{
|
||||
int32 extraDPS = ssv->getDPSMod(ScalingStatValue);
|
||||
if (extraDPS)
|
||||
@@ -6945,6 +6947,8 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
|
||||
|
||||
if (apply)
|
||||
{
|
||||
sScriptMgr->OnApplyWeaponDamage(this, slot, proto, minDamage, maxDamage, i);
|
||||
|
||||
if (minDamage > 0.f)
|
||||
{
|
||||
SetBaseWeaponDamage(WeaponAttackType(attType), MINDAMAGE, minDamage, i);
|
||||
|
||||
@@ -1423,6 +1423,7 @@ public:
|
||||
void CompleteQuest(uint32 quest_id);
|
||||
void IncompleteQuest(uint32 quest_id);
|
||||
void RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce = true, bool isLFGReward = false);
|
||||
void SetRewardedQuest(uint32 quest_id);
|
||||
void FailQuest(uint32 quest_id);
|
||||
bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const;
|
||||
bool SatisfyQuestLevel(Quest const* qInfo, bool msg) const;
|
||||
|
||||
@@ -819,8 +819,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
SetSeasonalQuestStatus(quest_id);
|
||||
|
||||
RemoveActiveQuest(quest_id, false);
|
||||
m_RewardedQuests.insert(quest_id);
|
||||
m_RewardedQuestsSave[quest_id] = true;
|
||||
SetRewardedQuest(quest_id);
|
||||
|
||||
if (announce)
|
||||
SendQuestReward(quest, XP);
|
||||
@@ -877,6 +876,12 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
sScriptMgr->OnPlayerCompleteQuest(this, quest);
|
||||
}
|
||||
|
||||
void Player::SetRewardedQuest(uint32 quest_id)
|
||||
{
|
||||
m_RewardedQuests.insert(quest_id);
|
||||
m_RewardedQuestsSave[quest_id] = true;
|
||||
}
|
||||
|
||||
void Player::FailQuest(uint32 questId)
|
||||
{
|
||||
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "Vehicle.h"
|
||||
#include "Weather.h"
|
||||
#include "WeatherMgr.h"
|
||||
#include "WorldState.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
@@ -1216,6 +1217,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
||||
{
|
||||
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sOutdoorPvPMgr->HandlePlayerEnterZone(this, newZone);
|
||||
sWorldState->HandlePlayerLeaveZone(this, static_cast<WorldStateZoneId>(m_zoneUpdateId));
|
||||
sWorldState->HandlePlayerEnterZone(this, static_cast<WorldStateZoneId>(newZone));
|
||||
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sBattlefieldMgr->HandlePlayerEnterZone(this, newZone);
|
||||
SendInitWorldStates(newZone,
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
#ifndef _CHARMINFO_H
|
||||
#define _CHARMINFO_H
|
||||
|
||||
#include "Object.h"
|
||||
#include "Define.h"
|
||||
#include "ObjectGuid.h"
|
||||
|
||||
#define MAX_SPELL_CHARM 4
|
||||
#define MAX_SPELL_VEHICLE 6
|
||||
|
||||
@@ -180,6 +180,7 @@ enum eScriptFlags
|
||||
// Playsound flags
|
||||
SF_PLAYSOUND_TARGET_PLAYER = 0x1,
|
||||
SF_PLAYSOUND_DISTANCE_SOUND = 0x2,
|
||||
SF_PLAYSOUND_DISTANCE_RADIUS = 0x4,
|
||||
|
||||
// Orientation flags
|
||||
SF_ORIENTATION_FACE_TARGET = 0x1,
|
||||
@@ -307,6 +308,7 @@ struct ScriptInfo
|
||||
{
|
||||
uint32 SoundID; // datalong
|
||||
uint32 Flags; // datalong2
|
||||
int32 Radius; // dataint
|
||||
} Playsound;
|
||||
|
||||
struct // SCRIPT_COMMAND_CREATE_ITEM (17)
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "Grid.h"
|
||||
#include "GridReference.h"
|
||||
#include "Timer.h"
|
||||
#include "Util.h"
|
||||
|
||||
template
|
||||
<
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "ObjectMgr.h"
|
||||
#include "Optional.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
@@ -59,6 +59,9 @@ void InstanceScript::OnCreatureCreate(Creature* creature)
|
||||
{
|
||||
AddObject(creature);
|
||||
AddMinion(creature);
|
||||
|
||||
if (creature->IsSummon())
|
||||
SetSummoner(creature);
|
||||
}
|
||||
|
||||
void InstanceScript::OnCreatureRemove(Creature* creature)
|
||||
@@ -194,6 +197,15 @@ void InstanceScript::LoadObjectData(ObjectData const* data, ObjectInfoMap& objec
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceScript::LoadSummonData(ObjectData const* data)
|
||||
{
|
||||
while (data->entry)
|
||||
{
|
||||
_summonInfo[data->entry] = data->type;
|
||||
++data;
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceScript::UpdateMinionState(Creature* minion, EncounterState state)
|
||||
{
|
||||
switch (state)
|
||||
@@ -348,6 +360,16 @@ void InstanceScript::RemoveMinion(Creature* minion)
|
||||
AddMinion(minion, false);
|
||||
}
|
||||
|
||||
void InstanceScript::SetSummoner(Creature* creature)
|
||||
{
|
||||
auto const& summonData = _summonInfo.find(creature->GetEntry());
|
||||
|
||||
if (summonData != _summonInfo.end())
|
||||
if (Creature* summoner = GetCreature(summonData->second))
|
||||
if (summoner->IsAIEnabled)
|
||||
summoner->AI()->JustSummoned(creature);
|
||||
}
|
||||
|
||||
bool InstanceScript::SetBossState(uint32 id, EncounterState state)
|
||||
{
|
||||
if (id < bosses.size())
|
||||
@@ -393,7 +415,11 @@ void InstanceScript::StorePersistentData(uint32 index, uint32 data)
|
||||
return;
|
||||
}
|
||||
|
||||
persistentData[index] = data;
|
||||
if (persistentData[index] != data)
|
||||
{
|
||||
persistentData[index] = data;
|
||||
SaveToDB();
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceScript::DoForAllMinions(uint32 id, std::function<void(Creature*)> exec)
|
||||
|
||||
@@ -288,6 +288,11 @@ protected:
|
||||
void LoadDoorData(DoorData const* data);
|
||||
void LoadMinionData(MinionData const* data);
|
||||
void LoadObjectData(ObjectData const* creatureData, ObjectData const* gameObjectData);
|
||||
// Allows setting another creature as summoner for a creature.
|
||||
// This is used to handle summons that are not directly controlled by the summoner.
|
||||
// Summoner creature must be loaded in the instance data (LoadObjectData).
|
||||
void LoadSummonData(ObjectData const* data);
|
||||
void SetSummoner(Creature* creature);
|
||||
|
||||
void AddObject(Creature* obj, bool add = true);
|
||||
void RemoveObject(Creature* obj);
|
||||
@@ -324,6 +329,7 @@ private:
|
||||
MinionInfoMap minions;
|
||||
ObjectInfoMap _creatureInfo;
|
||||
ObjectInfoMap _gameObjectInfo;
|
||||
ObjectInfoMap _summonInfo;
|
||||
ObjectGuidMap _objectGuids;
|
||||
ObjectStateMap _objectStateMap;
|
||||
uint32 completedEncounters; // completed encounter mask, bit indexes are DungeonEncounter.dbc boss numbers, used for packets
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "DatabaseEnv.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PreparedStatement.h"
|
||||
#include "QueryResult.h"
|
||||
|
||||
LootItemStorage::LootItemStorage()
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "MapInstanced.h"
|
||||
#include "Metric.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "MMapFactory.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectGridLoader.h"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "InstanceScript.h"
|
||||
#include "MapMgr.h"
|
||||
#include "MoveSpline.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Transport.h"
|
||||
|
||||
TransportTemplate::~TransportTemplate()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef __DYNAMICVISIBILITY_H
|
||||
#define __DYNAMICVISIBILITY_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Define.h"
|
||||
|
||||
struct VisibilitySettingData
|
||||
{
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#define ACORE_MOTIONMASTER_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "Position.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Spline/MoveSpline.h"
|
||||
#include <optional>
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
#ifndef ACORE_FLEEINGMOVEMENTGENERATOR_H
|
||||
#define ACORE_FLEEINGMOVEMENTGENERATOR_H
|
||||
|
||||
#include "Creature.h"
|
||||
#include "MovementGenerator.h"
|
||||
#include "Timer.h"
|
||||
|
||||
template<class T>
|
||||
class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovementGenerator<T> >
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourNavMeshQuery.h"
|
||||
#include "MMapFactory.h"
|
||||
#include "MMapMgr.h"
|
||||
#include "MapDefines.h"
|
||||
#include "MoveSplineInitArgs.h"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef ACORE_POINTMOVEMENTGENERATOR_H
|
||||
#define ACORE_POINTMOVEMENTGENERATOR_H
|
||||
|
||||
#include "FollowerReference.h"
|
||||
#include "Creature.h"
|
||||
#include "MovementGenerator.h"
|
||||
|
||||
template<class T>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Spell.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
|
||||
template<class T>
|
||||
RandomMovementGenerator<T>::~RandomMovementGenerator() { }
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#define RANDOM_POINTS_NUMBER 12
|
||||
#define RANDOM_LINKS_COUNT 7
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef ACORE_WAYPOINTMANAGER_H
|
||||
#define ACORE_WAYPOINTMANAGER_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Define.h"
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Log.h"
|
||||
#include "MapMgr.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Transport.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
#ifndef __ACORE_REPUTATION_MGR_H
|
||||
#define __ACORE_REPUTATION_MGR_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "DatabaseEnvFwd.h"
|
||||
#include "DBCStructure.h"
|
||||
#include "Language.h"
|
||||
#include "QueryResult.h"
|
||||
#include "SharedDefines.h"
|
||||
#include <map>
|
||||
|
||||
|
||||
@@ -20,14 +20,12 @@
|
||||
#include "GridNotifiers.h"
|
||||
#include "Map.h"
|
||||
#include "MapMgr.h"
|
||||
#include "MapRefMgr.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Pet.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Transport.h"
|
||||
#include "WaypointMgr.h"
|
||||
#include "World.h"
|
||||
|
||||
/// Put scripts in the execution queue
|
||||
void Map::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target)
|
||||
@@ -730,8 +728,10 @@ void Map::ScriptsProcess()
|
||||
break;
|
||||
}
|
||||
|
||||
// Playsound.Flags bitmask: 0/2=without/with distance dependent
|
||||
if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_SOUND)
|
||||
// Playsound.Flags bitmask: 0/2/4=without/with distance dependent/radius
|
||||
if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_RADIUS)
|
||||
object->PlayRadiusSound(step.script->Playsound.SoundID, step.script->Playsound.Radius);
|
||||
else if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_SOUND)
|
||||
object->PlayDistanceSound(step.script->Playsound.SoundID, player);
|
||||
else
|
||||
object->PlayDirectSound(step.script->Playsound.SoundID, player);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "AllCommandScript.h"
|
||||
#include "ChatCommand.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptMgrMacros.h"
|
||||
|
||||
@@ -29,6 +30,11 @@ bool ScriptMgr::OnTryExecuteCommand(ChatHandler& handler, std::string_view cmdSt
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(AllCommandScript, ALLCOMMANDHOOK_ON_TRY_EXECUTE_COMMAND, !script->OnTryExecuteCommand(handler, cmdStr));
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnBeforeIsInvokerVisible(std::string name, Acore::Impl::ChatCommands::CommandPermissions permissions, ChatHandler const& who)
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(AllCommandScript, ALLCOMMANDHOOK_ON_BEFORE_IS_INVOKER_VISIBLE, !script->OnBeforeIsInvokerVisible(name, permissions, who));
|
||||
}
|
||||
|
||||
AllCommandScript::AllCommandScript(const char* name, std::vector<uint16> enabledHooks)
|
||||
: ScriptObject(name, ALLCOMMANDHOOK_END)
|
||||
{
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
#define SCRIPT_OBJECT_ALL_COMMAND_SCRIPT_H_
|
||||
|
||||
#include "ScriptObject.h"
|
||||
#include "ChatCommand.h"
|
||||
#include <vector>
|
||||
|
||||
enum AllCommandHook
|
||||
{
|
||||
ALLCOMMANDHOOK_ON_HANDLE_DEV_COMMAND,
|
||||
ALLCOMMANDHOOK_ON_TRY_EXECUTE_COMMAND,
|
||||
ALLCOMMANDHOOK_ON_BEFORE_IS_INVOKER_VISIBLE,
|
||||
ALLCOMMANDHOOK_END
|
||||
};
|
||||
|
||||
@@ -45,6 +47,8 @@ public:
|
||||
* @param cmdStr Contains information about the command name
|
||||
*/
|
||||
[[nodiscard]] virtual bool OnTryExecuteCommand(ChatHandler& /*handler*/, std::string_view /*cmdStr*/) { return true; }
|
||||
|
||||
[[nodiscard]] virtual bool OnBeforeIsInvokerVisible(std::string /*name*/, Acore::Impl::ChatCommands::CommandPermissions /*permissions*/, ChatHandler const& /*who*/) { return true; }
|
||||
};
|
||||
|
||||
// Compatibility for old scripts
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef SCRIPT_OBJECT_GLOBAL_SCRIPT_H_
|
||||
#define SCRIPT_OBJECT_GLOBAL_SCRIPT_H_
|
||||
|
||||
#include "DatabaseEnvFwd.h"
|
||||
#include "DBCEnums.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "ScriptObject.h"
|
||||
|
||||
@@ -652,6 +652,11 @@ void ScriptMgr::OnApplyEnchantmentItemModsBefore(Player* player, Item* item, Enc
|
||||
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_APPLY_ENCHANTMENT_ITEM_MODS_BEFORE, script->OnApplyEnchantmentItemModsBefore(player, item, slot, apply, enchant_spell_id, enchant_amount));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnApplyWeaponDamage(Player* player, uint8 slot, ItemTemplate const* proto, float& minDamage, float& maxDamage, uint8 damageIndex)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_APPLY_WEAPON_DAMAGE, script->OnApplyWeaponDamage(player, slot, proto, minDamage, maxDamage, damageIndex));
|
||||
}
|
||||
|
||||
bool ScriptMgr::CanArmorDamageModifier(Player* player)
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(PlayerScript, PLAYERHOOK_CAN_ARMOR_DAMAGE_MODIFIER, !script->CanArmorDamageModifier(player));
|
||||
|
||||
@@ -150,6 +150,7 @@ enum PlayerHook
|
||||
PLAYERHOOK_ON_CUSTOM_SCALING_STAT_VALUE,
|
||||
PLAYERHOOK_ON_APPLY_ITEM_MODS_BEFORE,
|
||||
PLAYERHOOK_ON_APPLY_ENCHANTMENT_ITEM_MODS_BEFORE,
|
||||
PLAYERHOOK_ON_APPLY_WEAPON_DAMAGE,
|
||||
PLAYERHOOK_CAN_ARMOR_DAMAGE_MODIFIER,
|
||||
PLAYERHOOK_ON_GET_FERAL_AP_BONUS,
|
||||
PLAYERHOOK_CAN_APPLY_WEAPON_DEPENDENT_AURA_DAMAGE_MOD,
|
||||
@@ -548,6 +549,8 @@ public:
|
||||
|
||||
virtual void OnApplyEnchantmentItemModsBefore(Player* /*player*/, Item* /*item*/, EnchantmentSlot /*slot*/, bool /*apply*/, uint32 /*enchant_spell_id*/, uint32& /*enchant_amount*/) { }
|
||||
|
||||
virtual void OnApplyWeaponDamage(Player* /*player*/, uint8 /*slot*/, ItemTemplate const* /*proto*/, float& /*minDamage*/, float& /*maxDamage*/, uint8 /*damageIndex*/) { }
|
||||
|
||||
[[nodiscard]] virtual bool CanArmorDamageModifier(Player* /*player*/) { return true; }
|
||||
|
||||
virtual void OnGetFeralApBonus(Player* /*player*/, int32& /*feral_bonus*/, int32 /*dpsMod*/, ItemTemplate const* /*proto*/, ScalingStatValuesEntry const* /*ssv*/) { }
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "ScriptObject.h"
|
||||
#include <vector>
|
||||
#include <memory> // NOTE: this import is NEEDED (even though some IDEs report it as unused)
|
||||
|
||||
enum ServerHook
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ArenaTeam.h"
|
||||
#include "AuctionHouseMgr.h"
|
||||
#include "Battleground.h"
|
||||
#include "ChatCommand.h"
|
||||
#include "Common.h"
|
||||
#include "DBCStores.h"
|
||||
#include "DynamicObject.h"
|
||||
@@ -444,6 +445,7 @@ public: /* PlayerScript */
|
||||
void OnCustomScalingStatValue(Player* player, ItemTemplate const* proto, uint32& statType, int32& val, uint8 itemProtoStatNumber, uint32 ScalingStatValue, ScalingStatValuesEntry const* ssv);
|
||||
void OnApplyItemModsBefore(Player* player, uint8 slot, bool apply, uint8 itemProtoStatNumber, uint32 statType, int32& val);
|
||||
void OnApplyEnchantmentItemModsBefore(Player* player, Item* item, EnchantmentSlot slot, bool apply, uint32 enchant_spell_id, uint32& enchant_amount);
|
||||
void OnApplyWeaponDamage(Player* player, uint8 slot, ItemTemplate const* proto, float& minDamage, float& maxDamage, uint8 damageIndex);
|
||||
bool CanArmorDamageModifier(Player* player);
|
||||
void OnGetFeralApBonus(Player* player, int32& feral_bonus, int32 dpsMod, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv);
|
||||
bool CanApplyWeaponDependentAuraDamageMod(Player* player, Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
|
||||
@@ -704,6 +706,7 @@ public: /* CommandSC */
|
||||
|
||||
void OnHandleDevCommand(Player* player, bool& enable);
|
||||
bool OnTryExecuteCommand(ChatHandler& handler, std::string_view cmdStr);
|
||||
bool OnBeforeIsInvokerVisible(std::string name, Acore::Impl::ChatCommands::CommandPermissions permissions, ChatHandler const& who);
|
||||
|
||||
public: /* DatabaseScript */
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#ifndef _SCRIPT_OBJECT_H_
|
||||
#define _SCRIPT_OBJECT_H_
|
||||
|
||||
#include "DatabaseEnvFwd.h"
|
||||
#include "ScriptObjectFwd.h"
|
||||
#include <string>
|
||||
|
||||
//#include "Duration.h"
|
||||
//#include "LFG.h"
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSocket.h"
|
||||
#include "WorldState.h"
|
||||
#include <zlib.h>
|
||||
|
||||
#include "BanMgr.h"
|
||||
@@ -641,6 +642,7 @@ void WorldSession::LogoutPlayer(bool save)
|
||||
_player->RepopAtGraveyard();
|
||||
|
||||
sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId());
|
||||
sWorldState->HandlePlayerLeaveZone(_player, static_cast<WorldStateZoneId>(_player->GetZoneId()));
|
||||
|
||||
// pussywizard: remove from battleground queues on logout
|
||||
for (int i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
|
||||
|
||||
@@ -18,11 +18,13 @@
|
||||
#ifndef __SPELL_H
|
||||
#define __SPELL_H
|
||||
|
||||
#include "ConditionMgr.h"
|
||||
#include "GridDefines.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "LootMgr.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "Unit.h"
|
||||
|
||||
class Unit;
|
||||
class Player;
|
||||
|
||||
@@ -1152,13 +1152,29 @@ void Spell::EffectJumpDest(SpellEffIndex effIndex)
|
||||
|
||||
void Spell::CalculateJumpSpeeds(uint8 i, float dist, float& speedXY, float& speedZ)
|
||||
{
|
||||
if (m_spellInfo->Effects[i].MiscValue)
|
||||
speedZ = float(m_spellInfo->Effects[i].MiscValue) / 10;
|
||||
else if (m_spellInfo->Effects[i].MiscValueB)
|
||||
speedZ = float(m_spellInfo->Effects[i].MiscValueB) / 10;
|
||||
float runSpeed = m_caster->IsControlledByPlayer() ? playerBaseMoveSpeed[MOVE_RUN] : baseMoveSpeed[MOVE_RUN];
|
||||
if (Creature* creature = m_caster->ToCreature())
|
||||
runSpeed *= creature->GetCreatureTemplate()->speed_run;
|
||||
|
||||
float multiplier = m_spellInfo->Effects[i].ValueMultiplier;
|
||||
if (multiplier <= 0.0f)
|
||||
multiplier = 1.0f;
|
||||
|
||||
speedXY = std::min(runSpeed * 3.0f * multiplier, std::max(28.0f, m_caster->GetSpeed(MOVE_RUN) * 4.0f));
|
||||
|
||||
float duration = dist / speedXY;
|
||||
float durationSqr = duration * duration;
|
||||
float minHeight = m_spellInfo->Effects[i].MiscValue ? m_spellInfo->Effects[i].MiscValue / 10.0f : 0.5f; // Lower bound is blizzlike
|
||||
float maxHeight = m_spellInfo->Effects[i].MiscValueB ? m_spellInfo->Effects[i].MiscValueB / 10.0f : 1000.0f; // Upper bound is unknown
|
||||
float height;
|
||||
if (durationSqr < minHeight * 8 / Movement::gravity)
|
||||
height = minHeight;
|
||||
else if (durationSqr > maxHeight * 8 / Movement::gravity)
|
||||
height = maxHeight;
|
||||
else
|
||||
speedZ = 10.0f;
|
||||
speedXY = dist * 10.0f / speedZ;
|
||||
height = Movement::gravity * durationSqr / 8;
|
||||
|
||||
speedZ = std::sqrt(2 * Movement::gravity * height);
|
||||
}
|
||||
|
||||
void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
|
||||
@@ -1869,6 +1885,12 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
|
||||
if (!unitTarget->IsAlive())
|
||||
return;
|
||||
|
||||
if (unitTarget->HasUnitState(UNIT_STATE_ISOLATED))
|
||||
{
|
||||
m_caster->SendSpellDamageImmune(unitTarget, GetSpellInfo()->Id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS))
|
||||
return;
|
||||
|
||||
@@ -3663,6 +3685,12 @@ void Spell::EffectHealMaxHealth(SpellEffIndex /*effIndex*/)
|
||||
if (!unitTarget || !unitTarget->IsAlive())
|
||||
return;
|
||||
|
||||
if (unitTarget->HasUnitState(UNIT_STATE_ISOLATED))
|
||||
{
|
||||
m_caster->SendSpellDamageImmune(unitTarget, GetSpellInfo()->Id);
|
||||
return;
|
||||
}
|
||||
|
||||
int32 addhealth = 0;
|
||||
|
||||
// damage == 0 - heal for caster max health
|
||||
@@ -4743,8 +4771,8 @@ void Spell::EffectQuestComplete(SpellEffIndex effIndex)
|
||||
uint16 logSlot = player->FindQuestSlot(questId);
|
||||
if (logSlot < MAX_QUEST_LOG_SIZE)
|
||||
player->AreaExploredOrEventHappens(questId);
|
||||
else if (player->CanTakeQuest(quest, false)) // never rewarded before
|
||||
player->CompleteQuest(questId); // quest not in log - for internal use
|
||||
else if (player->CanTakeQuest(quest, false)) // Check if the quest has already been turned in.
|
||||
player->SetRewardedQuest(questId); // If not, set status to rewarded without broadcasting it to client.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1389,18 +1389,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
|
||||
});
|
||||
|
||||
// A'dal's Song of Battle
|
||||
ApplySpellFix({ 39953 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
|
||||
spellInfo->Effects[EFFECT_1].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
|
||||
spellInfo->Effects[EFFECT_2].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
|
||||
spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
|
||||
spellInfo->Effects[EFFECT_1].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
|
||||
spellInfo->Effects[EFFECT_2].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
|
||||
spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(367); // 2 Hours
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
57607, // WintergraspCatapult - Spell Plague Barrel - EffectRadiusIndex
|
||||
57619, // WintergraspDemolisher - Spell Hourl Boulder - EffectRadiusIndex
|
||||
@@ -4856,6 +4844,12 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
|
||||
});
|
||||
|
||||
// Claw Rage
|
||||
ApplySpellFix({ 43149 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].TriggerSpell = 0;
|
||||
});
|
||||
|
||||
// Black Qiraji Battle Tank
|
||||
ApplySpellFix({ 26655, 26656 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "Define.h"
|
||||
#include "Duration.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
constexpr auto AVG_DIFF_COUNT = 500;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "DBCStores.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "QueryResult.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "World.h"
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#define _PLAYER_DUMP_H
|
||||
|
||||
#include "ObjectGuid.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
enum DumpTableType
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Util.h"
|
||||
#include "Warden.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "Player.h"
|
||||
#include "Weather.h"
|
||||
#include "WorldSession.h"
|
||||
#include <memory>
|
||||
|
||||
namespace WeatherMgr
|
||||
{
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
#include "WhoListCacheMgr.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldState.h"
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <cmath>
|
||||
|
||||
@@ -2414,6 +2415,11 @@ void World::Update(uint32 diff)
|
||||
sOutdoorPvPMgr->Update(diff);
|
||||
}
|
||||
|
||||
{
|
||||
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update worldstate"));
|
||||
sWorldState->Update(diff);
|
||||
}
|
||||
|
||||
{
|
||||
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update battlefields"));
|
||||
sBattlefieldMgr->Update(diff);
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
#ifndef __WORLD_H
|
||||
#define __WORLD_H
|
||||
|
||||
#include "DatabaseEnvFwd.h"
|
||||
#include "IWorld.h"
|
||||
#include "LockedQueue.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "QueryResult.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Timer.h"
|
||||
#include <atomic>
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MapMgr.h"
|
||||
#include "Player.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "WorldState.h"
|
||||
|
||||
WorldState* WorldState::instance()
|
||||
{
|
||||
static WorldState instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
WorldState::WorldState() : _isMagtheridonHeadSpawnedHorde(false), _isMagtheridonHeadSpawnedAlliance(false)
|
||||
{
|
||||
_transportStates[WORLD_STATE_CONDITION_THE_IRON_EAGLE] = WORLD_STATE_CONDITION_STATE_NONE;
|
||||
_transportStates[WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS] = WORLD_STATE_CONDITION_STATE_NONE;
|
||||
_transportStates[WORLD_STATE_CONDITION_THE_THUNDERCALLER] = WORLD_STATE_CONDITION_STATE_NONE;
|
||||
}
|
||||
|
||||
WorldState::~WorldState()
|
||||
{
|
||||
}
|
||||
|
||||
bool WorldState::IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state) const
|
||||
{
|
||||
switch (conditionId)
|
||||
{
|
||||
case WORLD_STATE_CONDITION_TROLLBANES_COMMAND:
|
||||
return _isMagtheridonHeadSpawnedAlliance;
|
||||
case WORLD_STATE_CONDITION_NAZGRELS_FAVOR:
|
||||
return _isMagtheridonHeadSpawnedHorde;
|
||||
case WORLD_STATE_CONDITION_THE_IRON_EAGLE:
|
||||
case WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS:
|
||||
case WORLD_STATE_CONDITION_THE_THUNDERCALLER:
|
||||
return _transportStates.at(conditionId) == state;
|
||||
default:
|
||||
LOG_ERROR("scripts", "WorldState::IsConditionFulfilled: Unhandled WorldStateCondition {}", conditionId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldState::HandleConditionStateChange(WorldStateCondition conditionId, WorldStateConditionState state)
|
||||
{
|
||||
_transportStates[conditionId] = state;
|
||||
}
|
||||
|
||||
void WorldState::HandleExternalEvent(WorldStateEvent eventId, uint32 param)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
switch (eventId)
|
||||
{
|
||||
case WORLD_STATE_CUSTOM_EVENT_ON_ADALS_SONG_OF_BATTLE:
|
||||
if (!_adalSongOfBattleTimer)
|
||||
{
|
||||
_adalSongOfBattleTimer = 120 * MINUTE * IN_MILLISECONDS;
|
||||
BuffAdalsSongOfBattle();
|
||||
}
|
||||
break;
|
||||
case WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_SPAWN:
|
||||
if (param == TEAM_ALLIANCE)
|
||||
{
|
||||
_isMagtheridonHeadSpawnedAlliance = true;
|
||||
BuffMagtheridonTeam(TEAM_ALLIANCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isMagtheridonHeadSpawnedHorde = true;
|
||||
BuffMagtheridonTeam(TEAM_HORDE);
|
||||
}
|
||||
break;
|
||||
case WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_DESPAWN:
|
||||
if (param == TEAM_ALLIANCE)
|
||||
{
|
||||
_isMagtheridonHeadSpawnedAlliance = false;
|
||||
DispelMagtheridonTeam(TEAM_ALLIANCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isMagtheridonHeadSpawnedHorde = false;
|
||||
DispelMagtheridonTeam(TEAM_HORDE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldState::Update(uint32 diff)
|
||||
{
|
||||
if (_adalSongOfBattleTimer)
|
||||
{
|
||||
if (_adalSongOfBattleTimer <= diff)
|
||||
{
|
||||
_adalSongOfBattleTimer = 0;
|
||||
DispelAdalsSongOfBattle();
|
||||
}
|
||||
else
|
||||
{
|
||||
_adalSongOfBattleTimer -= diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldState::HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
switch (zoneId)
|
||||
{
|
||||
case ZONEID_SHATTRATH:
|
||||
case ZONEID_BOTANICA:
|
||||
case ZONEID_MECHANAR:
|
||||
case ZONEID_ARCATRAZ:
|
||||
if (_adalSongOfBattleTimer)
|
||||
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
|
||||
break;
|
||||
case ZONEID_HELLFIRE_PENINSULA:
|
||||
case ZONEID_HELLFIRE_RAMPARTS:
|
||||
case ZONEID_HELLFIRE_CITADEL:
|
||||
case ZONEID_BLOOD_FURNACE:
|
||||
case ZONEID_SHATTERED_HALLS:
|
||||
case ZONEID_MAGTHERIDON_LAIR:
|
||||
if (_isMagtheridonHeadSpawnedAlliance && player->GetTeamId() == TEAM_ALLIANCE)
|
||||
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
|
||||
else if (_isMagtheridonHeadSpawnedHorde && player->GetTeamId() == TEAM_HORDE)
|
||||
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
void WorldState::HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
switch (zoneId)
|
||||
{
|
||||
case ZONEID_SHATTRATH:
|
||||
case ZONEID_BOTANICA:
|
||||
case ZONEID_MECHANAR:
|
||||
case ZONEID_ARCATRAZ:
|
||||
if (!_adalSongOfBattleTimer)
|
||||
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
|
||||
break;
|
||||
case ZONEID_HELLFIRE_PENINSULA:
|
||||
case ZONEID_HELLFIRE_RAMPARTS:
|
||||
case ZONEID_HELLFIRE_CITADEL:
|
||||
case ZONEID_BLOOD_FURNACE:
|
||||
case ZONEID_SHATTERED_HALLS:
|
||||
case ZONEID_MAGTHERIDON_LAIR:
|
||||
if (player->GetTeamId() == TEAM_ALLIANCE)
|
||||
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
|
||||
else if (player->GetTeamId() == TEAM_HORDE)
|
||||
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
void WorldState::BuffMagtheridonTeam(TeamId team)
|
||||
{
|
||||
sMapMgr->DoForAllMaps([&](Map* map) -> void
|
||||
{
|
||||
switch (map->GetId())
|
||||
{
|
||||
case 530: // Outland
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
|
||||
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
|
||||
else if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
|
||||
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
|
||||
});
|
||||
break;
|
||||
case 540: // The Shattered Halls
|
||||
case 542: // The Blood Furnace
|
||||
case 543: // Ramparts
|
||||
case 544: // Magtheridon's Lair
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
|
||||
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
|
||||
else if (player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
|
||||
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WorldState::DispelMagtheridonTeam(TeamId team)
|
||||
{
|
||||
sMapMgr->DoForAllMaps([&](Map* map) -> void
|
||||
{
|
||||
switch (map->GetId())
|
||||
{
|
||||
case 530: // Outland
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
|
||||
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
|
||||
else if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
|
||||
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
|
||||
});
|
||||
break;
|
||||
case 540: // The Shattered Halls
|
||||
case 542: // The Blood Furnace
|
||||
case 543: // Ramparts
|
||||
case 544: // Magtheridon's Lair
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
|
||||
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
|
||||
else if (player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
|
||||
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WorldState::BuffAdalsSongOfBattle()
|
||||
{
|
||||
sMapMgr->DoForAllMaps([&](Map* map) -> void
|
||||
{
|
||||
switch (map->GetId())
|
||||
{
|
||||
case 530: // Outland
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetZoneId() == ZONEID_SHATTRATH)
|
||||
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
|
||||
});
|
||||
break;
|
||||
case 552: // Arcatraz
|
||||
case 553: // Botanica
|
||||
case 554: // Mechanar
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WorldState::DispelAdalsSongOfBattle()
|
||||
{
|
||||
sMapMgr->DoForAllMaps([&](Map* map) -> void
|
||||
{
|
||||
switch (map->GetId())
|
||||
{
|
||||
case 530: // Outland
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetZoneId() == ZONEID_SHATTRATH)
|
||||
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
|
||||
});
|
||||
break;
|
||||
case 552: // Arcatraz
|
||||
case 553: // Botanica
|
||||
case 554: // Mechanar
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WORLD_STATE_H
|
||||
#define WORLD_STATE_H
|
||||
|
||||
#include "Player.h"
|
||||
#include <atomic>
|
||||
|
||||
enum WorldStateCondition
|
||||
{
|
||||
WORLD_STATE_CONDITION_TROLLBANES_COMMAND = 39911,
|
||||
WORLD_STATE_CONDITION_NAZGRELS_FAVOR = 39913,
|
||||
// Zeppelins
|
||||
WORLD_STATE_CONDITION_THE_THUNDERCALLER = 164871,
|
||||
WORLD_STATE_CONDITION_THE_IRON_EAGLE = 175080,
|
||||
WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS = 176495,
|
||||
};
|
||||
|
||||
enum WorldStateConditionState
|
||||
{
|
||||
WORLD_STATE_CONDITION_STATE_NONE = 0,
|
||||
};
|
||||
|
||||
enum WorldStateEvent
|
||||
{
|
||||
WORLD_STATE_CUSTOM_EVENT_ON_ADALS_SONG_OF_BATTLE = 39953,
|
||||
WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_SPAWN = 184640,
|
||||
WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_DESPAWN = 184641,
|
||||
};
|
||||
|
||||
enum WorldStateZoneId
|
||||
{
|
||||
ZONEID_SHATTRATH = 3703,
|
||||
ZONEID_BOTANICA = 3847,
|
||||
ZONEID_ARCATRAZ = 3848,
|
||||
ZONEID_MECHANAR = 3849,
|
||||
|
||||
ZONEID_HELLFIRE_PENINSULA = 3483,
|
||||
ZONEID_HELLFIRE_RAMPARTS = 3562,
|
||||
ZONEID_HELLFIRE_CITADEL = 3563,
|
||||
ZONEID_BLOOD_FURNACE = 3713,
|
||||
ZONEID_SHATTERED_HALLS = 3714,
|
||||
ZONEID_MAGTHERIDON_LAIR = 3836,
|
||||
};
|
||||
|
||||
enum WorldStateSpells
|
||||
{
|
||||
SPELL_ADAL_SONG_OF_BATTLE = 39953,
|
||||
|
||||
SPELL_TROLLBANES_COMMAND = 39911,
|
||||
SPELL_NAZGRELS_FAVOR = 39913,
|
||||
};
|
||||
|
||||
// Intended for implementing server wide scripts, note: all behaviour must be safeguarded towards multithreading
|
||||
class WorldState
|
||||
{
|
||||
public:
|
||||
WorldState();
|
||||
virtual ~WorldState();
|
||||
static WorldState* instance();
|
||||
void HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId);
|
||||
void HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId);
|
||||
bool IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state = WORLD_STATE_CONDITION_STATE_NONE) const;
|
||||
void HandleConditionStateChange(WorldStateCondition conditionId, WorldStateConditionState state);
|
||||
void HandleExternalEvent(WorldStateEvent eventId, uint32 param);
|
||||
void Update(uint32 diff);
|
||||
private:
|
||||
void BuffAdalsSongOfBattle();
|
||||
void DispelAdalsSongOfBattle();
|
||||
uint32 _adalSongOfBattleTimer;
|
||||
void BuffMagtheridonTeam(TeamId team);
|
||||
void DispelMagtheridonTeam(TeamId team);
|
||||
bool _isMagtheridonHeadSpawnedHorde;
|
||||
bool _isMagtheridonHeadSpawnedAlliance;
|
||||
std::map<WorldStateCondition, std::atomic<WorldStateConditionState>> _transportStates; // atomic to avoid having to lock
|
||||
std::mutex _mutex; // all World State operations are threat unsafe
|
||||
};
|
||||
|
||||
#define sWorldState WorldState::instance()
|
||||
#endif
|
||||
@@ -32,7 +32,6 @@ EndScriptData */
|
||||
#include "MapMgr.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "Random.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "Language.h"
|
||||
#include "MapMgr.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "MMapFactory.h"
|
||||
#include "MovementGenerator.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Pet.h"
|
||||
@@ -1157,19 +1158,15 @@ public:
|
||||
static bool HandleReviveCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
if (!target)
|
||||
{
|
||||
target = PlayerIdentifier::FromTargetOrSelf(handler);
|
||||
}
|
||||
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target->IsConnected())
|
||||
{
|
||||
auto targetPlayer = target->GetConnectedPlayer();
|
||||
|
||||
targetPlayer->RemoveAurasDueToSpell(27827); // Spirit of Redemption
|
||||
targetPlayer->ResurrectPlayer(!AccountMgr::IsPlayerAccount(targetPlayer->GetSession()->GetSecurity()) ? 1.0f : 0.5f);
|
||||
targetPlayer->SpawnCorpseBones();
|
||||
targetPlayer->SaveToDB(false, false);
|
||||
|
||||
@@ -484,6 +484,9 @@ public:
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
if (!player->GetSelectedUnit())
|
||||
return false;
|
||||
|
||||
Creature* creature = player->GetSelectedUnit()->ToCreature();
|
||||
|
||||
if (!creature)
|
||||
|
||||
@@ -62,13 +62,20 @@ public:
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_summonedRend = false;
|
||||
if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS)
|
||||
{
|
||||
instance->SetBossState(DATA_GYTH, NOT_STARTED);
|
||||
summons.DespawnAll();
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
SetInvincibility(true); // Don't let boss die before summoning Rend.
|
||||
|
||||
ScheduleHealthCheckEvent(25, [&] {
|
||||
DoCastAOE(SPELL_SUMMON_REND, true);
|
||||
me->RemoveAura(SPELL_REND_MOUNTS);
|
||||
SetInvincibility(false);
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
@@ -104,21 +111,6 @@ public:
|
||||
instance->SetBossState(DATA_GYTH, DONE);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
|
||||
{
|
||||
if (!_summonedRend && me->HealthBelowPctDamaged(25, damage))
|
||||
{
|
||||
if (damage >= me->GetHealth())
|
||||
{
|
||||
// Let creature fall to 1 HP but prevent it from dying before boss is summoned.
|
||||
damage = me->GetHealth() - 1;
|
||||
}
|
||||
DoCast(me, SPELL_SUMMON_REND, true);
|
||||
me->RemoveAura(SPELL_REND_MOUNTS);
|
||||
_summonedRend = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
@@ -173,9 +165,6 @@ public:
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool _summonedRend;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
|
||||
@@ -37,8 +37,7 @@ enum Says
|
||||
enum Spells
|
||||
{
|
||||
// Phase 1
|
||||
SPELL_FIREBALL_N = 44189,
|
||||
SPELL_FIREBALL_H = 46164,
|
||||
SPELL_FIREBALL = 44189,
|
||||
SPELL_FLAMESTRIKE_SUMMON = 44192,
|
||||
SPELL_PHOENIX = 44194,
|
||||
SPELL_SHOCK_BARRIER = 46165,
|
||||
@@ -119,11 +118,10 @@ struct boss_felblood_kaelthas : public ScriptedAI
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
instance->SetBossState(DATA_KAELTHAS, DONE);
|
||||
summons.DespawnAll();
|
||||
|
||||
if (GameObject* orb = instance->GetGameObject(DATA_ESCAPE_ORB))
|
||||
{
|
||||
orb->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
@@ -218,7 +216,7 @@ struct boss_felblood_kaelthas : public ScriptedAI
|
||||
switch (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_FIREBALL:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_FIREBALL_N, SPELL_FIREBALL_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_FIREBALL, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_FIREBALL, urand(3000, 4500));
|
||||
break;
|
||||
case EVENT_SPELL_FLAMESTRIKE:
|
||||
|
||||
@@ -32,12 +32,9 @@ enum Spells
|
||||
SPELL_MEDALION_OF_IMMUNITY = 46227,
|
||||
SPELL_DISPEL_MAGIC = 27609,
|
||||
SPELL_FLASH_HEAL = 17843,
|
||||
SPELL_SHADOW_WORD_PAIN_N = 14032,
|
||||
SPELL_SHADOW_WORD_PAIN_H = 15654,
|
||||
SPELL_POWER_WORD_SHIELD_N = 44291,
|
||||
SPELL_POWER_WORD_SHIELD_H = 46193,
|
||||
SPELL_RENEW_N = 44174,
|
||||
SPELL_RENEW_H = 46192,
|
||||
SPELL_SHADOW_WORD_PAIN = 14032,
|
||||
SPELL_POWER_WORD_SHIELD = 44291,
|
||||
SPELL_RENEW = 44174
|
||||
};
|
||||
|
||||
enum Misc
|
||||
@@ -196,14 +193,14 @@ struct boss_priestess_delrissa : public ScriptedAI
|
||||
break;
|
||||
case EVENT_SPELL_RENEW:
|
||||
if (Unit* target = DoSelectLowestHpFriendly(40.0f, 1000))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_RENEW_N, SPELL_RENEW_H), false);
|
||||
me->CastSpell(target, SPELL_RENEW, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_RENEW, 7000);
|
||||
break;
|
||||
case EVENT_SPELL_PW_SHIELD:
|
||||
{
|
||||
std::list<Creature*> cList = DoFindFriendlyMissingBuff(40.0f, DUNGEON_MODE(SPELL_POWER_WORD_SHIELD_N, SPELL_POWER_WORD_SHIELD_H));
|
||||
std::list<Creature*> cList = DoFindFriendlyMissingBuff(40.0f, SPELL_POWER_WORD_SHIELD);
|
||||
if (Unit* target = Acore::Containers::SelectRandomContainerElement(cList))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_POWER_WORD_SHIELD_N, SPELL_POWER_WORD_SHIELD_H), false);
|
||||
me->CastSpell(target, SPELL_POWER_WORD_SHIELD, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_PW_SHIELD, 10000);
|
||||
break;
|
||||
}
|
||||
@@ -239,7 +236,7 @@ struct boss_priestess_delrissa : public ScriptedAI
|
||||
break;
|
||||
case EVENT_SPELL_SW_PAIN:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30.0f))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_SHADOW_WORD_PAIN_N, SPELL_SHADOW_WORD_PAIN_H), false);
|
||||
me->CastSpell(target, SPELL_SHADOW_WORD_PAIN, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SW_PAIN, 10000);
|
||||
break;
|
||||
}
|
||||
@@ -397,10 +394,8 @@ enum RogueEnum
|
||||
SPELL_VANISH = 44290,
|
||||
SPELL_GOUGE = 12540,
|
||||
SPELL_KICK = 27613,
|
||||
SPELL_BACKSTAB_N = 15657,
|
||||
SPELL_BACKSTAB_H = 15582,
|
||||
SPELL_EVISCERATE_N = 27611,
|
||||
SPELL_EVISCERATE_H = 46189,
|
||||
SPELL_BACKSTAB = 15657,
|
||||
SPELL_EVISCERATE = 27611,
|
||||
|
||||
EVENT_SPELL_GOUGE = 1,
|
||||
EVENT_SPELL_KICK = 2,
|
||||
@@ -461,13 +456,13 @@ struct boss_kagani_nightstrike : public boss_priestess_lackey_commonAI
|
||||
events.ScheduleEvent(EVENT_SPELL_KICK, 1000);
|
||||
break;
|
||||
case EVENT_SPELL_EVISCERATE:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_EVISCERATE_N, SPELL_EVISCERATE_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_EVISCERATE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_EVISCERATE, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_BACKSTAB:
|
||||
if (!me->GetVictim()->HasInArc(static_cast<float>(M_PI), me))
|
||||
{
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_BACKSTAB_N, SPELL_BACKSTAB_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_BACKSTAB, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_BACKSTAB, 5000);
|
||||
}
|
||||
else
|
||||
@@ -481,12 +476,9 @@ struct boss_kagani_nightstrike : public boss_priestess_lackey_commonAI
|
||||
|
||||
enum WarlockEnum
|
||||
{
|
||||
SPELL_IMMOLATE_N = 44267,
|
||||
SPELL_IMMOLATE_H = 46191,
|
||||
SPELL_SHADOW_BOLT_N = 12471,
|
||||
SPELL_SHADOW_BOLT_H = 15232,
|
||||
SPELL_CURSE_OF_AGONY_N = 14875,
|
||||
SPELL_CURSE_OF_AGONY_H = 46190,
|
||||
SPELL_IMMOLATE = 44267,
|
||||
SPELL_SHADOW_BOLT = 12471,
|
||||
SPELL_CURSE_OF_AGONY = 14875,
|
||||
SPELL_SEED_OF_CORRUPTION = 44141,
|
||||
SPELL_FEAR = 38595,
|
||||
SPELL_SUMMON_IMP = 44163,
|
||||
@@ -525,11 +517,11 @@ struct boss_ellris_duskhallow : public boss_priestess_lackey_commonAI
|
||||
{
|
||||
case EVENT_SPELL_IMMOLATE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30.0f))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_IMMOLATE_N, SPELL_IMMOLATE_H), false);
|
||||
me->CastSpell(target, SPELL_IMMOLATE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 12000);
|
||||
break;
|
||||
case EVENT_SPELL_SHADOW_BOLT:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_SHADOW_BOLT_N, SPELL_SHADOW_BOLT_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, 5000);
|
||||
break;
|
||||
case EVENT_SPELL_SEED_OF_CORRUPTION:
|
||||
@@ -539,7 +531,7 @@ struct boss_ellris_duskhallow : public boss_priestess_lackey_commonAI
|
||||
break;
|
||||
case EVENT_SPELL_CURSE_OF_AGONY:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30.0f))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_CURSE_OF_AGONY_N, SPELL_CURSE_OF_AGONY_H), false);
|
||||
me->CastSpell(target, SPELL_CURSE_OF_AGONY, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CURSE_OF_AGONY, 13000);
|
||||
break;
|
||||
case EVENT_SPELL_FEAR:
|
||||
@@ -555,8 +547,7 @@ struct boss_ellris_duskhallow : public boss_priestess_lackey_commonAI
|
||||
|
||||
enum MonkEnum
|
||||
{
|
||||
SPELL_KNOCKDOWN_N = 11428,
|
||||
SPELL_KNOCKDOWN_H = 46183,
|
||||
SPELL_KNOCKDOWN = 11428,
|
||||
SPELL_SNAP_KICK = 46182,
|
||||
SPELL_FISTS_OF_ARCANE = 44120,
|
||||
|
||||
@@ -588,7 +579,7 @@ struct boss_eramas_brightblaze : public boss_priestess_lackey_commonAI
|
||||
switch (actualEventId)
|
||||
{
|
||||
case EVENT_SPELL_KNOCKDOWN:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_KNOCKDOWN_N, SPELL_KNOCKDOWN_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_KNOCKDOWN, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_KNOCKDOWN, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_SNAP_KICK:
|
||||
@@ -609,14 +600,10 @@ enum MageEnum
|
||||
{
|
||||
SPELL_POLYMORPH = 13323,
|
||||
SPELL_ICE_BLOCK = 27619,
|
||||
SPELL_BLIZZARD_N = 44178,
|
||||
SPELL_BLIZZARD_H = 46195,
|
||||
SPELL_ICE_LANCE_N = 44176,
|
||||
SPELL_ICE_LANCE_H = 46194,
|
||||
SPELL_CONE_OF_COLD_N = 38384,
|
||||
SPELL_CONE_OF_COLD_H = 12611,
|
||||
SPELL_FROSTBOLT_N = 15043,
|
||||
SPELL_FROSTBOLT_H = 15530,
|
||||
SPELL_BLIZZARD = 44178,
|
||||
SPELL_ICE_LANCE = 44176,
|
||||
SPELL_CONE_OF_COLD = 12611,
|
||||
SPELL_FROSTBOLT = 15043,
|
||||
SPELL_BLINK = 14514,
|
||||
|
||||
EVENT_SPELL_POLYMORPH = 1,
|
||||
@@ -669,19 +656,19 @@ struct boss_yazzai : public boss_priestess_lackey_commonAI
|
||||
break;
|
||||
case EVENT_SPELL_BLIZZARD:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_BLIZZARD_N, SPELL_BLIZZARD_H), false);
|
||||
me->CastSpell(target, SPELL_BLIZZARD, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_BLIZZARD, 20000);
|
||||
break;
|
||||
case EVENT_SPELL_ICE_LANCE:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_ICE_LANCE_N, SPELL_ICE_LANCE_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_ICE_LANCE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_ICE_LANCE, 12000);
|
||||
break;
|
||||
case EVENT_SPELL_COC:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_CONE_OF_COLD_N, SPELL_CONE_OF_COLD_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_CONE_OF_COLD, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_COC, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_FROSTBOLT:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_FROSTBOLT_N, SPELL_FROSTBOLT_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_FROSTBOLT, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_FROSTBOLT, 8000);
|
||||
break;
|
||||
case EVENT_SPELL_BLINK:
|
||||
@@ -784,8 +771,7 @@ struct boss_warlord_salaris : public boss_priestess_lackey_commonAI
|
||||
enum HunterEnum
|
||||
{
|
||||
SPELL_AIMED_SHOT = 44271,
|
||||
SPELL_SHOOT_N = 15620,
|
||||
SPELL_SHOOT_H = 22907,
|
||||
SPELL_SHOOT = 15620,
|
||||
SPELL_CONCUSSIVE_SHOT = 27634,
|
||||
SPELL_MULTI_SHOT = 31942,
|
||||
SPELL_WING_CLIP = 44286,
|
||||
@@ -848,7 +834,7 @@ struct boss_garaxxas : public boss_priestess_lackey_commonAI
|
||||
events.ScheduleEvent(EVENT_SPELL_MULTI_SHOT, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_SHOOT:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_SHOOT_N, SPELL_SHOOT_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHOOT, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHOOT, 2500);
|
||||
break;
|
||||
}
|
||||
@@ -864,10 +850,8 @@ enum ShamanEnum
|
||||
SPELL_EARTHBIND_TOTEM = 15786,
|
||||
SPELL_WAR_STOMP = 46026,
|
||||
SPELL_PURGE = 27626,
|
||||
SPELL_LESSER_HEALING_WAVE_N = 44256,
|
||||
SPELL_LESSER_HEALING_WAVE_H = 46181,
|
||||
SPELL_FROST_SHOCK_N = 21401,
|
||||
SPELL_FROST_SHOCK_H = 46180,
|
||||
SPELL_LESSER_HEALING_WAVE = 44256,
|
||||
SPELL_FROST_SHOCK = 21401,
|
||||
|
||||
EVENT_SPELL_TOTEM1 = 1,
|
||||
EVENT_SPELL_TOTEM2 = 2,
|
||||
@@ -933,12 +917,12 @@ struct boss_apoko : public boss_priestess_lackey_commonAI
|
||||
events.ScheduleEvent(EVENT_SPELL_PURGE, 15000);
|
||||
break;
|
||||
case EVENT_SPELL_FROST_SHOCK:
|
||||
me->CastSpell(me, DUNGEON_MODE(SPELL_FROST_SHOCK_N, SPELL_FROST_SHOCK_H), false);
|
||||
me->CastSpell(me, SPELL_FROST_SHOCK, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_FROST_SHOCK, 12000);
|
||||
break;
|
||||
case EVENT_SPELL_HEALING_WAVE:
|
||||
if (Unit* target = DoSelectLowestHpFriendly(40.0f, 1000))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_LESSER_HEALING_WAVE_N, SPELL_LESSER_HEALING_WAVE_H), false);
|
||||
me->CastSpell(target, SPELL_LESSER_HEALING_WAVE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_HEALING_WAVE, 12000);
|
||||
break;
|
||||
}
|
||||
@@ -949,12 +933,9 @@ struct boss_apoko : public boss_priestess_lackey_commonAI
|
||||
|
||||
enum EngineerEnum
|
||||
{
|
||||
SPELL_GOBLIN_DRAGON_GUN_N = 44272,
|
||||
SPELL_GOBLIN_DRAGON_GUN_H = 46186,
|
||||
SPELL_ROCKET_LAUNCH_N = 44137,
|
||||
SPELL_ROCKET_LAUNCH_H = 46187,
|
||||
SPELL_FEL_IRON_BOMB_N = 46024,
|
||||
SPELL_FEL_IRON_BOMB_H = 46184,
|
||||
SPELL_GOBLIN_DRAGON_GUN = 44272,
|
||||
SPELL_ROCKET_LAUNCH = 44137,
|
||||
SPELL_FEL_IRON_BOMB = 46024,
|
||||
SPELL_RECOMBOBULATE = 44274,
|
||||
SPELL_HIGH_EXPLOSIVE_SHEEP = 44276,
|
||||
|
||||
@@ -990,16 +971,16 @@ struct boss_zelfan : public boss_priestess_lackey_commonAI
|
||||
switch (actualEventId)
|
||||
{
|
||||
case EVENT_SPELL_DRAGON_GUN:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_GOBLIN_DRAGON_GUN_N, SPELL_GOBLIN_DRAGON_GUN_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_GOBLIN_DRAGON_GUN, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_DRAGON_GUN, 20000);
|
||||
break;
|
||||
case EVENT_SPELL_ROCKET_LAUNCH:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_ROCKET_LAUNCH_N, SPELL_ROCKET_LAUNCH_H), false);
|
||||
me->CastSpell(me->GetVictim(), SPELL_ROCKET_LAUNCH, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_ROCKET_LAUNCH, 20000);
|
||||
break;
|
||||
case EVENT_SPELL_IRON_BOMB:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 15.0f))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_FEL_IRON_BOMB_N, SPELL_FEL_IRON_BOMB_H), false);
|
||||
me->CastSpell(target, SPELL_FEL_IRON_BOMB, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_IRON_BOMB, 20000);
|
||||
break;
|
||||
case EVENT_SPELL_RECOMBOBULATE:
|
||||
|
||||
@@ -36,8 +36,7 @@ enum Spells
|
||||
SPELL_MANA_RAGE_TRIGGER = 44321,
|
||||
|
||||
//Selin's spells
|
||||
SPELL_DRAIN_LIFE_N = 44294,
|
||||
SPELL_DRAIN_LIFE_H = 46155,
|
||||
SPELL_DRAIN_LIFE = 44294,
|
||||
SPELL_FEL_EXPLOSION = 44314,
|
||||
SPELL_DRAIN_MANA = 46153
|
||||
};
|
||||
@@ -181,7 +180,7 @@ struct boss_selin_fireheart : public ScriptedAI
|
||||
{
|
||||
case EVENT_SPELL_DRAIN_LIFE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_DRAIN_LIFE_N, SPELL_DRAIN_LIFE_H), false);
|
||||
me->CastSpell(target, SPELL_DRAIN_LIFE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_DRAIN_LIFE, 10000, 1);
|
||||
return;
|
||||
case EVENT_SPELL_DRAIN_MANA:
|
||||
|
||||
@@ -35,11 +35,9 @@ enum Spells
|
||||
SPELL_ENERGY_FEEDBACK = 44335,
|
||||
|
||||
// Vexallus spell info
|
||||
SPELL_CHAIN_LIGHTNING_N = 44318,
|
||||
SPELL_CHAIN_LIGHTNING_H = 46380,
|
||||
SPELL_CHAIN_LIGHTNING = 44318,
|
||||
SPELL_OVERLOAD = 44352,
|
||||
SPELL_ARCANE_SHOCK_N = 44319,
|
||||
SPELL_ARCANE_SHOCK_H = 46381,
|
||||
SPELL_ARCANE_SHOCK = 44319,
|
||||
|
||||
SPELL_SUMMON_PURE_ENERGY_N = 44322,
|
||||
SPELL_SUMMON_PURE_ENERGY_H1 = 46154,
|
||||
@@ -93,12 +91,12 @@ struct boss_vexallus : public BossAI
|
||||
|
||||
ScheduleTimedEvent(8s, [&]
|
||||
{
|
||||
DoCastRandomTarget(DUNGEON_MODE(SPELL_CHAIN_LIGHTNING_N, SPELL_CHAIN_LIGHTNING_H));
|
||||
DoCastRandomTarget(SPELL_CHAIN_LIGHTNING);
|
||||
}, 8s, 8s);
|
||||
|
||||
ScheduleTimedEvent(5s, [&]
|
||||
{
|
||||
DoCastRandomTarget(DUNGEON_MODE(SPELL_ARCANE_SHOCK_N, SPELL_ARCANE_SHOCK_H));
|
||||
DoCastRandomTarget(SPELL_ARCANE_SHOCK);
|
||||
}, 8s, 8s);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_KAEL_THAS, DATA_KAELTHAS },
|
||||
{ NPC_KALECGOS, DATA_KALECGOS },
|
||||
{ 0, 0 }
|
||||
};
|
||||
@@ -59,27 +60,19 @@ public:
|
||||
LoadDoorData(doorData);
|
||||
}
|
||||
|
||||
ObjectGuid EscapeOrbGUID;
|
||||
|
||||
ObjectGuid DelrissaGUID;
|
||||
ObjectGuid KaelGUID;
|
||||
|
||||
void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override
|
||||
{
|
||||
if (eventId == EVENT_SPAWN_KALECGOS)
|
||||
{
|
||||
if (!GetCreature(DATA_KALECGOS) && !scheduler.IsGroupScheduled(DATA_KALECGOS))
|
||||
{
|
||||
scheduler.Schedule(1min, 1min, DATA_KALECGOS,[this](TaskContext)
|
||||
{
|
||||
if (Creature* kalecgos = instance->SummonCreature(NPC_KALECGOS, KalecgosSpawnPos))
|
||||
{
|
||||
kalecgos->GetMotionMaster()->MovePath(PATH_KALECGOS_FLIGHT, false);
|
||||
kalecgos->AI()->Talk(SAY_KALECGOS_SPAWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
@@ -89,12 +82,9 @@ public:
|
||||
case NPC_DELRISSA:
|
||||
DelrissaGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_KAEL_THAS:
|
||||
KaelGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_PHOENIX:
|
||||
case NPC_PHOENIX_EGG:
|
||||
if (Creature* kael = instance->GetCreature(KaelGUID))
|
||||
if (Creature* kael = GetCreature(DATA_KAELTHAS))
|
||||
kael->AI()->JustSummoned(creature);
|
||||
break;
|
||||
}
|
||||
@@ -105,9 +95,7 @@ public:
|
||||
ObjectGuid GetGuidData(uint32 identifier) const override
|
||||
{
|
||||
if (identifier == NPC_DELRISSA)
|
||||
{
|
||||
return DelrissaGUID;
|
||||
}
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
@@ -119,53 +107,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_KALECGOS_TRANSFORM = 44670,
|
||||
SPELL_TRANSFORM_VISUAL = 24085,
|
||||
SPELL_CAMERA_SHAKE = 44762,
|
||||
SPELL_ORB_KILL_CREDIT = 46307
|
||||
};
|
||||
|
||||
enum MovementPoints
|
||||
{
|
||||
POINT_ID_PREPARE_LANDING = 6
|
||||
};
|
||||
|
||||
struct npc_kalecgos : public ScriptedAI
|
||||
{
|
||||
npc_kalecgos(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void MovementInform(uint32 type, uint32 pointId) override
|
||||
{
|
||||
if (type != WAYPOINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (pointId == POINT_ID_PREPARE_LANDING)
|
||||
{
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetHover(false);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
DoCastAOE(SPELL_CAMERA_SHAKE);
|
||||
me->SetObjectScale(0.6f);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
DoCastSelf(SPELL_ORB_KILL_CREDIT, true);
|
||||
DoCastSelf(SPELL_TRANSFORM_VISUAL);
|
||||
DoCastSelf(SPELL_KALECGOS_TRANSFORM);
|
||||
me->UpdateEntry(NPC_HUMAN_KALECGOS);
|
||||
}, 1s);
|
||||
}, 2s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_magisters_terrace()
|
||||
{
|
||||
new instance_magisters_terrace();
|
||||
RegisterMagistersTerraceCreatureAI(npc_kalecgos);
|
||||
}
|
||||
|
||||
@@ -42,8 +42,7 @@ enum MTCreatures
|
||||
NPC_KAEL_THAS = 24664,
|
||||
NPC_PHOENIX = 21362,
|
||||
NPC_PHOENIX_EGG = 21364,
|
||||
NPC_KALECGOS = 24844,
|
||||
NPC_HUMAN_KALECGOS = 24848
|
||||
NPC_KALECGOS = 24844
|
||||
};
|
||||
|
||||
enum MTGameObjects
|
||||
@@ -61,11 +60,6 @@ enum InstanceEventIds
|
||||
EVENT_SPAWN_KALECGOS = 16547
|
||||
};
|
||||
|
||||
enum InstanceText
|
||||
{
|
||||
SAY_KALECGOS_SPAWN = 0
|
||||
};
|
||||
|
||||
enum MovementData
|
||||
{
|
||||
PATH_KALECGOS_FLIGHT = 248440
|
||||
|
||||
@@ -63,106 +63,66 @@ enum Misc
|
||||
ACTION_SPAWN_FELMYST = 2
|
||||
};
|
||||
|
||||
class boss_brutallus : public CreatureScript
|
||||
struct boss_brutallus : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_brutallus() : CreatureScript("boss_brutallus") { }
|
||||
boss_brutallus(Creature* creature) : BossAI(creature, DATA_BRUTALLUS) { }
|
||||
|
||||
struct boss_brutallusAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_brutallusAI(Creature* creature) : BossAI(creature, DATA_BRUTALLUS) { }
|
||||
BossAI::Reset();
|
||||
DoCastSelf(SPELL_DUAL_WIELD, true);
|
||||
me->m_Events.KillAllEvents(false);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->CastSpell(me, SPELL_DUAL_WIELD, true);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (me->GetReactState() == REACT_PASSIVE && (!who || who->GetEntry() != NPC_MADRIGOSA))
|
||||
{
|
||||
if (who)
|
||||
Unit::Kill(me, who);
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
if (who->GetEntry() == NPC_MADRIGOSA)
|
||||
return;
|
||||
|
||||
Talk(YELL_AGGRO);
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_SLASH, 11000);
|
||||
events.ScheduleEvent(EVENT_SPELL_STOMP, 30000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BURN, 45000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BERSERK, 360000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && roll_chance_i(50))
|
||||
Talk(YELL_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
BossAI::JustDied(killer);
|
||||
Talk(YELL_DEATH);
|
||||
|
||||
me->CastSpell(me, SPELL_SUMMON_BRUTALLUS_DEATH_CLOUD, true);
|
||||
if (Creature* madrigosa = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_MADRIGOSA)))
|
||||
madrigosa->AI()->DoAction(ACTION_SPAWN_FELMYST);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (who->GetEntry() == NPC_MADRIGOSA)
|
||||
return;
|
||||
BossAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_SLASH:
|
||||
me->CastSpell(me->GetVictim(), SPELL_METEOR_SLASH, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SLASH, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_STOMP:
|
||||
me->CastSpell(me->GetVictim(), SPELL_STOMP, false);
|
||||
Talk(YELL_LOVE);
|
||||
events.ScheduleEvent(EVENT_SPELL_STOMP, 30000);
|
||||
break;
|
||||
case EVENT_SPELL_BURN:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, true, -SPELL_BURN_DAMAGE))
|
||||
me->CastSpell(target, SPELL_BURN, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_BURN, 60000);
|
||||
break;
|
||||
case EVENT_SPELL_BERSERK:
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
Talk(YELL_BERSERK);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_brutallusAI>(creature);
|
||||
if (who->GetEntry() == NPC_MADRIGOSA)
|
||||
return;
|
||||
|
||||
Talk(YELL_AGGRO);
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
ScheduleTimedEvent(11s, [&] {
|
||||
DoCastVictim(SPELL_METEOR_SLASH);
|
||||
}, 10s);
|
||||
|
||||
ScheduleTimedEvent(30s, [&] {
|
||||
DoCastVictim(SPELL_STOMP);
|
||||
Talk(YELL_LOVE);
|
||||
}, 30s);
|
||||
|
||||
ScheduleTimedEvent(45s, [&] {
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, true, -SPELL_BURN_DAMAGE))
|
||||
DoCast(target, SPELL_BURN);
|
||||
}, 1min);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
DoCastSelf(SPELL_BERSERK, true);
|
||||
Talk(YELL_BERSERK);
|
||||
}, 6min);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && roll_chance_i(50))
|
||||
Talk(YELL_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
BossAI::JustDied(killer);
|
||||
Talk(YELL_DEATH);
|
||||
|
||||
DoCastAOE(SPELL_SUMMON_BRUTALLUS_DEATH_CLOUD, true);
|
||||
if (Creature* madrigosa = instance->GetCreature(DATA_MADRIGOSA))
|
||||
madrigosa->AI()->DoAction(ACTION_SPAWN_FELMYST);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (who->GetEntry() == NPC_MADRIGOSA)
|
||||
return;
|
||||
BossAI::AttackStart(who);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -210,203 +170,193 @@ enum eMadrigosa
|
||||
SPELL_BRUTALLUS_BREAK_ICE = 46637,
|
||||
};
|
||||
|
||||
class npc_madrigosa : public CreatureScript
|
||||
struct npc_madrigosa : public NullCreatureAI
|
||||
{
|
||||
public:
|
||||
npc_madrigosa() : CreatureScript("npc_madrigosa") { }
|
||||
|
||||
struct npc_madrigosaAI : public NullCreatureAI
|
||||
npc_madrigosa(Creature* creature) : NullCreatureAI(creature)
|
||||
{
|
||||
npc_madrigosaAI(Creature* creature) : NullCreatureAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
bool appear = instance->GetBossState(DATA_BRUTALLUS) != DONE && instance->GetBossState(DATA_MADRIGOSA) == DONE;
|
||||
creature->SetVisible(appear);
|
||||
creature->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
creature->SetDynamicFlag(UNIT_DYNFLAG_DEAD);
|
||||
}
|
||||
instance = creature->GetInstanceScript();
|
||||
creature->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
creature->SetDynamicFlag(UNIT_DYNFLAG_DEAD);
|
||||
|
||||
EventMap events;
|
||||
InstanceScript* instance;
|
||||
if (instance->IsBossDone(DATA_BRUTALLUS))
|
||||
creature->SetVisible(false);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_START_EVENT)
|
||||
{
|
||||
me->SetDisableGravity(true);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->RemoveDynamicFlag(UNIT_DYNFLAG_DEAD);
|
||||
me->NearTeleportTo(1570.97f, 725.51f, 79.77f, 3.82f);
|
||||
events.ScheduleEvent(EVENT_MAD_1, 2000);
|
||||
}
|
||||
else if (param == ACTION_SPAWN_FELMYST)
|
||||
events.ScheduleEvent(EVENT_SPAWN_FELMYST, 60000);
|
||||
}
|
||||
EventMap events;
|
||||
InstanceScript* instance;
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_MAD_1:
|
||||
me->SetVisible(true);
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
{
|
||||
me->SetTarget(brutallus->GetGUID());
|
||||
brutallus->SetReactState(REACT_PASSIVE);
|
||||
brutallus->setActive(true);
|
||||
}
|
||||
me->GetMotionMaster()->MovePoint(1, 1477.94f, 643.22f, 21.21f);
|
||||
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
|
||||
events.ScheduleEvent(EVENT_MAD_2, 6000);
|
||||
break;
|
||||
case EVENT_MAD_2:
|
||||
Talk(SAY_MAD_1);
|
||||
me->CastSpell(me, SPELL_MADRIGOSA_FREEZE, false);
|
||||
events.ScheduleEvent(EVENT_MAD_2_1, 1000);
|
||||
break;
|
||||
case EVENT_MAD_2_1:
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->SetDisableGravity(false);
|
||||
me->CastSpell(me, SPELL_MADRIGOSA_FROST_BREATH, false);
|
||||
events.ScheduleEvent(EVENT_MAD_3, 7000);
|
||||
break;
|
||||
case EVENT_MAD_3:
|
||||
Talk(SAY_MAD_2);
|
||||
events.ScheduleEvent(EVENT_MAD_4, 7000);
|
||||
break;
|
||||
case EVENT_MAD_4:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
brutallus->AI()->Talk(YELL_INTRO);
|
||||
events.ScheduleEvent(EVENT_MAD_5, 5000);
|
||||
break;
|
||||
case EVENT_MAD_5:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
{
|
||||
brutallus->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK1H);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK1H);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_6, 10000);
|
||||
break;
|
||||
case EVENT_MAD_6:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
{
|
||||
brutallus->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
|
||||
}
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->SetDisableGravity(true);
|
||||
events.ScheduleEvent(EVENT_MAD_7, 4000);
|
||||
break;
|
||||
case EVENT_MAD_7:
|
||||
Talk(SAY_MAD_3);
|
||||
me->CastSpell(me, SPELL_MADRIGOSA_FROST_BLAST, false);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 3000);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 5000);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 6500);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 7500);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 8500);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 9500);
|
||||
events.ScheduleEvent(EVENT_MAD_9, 11000);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 12000);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 14000);
|
||||
break;
|
||||
case EVENT_MAD_8:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
me->CastSpell(brutallus, SPELL_MADRIGOSA_FROSTBOLT, false);
|
||||
break;
|
||||
case EVENT_MAD_9:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
{
|
||||
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_FLAME_RING, true);
|
||||
brutallus->RemoveAllAuras();
|
||||
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_FEL_FIREBALL, false);
|
||||
brutallus->AI()->Talk(YELL_INTRO_BREAK_ICE);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_11, 6000);
|
||||
break;
|
||||
//case EVENT_MAD_10:
|
||||
case EVENT_MAD_11:
|
||||
me->SetDisableGravity(false);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
events.ScheduleEvent(EVENT_MAD_13, 2500);
|
||||
break;
|
||||
case EVENT_MAD_13:
|
||||
Talk(SAY_MAD_4);
|
||||
me->RemoveAllAuras();
|
||||
me->CastSpell(me, SPELL_MADRIGOSA_ENCAPSULATE, false);
|
||||
events.ScheduleEvent(EVENT_MAD_14, 2000);
|
||||
break;
|
||||
case EVENT_MAD_14:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
{
|
||||
brutallus->SetDisableGravity(true);
|
||||
brutallus->GetMotionMaster()->MovePoint(0, brutallus->GetPositionX(), brutallus->GetPositionY() - 30.0f, brutallus->GetPositionZ() + 15.0f, false, true);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_15, 10000);
|
||||
break;
|
||||
case EVENT_MAD_15:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
{
|
||||
brutallus->RemoveAllAuras();
|
||||
brutallus->SetDisableGravity(false);
|
||||
brutallus->GetMotionMaster()->MoveFall();
|
||||
brutallus->AI()->Talk(YELL_INTRO_CHARGE);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_16, 1400);
|
||||
break;
|
||||
case EVENT_MAD_16:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
brutallus->CastSpell(me, SPELL_BRUTALLUS_CHARGE, true);
|
||||
events.ScheduleEvent(EVENT_MAD_17, 1200);
|
||||
break;
|
||||
case EVENT_MAD_17:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
brutallus->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H);
|
||||
events.ScheduleEvent(EVENT_MAD_18, 500);
|
||||
break;
|
||||
case EVENT_MAD_18:
|
||||
Talk(SAY_MAD_5);
|
||||
me->SetDynamicFlag(UNIT_DYNFLAG_DEAD);
|
||||
me->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
events.ScheduleEvent(EVENT_MAD_19, 6000);
|
||||
break;
|
||||
case EVENT_MAD_19:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
brutallus->AI()->Talk(YELL_INTRO_KILL_MADRIGOSA);
|
||||
events.ScheduleEvent(EVENT_MAD_20, 7000);
|
||||
break;
|
||||
case EVENT_MAD_20:
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
{
|
||||
brutallus->AI()->Talk(YELL_INTRO_TAUNT);
|
||||
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_BREAK_ICE, false);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_21, 4000);
|
||||
break;
|
||||
case EVENT_MAD_21:
|
||||
if (Creature* brutallus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BRUTALLUS)))
|
||||
{
|
||||
brutallus->SetReactState(REACT_AGGRESSIVE);
|
||||
brutallus->SetHealth(brutallus->GetMaxHealth());
|
||||
brutallus->AI()->EnterEvadeMode();
|
||||
brutallus->setActive(false);
|
||||
}
|
||||
break;
|
||||
case EVENT_SPAWN_FELMYST:
|
||||
me->DespawnOrUnsummon(1);
|
||||
if (Creature* felmyst = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_FELMYST)))
|
||||
felmyst->AI()->DoAction(ACTION_START_EVENT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
return GetSunwellPlateauAI<npc_madrigosaAI>(creature);
|
||||
if (param == ACTION_START_EVENT)
|
||||
{
|
||||
me->SetDisableGravity(true);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->RemoveDynamicFlag(UNIT_DYNFLAG_DEAD);
|
||||
me->NearTeleportTo(1570.97f, 725.51f, 79.77f, 3.82f);
|
||||
events.ScheduleEvent(EVENT_MAD_1, 2000);
|
||||
}
|
||||
else if (param == ACTION_SPAWN_FELMYST)
|
||||
events.ScheduleEvent(EVENT_SPAWN_FELMYST, 60000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_MAD_1:
|
||||
me->SetVisible(true);
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
{
|
||||
me->SetTarget(brutallus->GetGUID());
|
||||
brutallus->SetReactState(REACT_PASSIVE);
|
||||
brutallus->setActive(true);
|
||||
}
|
||||
me->GetMotionMaster()->MovePoint(1, 1477.94f, 643.22f, 21.21f);
|
||||
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
|
||||
events.ScheduleEvent(EVENT_MAD_2, 6000);
|
||||
break;
|
||||
case EVENT_MAD_2:
|
||||
Talk(SAY_MAD_1);
|
||||
me->CastSpell(me, SPELL_MADRIGOSA_FREEZE, false);
|
||||
events.ScheduleEvent(EVENT_MAD_2_1, 1000);
|
||||
break;
|
||||
case EVENT_MAD_2_1:
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->SetDisableGravity(false);
|
||||
me->CastSpell(me, SPELL_MADRIGOSA_FROST_BREATH, false);
|
||||
events.ScheduleEvent(EVENT_MAD_3, 7000);
|
||||
break;
|
||||
case EVENT_MAD_3:
|
||||
Talk(SAY_MAD_2);
|
||||
events.ScheduleEvent(EVENT_MAD_4, 7000);
|
||||
break;
|
||||
case EVENT_MAD_4:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
brutallus->AI()->Talk(YELL_INTRO);
|
||||
events.ScheduleEvent(EVENT_MAD_5, 5000);
|
||||
break;
|
||||
case EVENT_MAD_5:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
{
|
||||
brutallus->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK1H);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK1H);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_6, 10000);
|
||||
break;
|
||||
case EVENT_MAD_6:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
{
|
||||
brutallus->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
|
||||
}
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->SetDisableGravity(true);
|
||||
events.ScheduleEvent(EVENT_MAD_7, 4000);
|
||||
break;
|
||||
case EVENT_MAD_7:
|
||||
Talk(SAY_MAD_3);
|
||||
me->CastSpell(me, SPELL_MADRIGOSA_FROST_BLAST, false);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 3000);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 5000);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 6500);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 7500);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 8500);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 9500);
|
||||
events.ScheduleEvent(EVENT_MAD_9, 11000);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 12000);
|
||||
events.ScheduleEvent(EVENT_MAD_8, 14000);
|
||||
break;
|
||||
case EVENT_MAD_8:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
me->CastSpell(brutallus, SPELL_MADRIGOSA_FROSTBOLT, false);
|
||||
break;
|
||||
case EVENT_MAD_9:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
{
|
||||
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_FLAME_RING, true);
|
||||
brutallus->RemoveAllAuras();
|
||||
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_FEL_FIREBALL, false);
|
||||
brutallus->AI()->Talk(YELL_INTRO_BREAK_ICE);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_11, 6000);
|
||||
break;
|
||||
//case EVENT_MAD_10:
|
||||
case EVENT_MAD_11:
|
||||
me->SetDisableGravity(false);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
events.ScheduleEvent(EVENT_MAD_13, 2500);
|
||||
break;
|
||||
case EVENT_MAD_13:
|
||||
Talk(SAY_MAD_4);
|
||||
me->RemoveAllAuras();
|
||||
me->CastSpell(me, SPELL_MADRIGOSA_ENCAPSULATE, false);
|
||||
events.ScheduleEvent(EVENT_MAD_14, 2000);
|
||||
break;
|
||||
case EVENT_MAD_14:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
{
|
||||
brutallus->SetDisableGravity(true);
|
||||
brutallus->GetMotionMaster()->MovePoint(0, brutallus->GetPositionX(), brutallus->GetPositionY() - 30.0f, brutallus->GetPositionZ() + 15.0f, false, true);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_15, 10000);
|
||||
break;
|
||||
case EVENT_MAD_15:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
{
|
||||
brutallus->RemoveAllAuras();
|
||||
brutallus->SetDisableGravity(false);
|
||||
brutallus->GetMotionMaster()->MoveFall();
|
||||
brutallus->AI()->Talk(YELL_INTRO_CHARGE);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_16, 1400);
|
||||
break;
|
||||
case EVENT_MAD_16:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
brutallus->CastSpell(me, SPELL_BRUTALLUS_CHARGE, true);
|
||||
events.ScheduleEvent(EVENT_MAD_17, 1200);
|
||||
break;
|
||||
case EVENT_MAD_17:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
brutallus->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H);
|
||||
events.ScheduleEvent(EVENT_MAD_18, 500);
|
||||
break;
|
||||
case EVENT_MAD_18:
|
||||
Talk(SAY_MAD_5);
|
||||
me->SetDynamicFlag(UNIT_DYNFLAG_DEAD);
|
||||
me->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
events.ScheduleEvent(EVENT_MAD_19, 6000);
|
||||
break;
|
||||
case EVENT_MAD_19:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
brutallus->AI()->Talk(YELL_INTRO_KILL_MADRIGOSA);
|
||||
events.ScheduleEvent(EVENT_MAD_20, 7000);
|
||||
break;
|
||||
case EVENT_MAD_20:
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
{
|
||||
brutallus->AI()->Talk(YELL_INTRO_TAUNT);
|
||||
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_BREAK_ICE, false);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_MAD_21, 4000);
|
||||
break;
|
||||
case EVENT_MAD_21:
|
||||
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
|
||||
{
|
||||
brutallus->SetReactState(REACT_AGGRESSIVE);
|
||||
brutallus->SetHealth(brutallus->GetMaxHealth());
|
||||
brutallus->AI()->EnterEvadeMode();
|
||||
brutallus->setActive(false);
|
||||
}
|
||||
break;
|
||||
case EVENT_SPAWN_FELMYST:
|
||||
me->DespawnOrUnsummon(1);
|
||||
if (Creature* felmyst = instance->GetCreature(DATA_FELMYST))
|
||||
felmyst->AI()->DoAction(ACTION_START_EVENT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -421,18 +371,13 @@ class spell_madrigosa_activate_barrier : public SpellScript
|
||||
{
|
||||
go->SetGoState(GO_STATE_READY);
|
||||
if (Map* map = go->GetMap())
|
||||
{
|
||||
Map::PlayerList const& PlayerList = map->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
|
||||
if (i->GetSource())
|
||||
{
|
||||
UpdateData data;
|
||||
WorldPacket pkt;
|
||||
go->BuildValuesUpdateBlockForPlayer(&data, i->GetSource());
|
||||
data.BuildPacket(pkt);
|
||||
i->GetSource()->GetSession()->SendPacket(&pkt);
|
||||
}
|
||||
}
|
||||
map->DoForAllPlayers([&](Player* player) {
|
||||
UpdateData data;
|
||||
WorldPacket pkt;
|
||||
go->BuildValuesUpdateBlockForPlayer(&data, player);
|
||||
data.BuildPacket(pkt);
|
||||
player->GetSession()->SendPacket(&pkt);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,18 +398,13 @@ class spell_madrigosa_deactivate_barrier : public SpellScript
|
||||
{
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
if (Map* map = go->GetMap())
|
||||
{
|
||||
Map::PlayerList const& PlayerList = map->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
|
||||
if (i->GetSource())
|
||||
{
|
||||
UpdateData data;
|
||||
WorldPacket pkt;
|
||||
go->BuildValuesUpdateBlockForPlayer(&data, i->GetSource());
|
||||
data.BuildPacket(pkt);
|
||||
i->GetSource()->GetSession()->SendPacket(&pkt);
|
||||
}
|
||||
}
|
||||
map->DoForAllPlayers([&](Player* player) {
|
||||
UpdateData data;
|
||||
WorldPacket pkt;
|
||||
go->BuildValuesUpdateBlockForPlayer(&data, player);
|
||||
data.BuildPacket(pkt);
|
||||
player->GetSession()->SendPacket(&pkt);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,21 +437,17 @@ class spell_brutallus_burn : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
class AreaTrigger_at_sunwell_madrigosa : public AreaTriggerScript
|
||||
class at_sunwell_madrigosa : public OnlyOnceAreaTriggerScript
|
||||
{
|
||||
public:
|
||||
AreaTrigger_at_sunwell_madrigosa() : AreaTriggerScript("at_sunwell_madrigosa") {}
|
||||
at_sunwell_madrigosa() : OnlyOnceAreaTriggerScript("at_sunwell_madrigosa") {}
|
||||
|
||||
bool OnTrigger(Player* player, AreaTrigger const* /*trigger*/) override
|
||||
bool _OnTrigger(Player* player, AreaTrigger const* /*trigger*/) override
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
if (instance->GetBossState(DATA_MADRIGOSA) != DONE)
|
||||
{
|
||||
instance->SetBossState(DATA_MADRIGOSA, NOT_STARTED);
|
||||
instance->SetBossState(DATA_MADRIGOSA, DONE);
|
||||
if (Creature* creature = ObjectAccessor::GetCreature(*player, instance->GetGuidData(NPC_MADRIGOSA)))
|
||||
if (!instance->IsBossDone(DATA_BRUTALLUS))
|
||||
if (Creature* creature = instance->GetCreature(DATA_MADRIGOSA))
|
||||
creature->AI()->DoAction(ACTION_START_EVENT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -519,10 +455,10 @@ public:
|
||||
|
||||
void AddSC_boss_brutallus()
|
||||
{
|
||||
new boss_brutallus();
|
||||
new npc_madrigosa();
|
||||
RegisterSunwellPlateauCreatureAI(boss_brutallus);
|
||||
RegisterSunwellPlateauCreatureAI(npc_madrigosa);
|
||||
RegisterSpellScript(spell_madrigosa_activate_barrier);
|
||||
RegisterSpellScript(spell_madrigosa_deactivate_barrier);
|
||||
RegisterSpellScript(spell_brutallus_burn);
|
||||
new AreaTrigger_at_sunwell_madrigosa();
|
||||
new at_sunwell_madrigosa();
|
||||
}
|
||||
|
||||
@@ -70,344 +70,248 @@ enum Spells
|
||||
enum Misc
|
||||
{
|
||||
ACTION_SISTER_DIED = 1,
|
||||
|
||||
EVENT_SPELL_SHADOW_BLADES = 1,
|
||||
EVENT_SPELL_SHADOW_NOVA = 2,
|
||||
EVENT_SPELL_CONFOUNDING_BLOW = 3,
|
||||
EVENT_SHADOW_IMAGE = 4,
|
||||
EVENT_SPELL_ENRAGE = 5,
|
||||
EVENT_SPELL_CONFLAGRATION = 6,
|
||||
EVENT_SPELL_BLAZE = 7,
|
||||
EVENT_SPELL_PYROGENICS = 8,
|
||||
EVENT_SPELL_FLAME_SEAR = 9
|
||||
GROUP_SPECIAL_ABILITY = 1
|
||||
};
|
||||
|
||||
class boss_sacrolash : public CreatureScript
|
||||
struct boss_sacrolash : public BossAI
|
||||
{
|
||||
boss_sacrolash(Creature* creature) : BossAI(creature, DATA_EREDAR_TWINS), _isSisterDead(false) {}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
DoCastSelf(SPELL_SHADOWFORM, true);
|
||||
_isSisterDead = false;
|
||||
BossAI::Reset();
|
||||
me->SetLootMode(0);
|
||||
me->m_Events.KillAllEvents(false);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_SISTER_DIED)
|
||||
{
|
||||
me->ResetLootMode();
|
||||
_isSisterDead = true;
|
||||
Talk(YELL_SISTER_ALYTHESS_DEAD);
|
||||
me->CastSpell(me, SPELL_EMPOWER, true);
|
||||
|
||||
scheduler.CancelGroup(GROUP_SPECIAL_ABILITY);
|
||||
ScheduleTimedEvent(20s, [&] {
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
me->CastSpell(target, SPELL_CONFLAGRATION, false);
|
||||
}, 30s, 35s);
|
||||
}
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
BossAI::EnterEvadeMode(why);
|
||||
if (Creature* alythess = instance->GetCreature(DATA_ALYTHESS))
|
||||
{
|
||||
if (!alythess->IsAlive())
|
||||
alythess->Respawn(true);
|
||||
else if (!alythess->IsInEvadeMode())
|
||||
alythess->AI()->EnterEvadeMode(why);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
if (Creature* alythess = instance->GetCreature(DATA_ALYTHESS))
|
||||
if (alythess->IsAlive() && !alythess->IsInCombat())
|
||||
alythess->AI()->AttackStart(who);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
Talk(YELL_BERSERK);
|
||||
DoCastSelf(SPELL_ENRAGE, true);
|
||||
}, 6min);
|
||||
|
||||
ScheduleTimedEvent(10s, [&] {
|
||||
DoCastSelf(SPELL_SHADOW_BLADES);
|
||||
}, 10s);
|
||||
|
||||
ScheduleTimedEvent(25s, [&] {
|
||||
DoCastVictim(SPELL_CONFOUNDING_BLOW);
|
||||
}, 20s, 25s);
|
||||
|
||||
ScheduleTimedEvent(20s, [&] {
|
||||
me->SummonCreature(NPC_SHADOW_IMAGE, me->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 12000);
|
||||
}, 6s);
|
||||
|
||||
scheduler.Schedule(36s, GROUP_SPECIAL_ABILITY, [this](TaskContext context) {
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
Talk(EMOTE_SHADOW_NOVA, target);
|
||||
Talk(YELL_SHADOW_NOVA);
|
||||
DoCast(target, SPELL_SHADOW_NOVA);
|
||||
context.Repeat(30s, 35s);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && urand(0, 1))
|
||||
Talk(YELL_SAC_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
summons.DespawnAll();
|
||||
|
||||
if (_isSisterDead)
|
||||
{
|
||||
Talk(YELL_SAC_DEAD);
|
||||
instance->SetBossState(DATA_EREDAR_TWINS, DONE);
|
||||
}
|
||||
else if (Creature* alythess = instance->GetCreature(DATA_ALYTHESS))
|
||||
alythess->AI()->DoAction(ACTION_SISTER_DIED);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
|
||||
{
|
||||
summon->AI()->AttackStart(target);
|
||||
summon->AddThreat(target, 10000000);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool _isSisterDead;
|
||||
};
|
||||
|
||||
struct boss_alythess : public BossAI
|
||||
{
|
||||
boss_alythess(Creature* creature) : BossAI(creature, DATA_EREDAR_TWINS), _isSisterDead(false) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
DoCastSelf(SPELL_FIREFORM, true);
|
||||
_isSisterDead = false;
|
||||
BossAI::Reset();
|
||||
me->SetLootMode(0);
|
||||
me->m_Events.KillAllEvents(false);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_SISTER_DIED)
|
||||
{
|
||||
me->ResetLootMode();
|
||||
_isSisterDead = true;
|
||||
Talk(YELL_SISTER_SACROLASH_DEAD);
|
||||
me->CastSpell(me, SPELL_EMPOWER, true);
|
||||
|
||||
scheduler.CancelGroup(GROUP_SPECIAL_ABILITY);
|
||||
ScheduleTimedEvent(20s, [&] {
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
DoCast(target, SPELL_SHADOW_NOVA);
|
||||
}, 30s, 35s);
|
||||
}
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
BossAI::EnterEvadeMode(why);
|
||||
if (Creature* sacrolash = instance->GetCreature(DATA_SACROLASH))
|
||||
{
|
||||
if (!sacrolash->IsAlive())
|
||||
sacrolash->Respawn(true);
|
||||
else if (!sacrolash->IsInEvadeMode())
|
||||
sacrolash->AI()->EnterEvadeMode(why);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
if (Creature* sacrolash = instance->GetCreature(DATA_SACROLASH))
|
||||
if (sacrolash->IsAlive() && !sacrolash->IsInCombat())
|
||||
sacrolash->AI()->AttackStart(who);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
Talk(YELL_BERSERK);
|
||||
DoCastSelf(SPELL_ENRAGE, true);
|
||||
}, 6min);
|
||||
|
||||
ScheduleTimedEvent(1s, [&] {
|
||||
DoCastVictim(SPELL_BLAZE);
|
||||
}, 3800ms);
|
||||
|
||||
ScheduleTimedEvent(15s, [&] {
|
||||
DoCastSelf(SPELL_PYROGENICS);
|
||||
}, 15s);
|
||||
|
||||
ScheduleTimedEvent(20s, [&] {
|
||||
me->CastCustomSpell(SPELL_FLAME_SEAR, SPELLVALUE_MAX_TARGETS, 5, me, TRIGGERED_NONE);
|
||||
}, 15s);
|
||||
|
||||
scheduler.Schedule(20s, GROUP_SPECIAL_ABILITY, [this](TaskContext context) {
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
Talk(EMOTE_CONFLAGRATION, target);
|
||||
Talk(YELL_CANFLAGRATION);
|
||||
DoCast(target, SPELL_CONFLAGRATION);
|
||||
context.Repeat(30s, 35s);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && urand(0, 1))
|
||||
Talk(YELL_SAC_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
summons.DespawnAll();
|
||||
|
||||
if (_isSisterDead)
|
||||
{
|
||||
Talk(YELL_SAC_DEAD);
|
||||
instance->SetBossState(DATA_EREDAR_TWINS, DONE);
|
||||
}
|
||||
else if (Creature* sacrolash = instance->GetCreature(DATA_SACROLASH))
|
||||
sacrolash->AI()->DoAction(ACTION_SISTER_DIED);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _isSisterDead;
|
||||
};
|
||||
|
||||
class spell_eredar_twins_apply_touch : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_eredar_twins_apply_touch);
|
||||
|
||||
public:
|
||||
boss_sacrolash() : CreatureScript("boss_sacrolash") { }
|
||||
|
||||
struct boss_sacrolashAI : public BossAI
|
||||
{
|
||||
boss_sacrolashAI(Creature* creature) : BossAI(creature, DATA_EREDAR_TWINS) {}
|
||||
|
||||
bool sisterDied;
|
||||
void Reset() override
|
||||
{
|
||||
me->CastSpell(me, SPELL_SHADOWFORM, true);
|
||||
sisterDied = false;
|
||||
BossAI::Reset();
|
||||
me->SetLootMode(0);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_SISTER_DIED)
|
||||
{
|
||||
me->ResetLootMode();
|
||||
sisterDied = true;
|
||||
Talk(YELL_SISTER_ALYTHESS_DEAD);
|
||||
me->CastSpell(me, SPELL_EMPOWER, true);
|
||||
|
||||
uint32 timer = events.GetNextEventTime(EVENT_SPELL_SHADOW_NOVA);
|
||||
events.CancelEvent(EVENT_SPELL_SHADOW_NOVA);
|
||||
events.ScheduleEvent(EVENT_SPELL_CONFLAGRATION, timer - events.GetTimer());
|
||||
}
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
BossAI::EnterEvadeMode(why);
|
||||
if (Creature* alythess = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_ALYTHESS)))
|
||||
{
|
||||
if (!alythess->IsAlive())
|
||||
alythess->Respawn(true);
|
||||
else if (!alythess->IsInEvadeMode())
|
||||
alythess->AI()->EnterEvadeMode(why);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
if (Creature* alythess = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_ALYTHESS)))
|
||||
if (alythess->IsAlive() && !alythess->IsInCombat())
|
||||
alythess->AI()->AttackStart(who);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_BLADES, 10000);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_NOVA, 36000);
|
||||
events.ScheduleEvent(EVENT_SPELL_CONFOUNDING_BLOW, 25000);
|
||||
events.ScheduleEvent(EVENT_SHADOW_IMAGE, 20000);
|
||||
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 360000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && urand(0, 1))
|
||||
Talk(YELL_SAC_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
|
||||
if (sisterDied)
|
||||
{
|
||||
Talk(YELL_SAC_DEAD);
|
||||
instance->SetBossState(DATA_EREDAR_TWINS, DONE);
|
||||
}
|
||||
else if (Creature* alythess = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_ALYTHESS)))
|
||||
alythess->AI()->DoAction(ACTION_SISTER_DIED);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
|
||||
{
|
||||
summon->AI()->AttackStart(target);
|
||||
summon->AddThreat(target, 10000000);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_ENRAGE:
|
||||
Talk(YELL_ENRAGE);
|
||||
me->CastSpell(me, SPELL_ENRAGE, true);
|
||||
break;
|
||||
case EVENT_SPELL_CONFOUNDING_BLOW:
|
||||
me->CastSpell(me->GetVictim(), SPELL_CONFOUNDING_BLOW, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CONFOUNDING_BLOW, urand(20000, 25000));
|
||||
break;
|
||||
case EVENT_SPELL_SHADOW_BLADES:
|
||||
me->CastSpell(me, SPELL_SHADOW_BLADES, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_BLADES, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_SHADOW_NOVA:
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
Talk(EMOTE_SHADOW_NOVA, target);
|
||||
Talk(YELL_SHADOW_NOVA);
|
||||
me->CastSpell(target, SPELL_SHADOW_NOVA, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_NOVA, urand(30000, 35000));
|
||||
break;
|
||||
}
|
||||
case EVENT_SHADOW_IMAGE:
|
||||
me->SummonCreature(NPC_SHADOW_IMAGE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 12000);
|
||||
events.ScheduleEvent(EVENT_SHADOW_IMAGE, 6000);
|
||||
break;
|
||||
case EVENT_SPELL_CONFLAGRATION:
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
me->CastSpell(target, SPELL_CONFLAGRATION, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CONFLAGRATION, urand(30000, 35000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_sacrolashAI>(creature);
|
||||
};
|
||||
};
|
||||
|
||||
class boss_alythess : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_alythess() : CreatureScript("boss_alythess") { }
|
||||
|
||||
struct boss_alythessAI : public BossAI
|
||||
{
|
||||
boss_alythessAI(Creature* creature) : BossAI(creature, DATA_EREDAR_TWINS) { }
|
||||
|
||||
bool sisterDied;
|
||||
void Reset() override
|
||||
{
|
||||
me->CastSpell(me, SPELL_FIREFORM, true);
|
||||
sisterDied = false;
|
||||
BossAI::Reset();
|
||||
me->SetLootMode(0);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_SISTER_DIED)
|
||||
{
|
||||
me->ResetLootMode();
|
||||
sisterDied = true;
|
||||
Talk(YELL_SISTER_SACROLASH_DEAD);
|
||||
me->CastSpell(me, SPELL_EMPOWER, true);
|
||||
|
||||
uint32 timer = events.GetNextEventTime(EVENT_SPELL_CONFLAGRATION);
|
||||
events.CancelEvent(EVENT_SPELL_CONFLAGRATION);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_NOVA, timer - events.GetTimer());
|
||||
}
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
BossAI::EnterEvadeMode(why);
|
||||
if (Creature* scorlash = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_LADY_SACROLASH)))
|
||||
{
|
||||
if (!scorlash->IsAlive())
|
||||
scorlash->Respawn(true);
|
||||
else if (!scorlash->IsInEvadeMode())
|
||||
scorlash->AI()->EnterEvadeMode(why);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
if (Creature* scorlash = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_LADY_SACROLASH)))
|
||||
if (scorlash->IsAlive() && !scorlash->IsInCombat())
|
||||
scorlash->AI()->AttackStart(who);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_BLAZE, 100);
|
||||
events.ScheduleEvent(EVENT_SPELL_PYROGENICS, 15000);
|
||||
events.ScheduleEvent(EVENT_SPELL_FLAME_SEAR, 20000);
|
||||
events.ScheduleEvent(EVENT_SPELL_CONFLAGRATION, 30000);
|
||||
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 360000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && urand(0, 1))
|
||||
Talk(YELL_SAC_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
|
||||
if (sisterDied)
|
||||
{
|
||||
Talk(YELL_SAC_DEAD);
|
||||
instance->SetBossState(DATA_EREDAR_TWINS, DONE);
|
||||
}
|
||||
else if (Creature* scorlash = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_LADY_SACROLASH)))
|
||||
scorlash->AI()->DoAction(ACTION_SISTER_DIED);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_ENRAGE:
|
||||
Talk(YELL_BERSERK);
|
||||
me->CastSpell(me, SPELL_ENRAGE, true);
|
||||
break;
|
||||
case EVENT_SPELL_PYROGENICS:
|
||||
me->CastSpell(me, SPELL_PYROGENICS, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_PYROGENICS, 15000);
|
||||
break;
|
||||
case EVENT_SPELL_FLAME_SEAR:
|
||||
me->CastCustomSpell(SPELL_FLAME_SEAR, SPELLVALUE_MAX_TARGETS, 5, me, TRIGGERED_NONE);
|
||||
events.ScheduleEvent(EVENT_SPELL_FLAME_SEAR, 15000);
|
||||
break;
|
||||
case EVENT_SPELL_BLAZE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_BLAZE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_BLAZE, 3800);
|
||||
break;
|
||||
case EVENT_SPELL_SHADOW_NOVA:
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
me->CastSpell(target, SPELL_SHADOW_NOVA, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_NOVA, urand(30000, 35000));
|
||||
break;
|
||||
}
|
||||
case EVENT_SPELL_CONFLAGRATION:
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 100.0f);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
Talk(EMOTE_CONFLAGRATION, target);
|
||||
Talk(YELL_CANFLAGRATION);
|
||||
me->CastSpell(target, SPELL_CONFLAGRATION, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CONFLAGRATION, urand(30000, 35000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_alythessAI>(creature);
|
||||
};
|
||||
};
|
||||
|
||||
class spell_eredar_twins_apply_dark_touched : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_eredar_twins_apply_dark_touched);
|
||||
spell_eredar_twins_apply_touch(uint32 touchSpell) : SpellScript(), _touchSpell(touchSpell) { }
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_DARK_TOUCHED });
|
||||
return ValidateSpellInfo({ _touchSpell });
|
||||
}
|
||||
|
||||
void HandleApplyTouch()
|
||||
{
|
||||
if (Player* target = GetHitPlayer())
|
||||
target->CastSpell(target, SPELL_DARK_TOUCHED, true);
|
||||
target->CastSpell(target, _touchSpell, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterHit += SpellHitFn(spell_eredar_twins_apply_dark_touched::HandleApplyTouch);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_eredar_twins_apply_flame_touched : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_eredar_twins_apply_flame_touched);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_FLAME_TOUCHED });
|
||||
AfterHit += SpellHitFn(spell_eredar_twins_apply_touch::HandleApplyTouch);
|
||||
}
|
||||
|
||||
void HandleApplyTouch()
|
||||
{
|
||||
if (Player* target = GetHitPlayer())
|
||||
target->CastSpell(target, SPELL_FLAME_TOUCHED, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterHit += SpellHitFn(spell_eredar_twins_apply_flame_touched::HandleApplyTouch);
|
||||
}
|
||||
private:
|
||||
uint32 _touchSpell;
|
||||
};
|
||||
|
||||
class spell_eredar_twins_handle_touch : public SpellScript
|
||||
@@ -473,22 +377,20 @@ class spell_eredar_twins_blaze : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
class AreaTrigger_at_sunwell_eredar_twins : public AreaTriggerScript
|
||||
class at_sunwell_eredar_twins : public OnlyOnceAreaTriggerScript
|
||||
{
|
||||
public:
|
||||
AreaTrigger_at_sunwell_eredar_twins() : AreaTriggerScript("at_sunwell_eredar_twins") {}
|
||||
at_sunwell_eredar_twins() : OnlyOnceAreaTriggerScript("at_sunwell_eredar_twins") {}
|
||||
|
||||
bool OnTrigger(Player* player, AreaTrigger const* /*trigger*/) override
|
||||
bool _OnTrigger(Player* player, AreaTrigger const* /*trigger*/) override
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
if (instance->GetBossState(DATA_EREDAR_TWINS_INTRO) != DONE)
|
||||
{
|
||||
instance->SetBossState(DATA_EREDAR_TWINS_INTRO, DONE);
|
||||
if (Creature* creature = ObjectAccessor::GetCreature(*player, instance->GetGuidData(NPC_LADY_SACROLASH)))
|
||||
creature->AI()->Talk(YELL_INTRO_SAC);
|
||||
if (Creature* creature = ObjectAccessor::GetCreature(*player, instance->GetGuidData(NPC_GRAND_WARLOCK_ALYTHESS)))
|
||||
creature->AI()->Talk(YELL_INTRO_ALY);
|
||||
}
|
||||
{
|
||||
if (Creature* creature = instance->GetCreature(DATA_SACROLASH))
|
||||
creature->AI()->Talk(YELL_INTRO_SAC);
|
||||
if (Creature* creature = instance->GetCreature(DATA_ALYTHESS))
|
||||
creature->AI()->Talk(YELL_INTRO_ALY);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -496,11 +398,11 @@ public:
|
||||
|
||||
void AddSC_boss_eredar_twins()
|
||||
{
|
||||
new boss_sacrolash();
|
||||
new boss_alythess();
|
||||
RegisterSpellScript(spell_eredar_twins_apply_dark_touched);
|
||||
RegisterSpellScript(spell_eredar_twins_apply_flame_touched);
|
||||
RegisterSunwellPlateauCreatureAI(boss_sacrolash);
|
||||
RegisterSunwellPlateauCreatureAI(boss_alythess);
|
||||
RegisterSpellScriptWithArgs(spell_eredar_twins_apply_touch, "spell_eredar_twins_apply_dark_touched", SPELL_DARK_TOUCHED);
|
||||
RegisterSpellScriptWithArgs(spell_eredar_twins_apply_touch, "spell_eredar_twins_apply_flame_touched", SPELL_FLAME_TOUCHED);
|
||||
RegisterSpellScript(spell_eredar_twins_handle_touch);
|
||||
RegisterSpellScript(spell_eredar_twins_blaze);
|
||||
new AreaTrigger_at_sunwell_eredar_twins();
|
||||
new at_sunwell_eredar_twins();
|
||||
}
|
||||
|
||||
@@ -126,356 +126,323 @@ private:
|
||||
Unit* _caster;
|
||||
};
|
||||
|
||||
class boss_felmyst : public CreatureScript
|
||||
struct boss_felmyst : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_felmyst() : CreatureScript("boss_felmyst") { }
|
||||
|
||||
struct boss_felmystAI : public BossAI
|
||||
boss_felmyst(Creature* creature) : BossAI(creature, DATA_FELMYST)
|
||||
{
|
||||
boss_felmystAI(Creature* creature) : BossAI(creature, DATA_FELMYST)
|
||||
{
|
||||
bool appear = instance->GetBossState(DATA_BRUTALLUS) == DONE;
|
||||
creature->SetVisible(appear);
|
||||
creature->SetStandState(UNIT_STAND_STATE_SLEEP);
|
||||
creature->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
bool appear = instance->GetBossState(DATA_BRUTALLUS) == DONE;
|
||||
creature->SetVisible(appear);
|
||||
creature->SetStandState(UNIT_STAND_STATE_SLEEP);
|
||||
creature->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
EventMap events2;
|
||||
EventMap events2;
|
||||
|
||||
void DoAction(int32 param) override
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_START_EVENT)
|
||||
{
|
||||
if (param == ACTION_START_EVENT)
|
||||
{
|
||||
me->SetVisible(true);
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
events2.ScheduleEvent(EVENT_INTRO_1, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetDisableGravity(false);
|
||||
events2.Reset();
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FOG_OF_CORRUPTION_CHARM);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
me->SetVisible(true);
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
if (events.Empty() && events2.Empty())
|
||||
events2.ScheduleEvent(EVENT_INTRO_2, 3000);
|
||||
events2.ScheduleEvent(EVENT_INTRO_1, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && roll_chance_i(50))
|
||||
Talk(YELL_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
BossAI::JustDied(killer);
|
||||
Talk(YELL_DEATH);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FOG_OF_CORRUPTION_CHARM);
|
||||
|
||||
// Summon Kalecgos (human form of kalecgos fight)
|
||||
me->SummonCreature(NPC_KALEC, 1526.28f, 700.10f, 60.0f, 4.33f);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 point) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (point == POINT_GROUND)
|
||||
{
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->SetDisableGravity(false);
|
||||
me->SendMovementFlagUpdate();
|
||||
|
||||
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 0);
|
||||
events.ScheduleEvent(EVENT_RESTORE_COMBAT2, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_CLEAVE, 7500, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_CORROSION, 12000, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_GAS_NOVA, 18000, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_ENCAPSULATE, 25000, 1);
|
||||
events.ScheduleEvent(EVENT_FLIGHT, 60000, 1);
|
||||
}
|
||||
else if (point == POINT_AIR_BREATH_START1)
|
||||
{
|
||||
me->SetTarget();
|
||||
me->SetFacingTo(4.71f);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_EMOTE, 2000);
|
||||
events.ScheduleEvent(EVENT_CORRUPT_TRIGGERS, 5000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_FLYOVER1, 5000);
|
||||
}
|
||||
else if (point == POINT_AIR_BREATH_END1)
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_FELMYST_SPEED_BURST);
|
||||
me->SetFacingTo(1.57f);
|
||||
if (events.GetNextEventTime(EVENT_FLIGHT_BREATH1) != 0)
|
||||
events.ScheduleEvent(EVENT_FLIGHT_BREATH2, 2000);
|
||||
}
|
||||
else if (point == POINT_AIR_BREATH_START2)
|
||||
{
|
||||
me->SetTarget();
|
||||
me->SetFacingTo(1.57f);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_EMOTE, 2000);
|
||||
events.ScheduleEvent(EVENT_CORRUPT_TRIGGERS, 5000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_FLYOVER2, 5000);
|
||||
}
|
||||
else if (point == POINT_AIR_BREATH_END2)
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_FELMYST_SPEED_BURST);
|
||||
me->SetFacingTo(4.71f);
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_INTRO_1:
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
events2.ScheduleEvent(EVENT_INTRO_2, 4000);
|
||||
break;
|
||||
case EVENT_INTRO_2:
|
||||
Talk(YELL_BIRTH);
|
||||
me->SetDisableGravity(true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->SendMovementFlagUpdate();
|
||||
events2.ScheduleEvent(EVENT_INTRO_3, 1500);
|
||||
break;
|
||||
case EVENT_INTRO_3:
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10.0f, false, true);
|
||||
events2.ScheduleEvent(EVENT_INTRO_4, 2000);
|
||||
break;
|
||||
case EVENT_INTRO_4:
|
||||
events.ScheduleEvent(EVENT_LAND, 3000, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000);
|
||||
me->SetInCombatWithZone();
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->CastSpell(me, SPELL_NOXIOUS_FUMES, true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_MISC, 1472.18f, 603.38f, 34.0f, false, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!events2.Empty())
|
||||
return;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_RESTORE_COMBAT:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
break;
|
||||
case EVENT_RESTORE_COMBAT2:
|
||||
me->SetTarget(me->GetVictim()->GetGUID());
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
break;
|
||||
case EVENT_LAND:
|
||||
me->GetMotionMaster()->MovePoint(POINT_GROUND, me->GetPositionX(), me->GetPositionY(), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), false, true);
|
||||
break;
|
||||
case EVENT_SPELL_BERSERK:
|
||||
Talk(YELL_BERSERK);
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
break;
|
||||
case EVENT_SPELL_CLEAVE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CLEAVE, 7500, 1);
|
||||
break;
|
||||
case EVENT_SPELL_CORROSION:
|
||||
me->CastSpell(me->GetVictim(), SPELL_CORROSION, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CORROSION, 20000, 1);
|
||||
break;
|
||||
case EVENT_SPELL_GAS_NOVA:
|
||||
DoCast(me, SPELL_GAS_NOVA, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_GAS_NOVA, 20000, 1);
|
||||
break;
|
||||
case EVENT_SPELL_ENCAPSULATE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
|
||||
me->CastSpell(target, SPELL_ENCAPSULATE_CHANNEL, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_ENCAPSULATE, 25000, 1);
|
||||
break;
|
||||
case EVENT_FLIGHT:
|
||||
events.CancelEventGroup(1);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_SEQ, 1000);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->Clear();
|
||||
break;
|
||||
case EVENT_FLIGHT_SEQ:
|
||||
Talk(YELL_TAKEOFF);
|
||||
me->SetTarget();
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->SetDisableGravity(true);
|
||||
me->SendMovementFlagUpdate();
|
||||
|
||||
events.ScheduleEvent(EVENT_FLIGHT_MOVE_UP, 2000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_VAPOR, 8000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_VAPOR, 21000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_BREATH1, 35000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_BREATH1, 72000);
|
||||
events.ScheduleEvent(EVENT_LAND_FIGHT, 86000);
|
||||
break;
|
||||
case EVENT_FLIGHT_MOVE_UP:
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 15.0f, false, true);
|
||||
break;
|
||||
case EVENT_FLIGHT_VAPOR:
|
||||
me->CastCustomSpell(SPELL_SUMMON_DEMONIC_VAPOR, SPELLVALUE_MAX_TARGETS, 1, me, true);
|
||||
break;
|
||||
case EVENT_FLIGHT_BREATH1:
|
||||
{
|
||||
Position pos = {1447.0f + urand(0, 2) * 25.0f, 705.0f, 50.0f, 4.71f};
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START1, pos, false, true);
|
||||
break;
|
||||
}
|
||||
case EVENT_FLIGHT_BREATH2:
|
||||
{
|
||||
Position pos = {1447.0f + urand(0, 2) * 25.0f, 515.0f, 50.0f, 1.57f};
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START2, pos, false, true);
|
||||
break;
|
||||
}
|
||||
case EVENT_FLIGHT_EMOTE:
|
||||
Talk(EMOTE_BREATH);
|
||||
break;
|
||||
case EVENT_CORRUPT_TRIGGERS:
|
||||
Talk(YELL_BREATH);
|
||||
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));
|
||||
break;
|
||||
case EVENT_FLIGHT_FLYOVER1:
|
||||
me->CastSpell(me, SPELL_FELMYST_SPEED_BURST, true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END1, me->GetPositionX(), me->GetPositionY() - 200.0f, me->GetPositionZ() + 5.0f, false, true);
|
||||
break;
|
||||
case EVENT_FLIGHT_FLYOVER2:
|
||||
me->CastSpell(me, SPELL_FELMYST_SPEED_BURST, true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END2, me->GetPositionX(), me->GetPositionY() + 200.0f, me->GetPositionZ() + 5.0f, false, true);
|
||||
break;
|
||||
case EVENT_LAND_FIGHT:
|
||||
me->GetMotionMaster()->MovePoint(POINT_GROUND, 1500.0f, 552.8f, 26.52f, false, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!me->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY))
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void Reset() override
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_felmystAI>(creature);
|
||||
BossAI::Reset();
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetDisableGravity(false);
|
||||
events2.Reset();
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FOG_OF_CORRUPTION_CHARM);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
if (events.Empty() && events2.Empty())
|
||||
events2.ScheduleEvent(EVENT_INTRO_2, 3000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && roll_chance_i(50))
|
||||
Talk(YELL_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
BossAI::JustDied(killer);
|
||||
Talk(YELL_DEATH);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FOG_OF_CORRUPTION_CHARM);
|
||||
|
||||
// Summon Kalecgos (human form of kalecgos fight)
|
||||
me->SummonCreature(NPC_KALEC, 1526.28f, 700.10f, 60.0f, 4.33f);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 point) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (point == POINT_GROUND)
|
||||
{
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->SetDisableGravity(false);
|
||||
me->SendMovementFlagUpdate();
|
||||
|
||||
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 0);
|
||||
events.ScheduleEvent(EVENT_RESTORE_COMBAT2, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_CLEAVE, 7500, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_CORROSION, 12000, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_GAS_NOVA, 18000, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_ENCAPSULATE, 25000, 1);
|
||||
events.ScheduleEvent(EVENT_FLIGHT, 60000, 1);
|
||||
}
|
||||
else if (point == POINT_AIR_BREATH_START1)
|
||||
{
|
||||
me->SetTarget();
|
||||
me->SetFacingTo(4.71f);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_EMOTE, 2000);
|
||||
events.ScheduleEvent(EVENT_CORRUPT_TRIGGERS, 5000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_FLYOVER1, 5000);
|
||||
}
|
||||
else if (point == POINT_AIR_BREATH_END1)
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_FELMYST_SPEED_BURST);
|
||||
me->SetFacingTo(1.57f);
|
||||
if (events.GetNextEventTime(EVENT_FLIGHT_BREATH1) != 0)
|
||||
events.ScheduleEvent(EVENT_FLIGHT_BREATH2, 2000);
|
||||
}
|
||||
else if (point == POINT_AIR_BREATH_START2)
|
||||
{
|
||||
me->SetTarget();
|
||||
me->SetFacingTo(1.57f);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_EMOTE, 2000);
|
||||
events.ScheduleEvent(EVENT_CORRUPT_TRIGGERS, 5000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_FLYOVER2, 5000);
|
||||
}
|
||||
else if (point == POINT_AIR_BREATH_END2)
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_FELMYST_SPEED_BURST);
|
||||
me->SetFacingTo(4.71f);
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_INTRO_1:
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
events2.ScheduleEvent(EVENT_INTRO_2, 4000);
|
||||
break;
|
||||
case EVENT_INTRO_2:
|
||||
Talk(YELL_BIRTH);
|
||||
me->SetDisableGravity(true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->SendMovementFlagUpdate();
|
||||
events2.ScheduleEvent(EVENT_INTRO_3, 1500);
|
||||
break;
|
||||
case EVENT_INTRO_3:
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10.0f, false, true);
|
||||
events2.ScheduleEvent(EVENT_INTRO_4, 2000);
|
||||
break;
|
||||
case EVENT_INTRO_4:
|
||||
events.ScheduleEvent(EVENT_LAND, 3000, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000);
|
||||
me->SetInCombatWithZone();
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->CastSpell(me, SPELL_NOXIOUS_FUMES, true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_MISC, 1472.18f, 603.38f, 34.0f, false, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!events2.Empty())
|
||||
return;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_RESTORE_COMBAT:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
break;
|
||||
case EVENT_RESTORE_COMBAT2:
|
||||
me->SetTarget(me->GetVictim()->GetGUID());
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
break;
|
||||
case EVENT_LAND:
|
||||
me->GetMotionMaster()->MovePoint(POINT_GROUND, me->GetPositionX(), me->GetPositionY(), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), false, true);
|
||||
break;
|
||||
case EVENT_SPELL_BERSERK:
|
||||
Talk(YELL_BERSERK);
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
break;
|
||||
case EVENT_SPELL_CLEAVE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CLEAVE, 7500, 1);
|
||||
break;
|
||||
case EVENT_SPELL_CORROSION:
|
||||
me->CastSpell(me->GetVictim(), SPELL_CORROSION, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CORROSION, 20000, 1);
|
||||
break;
|
||||
case EVENT_SPELL_GAS_NOVA:
|
||||
DoCast(me, SPELL_GAS_NOVA, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_GAS_NOVA, 20000, 1);
|
||||
break;
|
||||
case EVENT_SPELL_ENCAPSULATE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
|
||||
me->CastSpell(target, SPELL_ENCAPSULATE_CHANNEL, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_ENCAPSULATE, 25000, 1);
|
||||
break;
|
||||
case EVENT_FLIGHT:
|
||||
events.CancelEventGroup(1);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_SEQ, 1000);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->Clear();
|
||||
break;
|
||||
case EVENT_FLIGHT_SEQ:
|
||||
Talk(YELL_TAKEOFF);
|
||||
me->SetTarget();
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->SetDisableGravity(true);
|
||||
me->SendMovementFlagUpdate();
|
||||
|
||||
events.ScheduleEvent(EVENT_FLIGHT_MOVE_UP, 2000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_VAPOR, 8000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_VAPOR, 21000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_BREATH1, 35000);
|
||||
events.ScheduleEvent(EVENT_FLIGHT_BREATH1, 72000);
|
||||
events.ScheduleEvent(EVENT_LAND_FIGHT, 86000);
|
||||
break;
|
||||
case EVENT_FLIGHT_MOVE_UP:
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 15.0f, false, true);
|
||||
break;
|
||||
case EVENT_FLIGHT_VAPOR:
|
||||
me->CastCustomSpell(SPELL_SUMMON_DEMONIC_VAPOR, SPELLVALUE_MAX_TARGETS, 1, me, true);
|
||||
break;
|
||||
case EVENT_FLIGHT_BREATH1:
|
||||
{
|
||||
Position pos = { 1447.0f + urand(0, 2) * 25.0f, 705.0f, 50.0f, 4.71f };
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START1, pos, false, true);
|
||||
break;
|
||||
}
|
||||
case EVENT_FLIGHT_BREATH2:
|
||||
{
|
||||
Position pos = { 1447.0f + urand(0, 2) * 25.0f, 515.0f, 50.0f, 1.57f };
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START2, pos, false, true);
|
||||
break;
|
||||
}
|
||||
case EVENT_FLIGHT_EMOTE:
|
||||
Talk(EMOTE_BREATH);
|
||||
break;
|
||||
case EVENT_CORRUPT_TRIGGERS:
|
||||
Talk(YELL_BREATH);
|
||||
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));
|
||||
break;
|
||||
case EVENT_FLIGHT_FLYOVER1:
|
||||
me->CastSpell(me, SPELL_FELMYST_SPEED_BURST, true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END1, me->GetPositionX(), me->GetPositionY() - 200.0f, me->GetPositionZ() + 5.0f, false, true);
|
||||
break;
|
||||
case EVENT_FLIGHT_FLYOVER2:
|
||||
me->CastSpell(me, SPELL_FELMYST_SPEED_BURST, true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END2, me->GetPositionX(), me->GetPositionY() + 200.0f, me->GetPositionZ() + 5.0f, false, true);
|
||||
break;
|
||||
case EVENT_LAND_FIGHT:
|
||||
me->GetMotionMaster()->MovePoint(POINT_GROUND, 1500.0f, 552.8f, 26.52f, false, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!me->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY))
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
class npc_demonic_vapor : public CreatureScript
|
||||
struct npc_demonic_vapor : public NullCreatureAI
|
||||
{
|
||||
public:
|
||||
npc_demonic_vapor() : CreatureScript("npc_demonic_vapor") { }
|
||||
npc_demonic_vapor(Creature* creature) : NullCreatureAI(creature) { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void Reset() override
|
||||
{
|
||||
return GetSunwellPlateauAI<npc_demonic_vaporAI>(creature);
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_SPAWN_TRIGGER, true);
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_PERIODIC, true);
|
||||
}
|
||||
|
||||
struct npc_demonic_vaporAI : public NullCreatureAI
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
{
|
||||
npc_demonic_vaporAI(Creature* creature) : NullCreatureAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
|
||||
{
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_SPAWN_TRIGGER, true);
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_PERIODIC, true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
{
|
||||
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class npc_demonic_vapor_trail : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_demonic_vapor_trail() : CreatureScript("npc_demonic_vapor_trail") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetSunwellPlateauAI<npc_demonic_vapor_trailAI>(creature);
|
||||
}
|
||||
|
||||
struct npc_demonic_vapor_trailAI : public NullCreatureAI
|
||||
{
|
||||
npc_demonic_vapor_trailAI(Creature* creature) : NullCreatureAI(creature)
|
||||
{
|
||||
timer = 1;
|
||||
}
|
||||
|
||||
uint32 timer;
|
||||
void Reset() override
|
||||
{
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_TRAIL_PERIODIC, true);
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit*, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_DEMONIC_VAPOR)
|
||||
me->CastSpell(me, SPELL_SUMMON_BLAZING_DEAD, true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (timer)
|
||||
{
|
||||
timer += diff;
|
||||
if (timer >= 6000)
|
||||
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())
|
||||
{
|
||||
timer = 0;
|
||||
me->CastSpell(me, SPELL_SUMMON_BLAZING_DEAD, true);
|
||||
me->GetMotionMaster()->MoveFollow(itr->GetSource(), 0.0f, 0.0f, MOTION_SLOT_CONTROLLED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_demonic_vapor_trail : public NullCreatureAI
|
||||
{
|
||||
npc_demonic_vapor_trail(Creature* creature) : NullCreatureAI(creature)
|
||||
{
|
||||
timer = 1;
|
||||
}
|
||||
|
||||
uint32 timer;
|
||||
void Reset() override
|
||||
{
|
||||
me->CastSpell(me, SPELL_DEMONIC_VAPOR_TRAIL_PERIODIC, true);
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit*, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_DEMONIC_VAPOR)
|
||||
me->CastSpell(me, SPELL_SUMMON_BLAZING_DEAD, true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (timer)
|
||||
{
|
||||
timer += diff;
|
||||
if (timer >= 6000)
|
||||
{
|
||||
timer = 0;
|
||||
me->CastSpell(me, SPELL_SUMMON_BLAZING_DEAD, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summon->SetInCombatWithZone();
|
||||
summon->AI()->AttackStart(summon->AI()->SelectTarget(SelectTargetMethod::Random, 0, 100.0f));
|
||||
}
|
||||
};
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summon->SetInCombatWithZone();
|
||||
summon->AI()->AttackStart(summon->AI()->SelectTarget(SelectTargetMethod::Random, 0, 100.0f));
|
||||
}
|
||||
};
|
||||
|
||||
class spell_felmyst_fog_of_corruption : public SpellScript
|
||||
@@ -558,9 +525,9 @@ class spell_felmyst_open_brutallus_back_doors : public SpellScript
|
||||
|
||||
void AddSC_boss_felmyst()
|
||||
{
|
||||
new boss_felmyst();
|
||||
new npc_demonic_vapor();
|
||||
new npc_demonic_vapor_trail();
|
||||
RegisterSunwellPlateauCreatureAI(boss_felmyst);
|
||||
RegisterSunwellPlateauCreatureAI(npc_demonic_vapor);
|
||||
RegisterSunwellPlateauCreatureAI(npc_demonic_vapor_trail);
|
||||
RegisterSpellScript(spell_felmyst_fog_of_corruption);
|
||||
RegisterSpellScript(spell_felmyst_fog_of_corruption_charm_aura);
|
||||
RegisterSpellScript(spell_felmyst_open_brutallus_back_doors);
|
||||
|
||||
@@ -114,250 +114,239 @@ enum kalEvents
|
||||
|
||||
#define DRAGON_REALM_Z 53.079f
|
||||
|
||||
class boss_kalecgos : public CreatureScript
|
||||
struct boss_kalecgos : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_kalecgos() : CreatureScript("boss_kalecgos") { }
|
||||
|
||||
struct boss_kalecgosAI : public BossAI
|
||||
boss_kalecgos(Creature* creature) : BossAI(creature, DATA_KALECGOS)
|
||||
{
|
||||
boss_kalecgosAI(Creature* creature) : BossAI(creature, DATA_KALECGOS)
|
||||
}
|
||||
|
||||
bool sathBanished;
|
||||
EventMap events2;
|
||||
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
{
|
||||
return target->GetPositionZ() > 50.0f;
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
{
|
||||
BossAI::JustReachedHome();
|
||||
me->SetVisible(true);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->SetHealth(me->GetMaxHealth());
|
||||
me->SetStandState(UNIT_STAND_STATE_SLEEP);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
|
||||
events2.Reset();
|
||||
|
||||
sathBanished = false;
|
||||
ClearPlayerAuras();
|
||||
}
|
||||
|
||||
void ClearPlayerAuras() const
|
||||
{
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_CURSE_OF_BOUNDLESS_AGONY);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_CURSE_OF_BOUNDLESS_AGONY_PLR);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SPECTRAL_REALM);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_ENRAGE || param == ACTION_ENRAGE_OTHER)
|
||||
{
|
||||
Talk(param == ACTION_ENRAGE ? SAY_KALEC_ENRAGE_SATH : SAY_SATH_ENRAGE_ME);
|
||||
me->CastSpell(me, SPELL_CRAZED_RAGE, true);
|
||||
events.CancelEvent(EVENT_CHECK_HEALTH);
|
||||
return;
|
||||
}
|
||||
|
||||
bool sathBanished;
|
||||
EventMap events2;
|
||||
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
else if (param == ACTION_BANISH)
|
||||
{
|
||||
return target->GetPositionZ() > 50.0f;
|
||||
me->CastSpell(me, SPELL_BANISH, true);
|
||||
events.Reset();
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
else if (param == ACTION_SATH_BANISH)
|
||||
sathBanished = true;
|
||||
else if (param == ACTION_KALEC_DIED)
|
||||
{
|
||||
BossAI::JustReachedHome();
|
||||
me->SetVisible(true);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->SetHealth(me->GetMaxHealth());
|
||||
me->SetStandState(UNIT_STAND_STATE_SLEEP);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
|
||||
events2.Reset();
|
||||
|
||||
sathBanished = false;
|
||||
events.Reset();
|
||||
events2.ScheduleEvent(EVENT_TALK_BAD_1, 0);
|
||||
ClearPlayerAuras();
|
||||
return;
|
||||
}
|
||||
|
||||
void ClearPlayerAuras() const
|
||||
if (me->HasAura(SPELL_BANISH) && sathBanished)
|
||||
{
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_CURSE_OF_BOUNDLESS_AGONY);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_CURSE_OF_BOUNDLESS_AGONY_PLR);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SPECTRAL_REALM);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_ENRAGE || param == ACTION_ENRAGE_OTHER)
|
||||
events.Reset();
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_1, 1000);
|
||||
ClearPlayerAuras();
|
||||
if (Creature* Sath = instance->GetCreature(DATA_SATHROVARR))
|
||||
{
|
||||
Talk(param == ACTION_ENRAGE ? SAY_KALEC_ENRAGE_SATH : SAY_SATH_ENRAGE_ME);
|
||||
me->CastSpell(me, SPELL_CRAZED_RAGE, true);
|
||||
events.CancelEvent(EVENT_CHECK_HEALTH);
|
||||
return;
|
||||
}
|
||||
else if (param == ACTION_BANISH)
|
||||
{
|
||||
me->CastSpell(me, SPELL_BANISH, true);
|
||||
events.Reset();
|
||||
}
|
||||
else if (param == ACTION_SATH_BANISH)
|
||||
sathBanished = true;
|
||||
else if (param == ACTION_KALEC_DIED)
|
||||
{
|
||||
events.Reset();
|
||||
events2.ScheduleEvent(EVENT_TALK_BAD_1, 0);
|
||||
ClearPlayerAuras();
|
||||
return;
|
||||
}
|
||||
|
||||
if (me->HasAura(SPELL_BANISH) && sathBanished)
|
||||
{
|
||||
events.Reset();
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_1, 1000);
|
||||
ClearPlayerAuras();
|
||||
if (Creature* Sath = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_SATHROVARR)))
|
||||
{
|
||||
Sath->RemoveAllAuras();
|
||||
Sath->GetMotionMaster()->MovementExpired();
|
||||
Sath->SetReactState(REACT_PASSIVE);
|
||||
Sath->NearTeleportTo(1696.20f, 915.0f, DRAGON_REALM_Z, Sath->GetOrientation());
|
||||
}
|
||||
Sath->RemoveAllAuras();
|
||||
Sath->GetMotionMaster()->MovementExpired();
|
||||
Sath->SetReactState(REACT_PASSIVE);
|
||||
Sath->NearTeleportTo(1696.20f, 915.0f, DRAGON_REALM_Z, Sath->GetOrientation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
events.ScheduleEvent(EVENT_ARCANE_BUFFET, 6000);
|
||||
events.ScheduleEvent(EVENT_FROST_BREATH, 15000);
|
||||
events.ScheduleEvent(EVENT_WILD_MAGIC, 10000);
|
||||
events.ScheduleEvent(EVENT_TAIL_LASH, 25000);
|
||||
events.ScheduleEvent(EVENT_SPECTRAL_BLAST, 20000);
|
||||
events.ScheduleEvent(EVENT_CHECK_POS, 5000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
events.ScheduleEvent(EVENT_SPAWN_SPECTRALS, 16000);
|
||||
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
Talk(SAY_EVIL_AGGRO);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && attacker != me)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && roll_chance_i(50))
|
||||
Talk(SAY_EVIL_SLAY);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_TALK_GOOD_1:
|
||||
me->SetRegeneratingHealth(false);
|
||||
me->RemoveAllAuras();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->CombatStop();
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_2, 1000);
|
||||
break;
|
||||
case EVENT_TALK_GOOD_2:
|
||||
if (Creature* Sath = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_SATHROVARR)))
|
||||
{
|
||||
summons.Despawn(Sath);
|
||||
Unit::Kill(me, Sath);
|
||||
}
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_3, 8000);
|
||||
break;
|
||||
case EVENT_TALK_GOOD_3:
|
||||
Talk(SAY_GOOD_PLRWIN);
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_4, 10000);
|
||||
break;
|
||||
case EVENT_TALK_GOOD_4:
|
||||
me->SetDisableGravity(true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_5, 10000);
|
||||
break;
|
||||
case EVENT_TALK_GOOD_5:
|
||||
me->SetVisible(false);
|
||||
me->KillSelf();
|
||||
break;
|
||||
case EVENT_TALK_BAD_1:
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->CombatStop();
|
||||
me->RemoveAllAuras();
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
Talk(SAY_EVIL_ENRAGE);
|
||||
events2.ScheduleEvent(EVENT_TALK_BAD_2, 3000);
|
||||
break;
|
||||
case EVENT_TALK_BAD_2:
|
||||
me->SetDisableGravity(true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
events2.ScheduleEvent(EVENT_TALK_BAD_3, 15000);
|
||||
break;
|
||||
case EVENT_TALK_BAD_3:
|
||||
me->SetVisible(false);
|
||||
EnterEvadeMode();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!events2.Empty())
|
||||
return;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPAWN_SPECTRALS:
|
||||
me->SummonCreature(NPC_KALEC, 1702.21f, 931.7f, -74.56f, 5.07f, TEMPSUMMON_MANUAL_DESPAWN);
|
||||
me->SummonCreature(NPC_SATHROVARR, 1704.62f, 927.78f, -73.9f, 2.0f, TEMPSUMMON_MANUAL_DESPAWN);
|
||||
break;
|
||||
case EVENT_ARCANE_BUFFET:
|
||||
me->CastSpell(me, SPELL_ARCANE_BUFFET, false);
|
||||
events.ScheduleEvent(EVENT_ARCANE_BUFFET, 8000);
|
||||
break;
|
||||
case EVENT_FROST_BREATH:
|
||||
me->CastSpell(me->GetVictim(), SPELL_FROST_BREATH, false);
|
||||
events.ScheduleEvent(EVENT_FROST_BREATH, 15000);
|
||||
break;
|
||||
case EVENT_TAIL_LASH:
|
||||
me->CastSpell(me->GetVictim(), SPELL_TAIL_LASH, false);
|
||||
events.ScheduleEvent(EVENT_TAIL_LASH, 15000);
|
||||
break;
|
||||
case EVENT_WILD_MAGIC:
|
||||
me->CastCustomSpell(RAND(44978, 45001, 45002, 45004, 45006, 45010), SPELLVALUE_MAX_TARGETS, 1, me, false);
|
||||
events.ScheduleEvent(EVENT_WILD_MAGIC, 20000);
|
||||
break;
|
||||
case EVENT_SPECTRAL_BLAST:
|
||||
me->CastSpell(me, SPELL_SPECTRAL_BLAST, false);
|
||||
events.ScheduleEvent(EVENT_SPECTRAL_BLAST, urand(15000, 25000));
|
||||
break;
|
||||
case EVENT_CHECK_POS:
|
||||
if (me->GetDistance(me->GetHomePosition()) > 50.0f)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_POS, 5000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(10))
|
||||
{
|
||||
if (Creature* Sath = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_SATHROVARR)))
|
||||
Sath->AI()->DoAction(ACTION_ENRAGE_OTHER);
|
||||
DoAction(ACTION_ENRAGE);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH2:
|
||||
if (me->HealthBelowPct(1))
|
||||
{
|
||||
DoAction(ACTION_BANISH);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_kalecgosAI>(creature);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
events.ScheduleEvent(EVENT_ARCANE_BUFFET, 6000);
|
||||
events.ScheduleEvent(EVENT_FROST_BREATH, 15000);
|
||||
events.ScheduleEvent(EVENT_WILD_MAGIC, 10000);
|
||||
events.ScheduleEvent(EVENT_TAIL_LASH, 25000);
|
||||
events.ScheduleEvent(EVENT_SPECTRAL_BLAST, 20000);
|
||||
events.ScheduleEvent(EVENT_CHECK_POS, 5000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
events.ScheduleEvent(EVENT_SPAWN_SPECTRALS, 16000);
|
||||
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
Talk(SAY_EVIL_AGGRO);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && attacker != me)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->IsPlayer() && roll_chance_i(50))
|
||||
Talk(SAY_EVIL_SLAY);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_TALK_GOOD_1:
|
||||
me->SetRegeneratingHealth(false);
|
||||
me->RemoveAllAuras();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->CombatStop();
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_2, 1000);
|
||||
break;
|
||||
case EVENT_TALK_GOOD_2:
|
||||
if (Creature* Sath = instance->GetCreature(DATA_SATHROVARR))
|
||||
{
|
||||
summons.Despawn(Sath);
|
||||
Unit::Kill(me, Sath);
|
||||
}
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_3, 8000);
|
||||
break;
|
||||
case EVENT_TALK_GOOD_3:
|
||||
Talk(SAY_GOOD_PLRWIN);
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_4, 10000);
|
||||
break;
|
||||
case EVENT_TALK_GOOD_4:
|
||||
me->SetDisableGravity(true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
events2.ScheduleEvent(EVENT_TALK_GOOD_5, 10000);
|
||||
break;
|
||||
case EVENT_TALK_GOOD_5:
|
||||
me->SetVisible(false);
|
||||
me->KillSelf();
|
||||
break;
|
||||
case EVENT_TALK_BAD_1:
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->CombatStop();
|
||||
me->RemoveAllAuras();
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
Talk(SAY_EVIL_ENRAGE);
|
||||
events2.ScheduleEvent(EVENT_TALK_BAD_2, 3000);
|
||||
break;
|
||||
case EVENT_TALK_BAD_2:
|
||||
me->SetDisableGravity(true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
events2.ScheduleEvent(EVENT_TALK_BAD_3, 15000);
|
||||
break;
|
||||
case EVENT_TALK_BAD_3:
|
||||
me->SetVisible(false);
|
||||
EnterEvadeMode();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!events2.Empty())
|
||||
return;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPAWN_SPECTRALS:
|
||||
me->SummonCreature(NPC_KALEC, 1702.21f, 931.7f, -74.56f, 5.07f, TEMPSUMMON_MANUAL_DESPAWN);
|
||||
me->SummonCreature(NPC_SATHROVARR, 1704.62f, 927.78f, -73.9f, 2.0f, TEMPSUMMON_MANUAL_DESPAWN);
|
||||
break;
|
||||
case EVENT_ARCANE_BUFFET:
|
||||
me->CastSpell(me, SPELL_ARCANE_BUFFET, false);
|
||||
events.ScheduleEvent(EVENT_ARCANE_BUFFET, 8000);
|
||||
break;
|
||||
case EVENT_FROST_BREATH:
|
||||
me->CastSpell(me->GetVictim(), SPELL_FROST_BREATH, false);
|
||||
events.ScheduleEvent(EVENT_FROST_BREATH, 15000);
|
||||
break;
|
||||
case EVENT_TAIL_LASH:
|
||||
me->CastSpell(me->GetVictim(), SPELL_TAIL_LASH, false);
|
||||
events.ScheduleEvent(EVENT_TAIL_LASH, 15000);
|
||||
break;
|
||||
case EVENT_WILD_MAGIC:
|
||||
me->CastCustomSpell(RAND(44978, 45001, 45002, 45004, 45006, 45010), SPELLVALUE_MAX_TARGETS, 1, me, false);
|
||||
events.ScheduleEvent(EVENT_WILD_MAGIC, 20000);
|
||||
break;
|
||||
case EVENT_SPECTRAL_BLAST:
|
||||
me->CastSpell(me, SPELL_SPECTRAL_BLAST, false);
|
||||
events.ScheduleEvent(EVENT_SPECTRAL_BLAST, urand(15000, 25000));
|
||||
break;
|
||||
case EVENT_CHECK_POS:
|
||||
if (me->GetDistance(me->GetHomePosition()) > 50.0f)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_POS, 5000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(10))
|
||||
{
|
||||
if (Creature* Sath = instance->GetCreature(DATA_SATHROVARR))
|
||||
Sath->AI()->DoAction(ACTION_ENRAGE_OTHER);
|
||||
DoAction(ACTION_ENRAGE);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH2:
|
||||
if (me->HealthBelowPct(1))
|
||||
{
|
||||
DoAction(ACTION_BANISH);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -371,255 +360,233 @@ enum Kalec
|
||||
EVENT_KALEC_SCENE_3 = 103
|
||||
};
|
||||
|
||||
class boss_kalec : public CreatureScript
|
||||
struct boss_kalec : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_kalec() : CreatureScript("boss_kalec") { }
|
||||
boss_kalec(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
EventMap events;
|
||||
EventMap events2;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_kalecAI>(creature);
|
||||
events.Reset();
|
||||
events2.Reset();
|
||||
if (me->GetPositionY() < 750.0f)
|
||||
{
|
||||
me->SetSpeed(MOVE_RUN, 2.4f);
|
||||
me->SetDisplayId(MODEL_KALECGOS_DRAGON);
|
||||
me->SetDisableGravity(true);
|
||||
me->GetMotionMaster()->MovePoint(0, 1483.30f, 657.99f, 28.0f, false, true);
|
||||
events2.ScheduleEvent(EVENT_KALEC_SCENE_1, 9000);
|
||||
events2.ScheduleEvent(EVENT_KALEC_SCENE_2, 16000);
|
||||
events2.ScheduleEvent(EVENT_KALEC_SCENE_3, 22000);
|
||||
}
|
||||
else
|
||||
me->CastSpell(me, SPELL_SPECTRAL_INVISIBILITY, true);
|
||||
}
|
||||
|
||||
struct boss_kalecAI : public ScriptedAI
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
boss_kalecAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
if (!who || who->GetEntry() != NPC_SATHROVARR)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
EventMap events;
|
||||
EventMap events2;
|
||||
void JustEngagedWith(Unit*) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
events.ScheduleEvent(EVENT_SPELL_REVITALIZE, 5000);
|
||||
events.ScheduleEvent(EVENT_SPELL_HEROIC_STRIKE, 3000);
|
||||
Talk(SAY_GOOD_AGGRO);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS))
|
||||
kalecgos->AI()->DoAction(ACTION_KALEC_DIED);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (events2.ExecuteEvent())
|
||||
{
|
||||
events.Reset();
|
||||
events2.Reset();
|
||||
if (me->GetPositionY() < 750.0f)
|
||||
case EVENT_KALEC_SCENE_1:
|
||||
Talk(SAY_GOOD_MADRIGOSA);
|
||||
me->GetMotionMaster()->MovePoint(0, 1509.0f, 560.0f, 30.0f, false, true);
|
||||
break;
|
||||
case EVENT_KALEC_SCENE_2:
|
||||
me->CastSpell(me, SPELL_OPEN_BRUTALLUS_BACK_DOOR, true);
|
||||
me->GetInstanceScript()->SetBossState(DATA_FELMYST_DOORS, NOT_STARTED);
|
||||
me->GetInstanceScript()->SetBossState(DATA_FELMYST_DOORS, DONE);
|
||||
break;
|
||||
case EVENT_KALEC_SCENE_3:
|
||||
me->GetMotionMaster()->MovePoint(0, 1400.0f, 630.0f, 90.0f, false, true);
|
||||
me->DespawnOrUnsummon(6000);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(50))
|
||||
{
|
||||
me->SetSpeed(MOVE_RUN, 2.4f);
|
||||
me->SetDisplayId(MODEL_KALECGOS_DRAGON);
|
||||
me->SetDisableGravity(true);
|
||||
me->GetMotionMaster()->MovePoint(0, 1483.30f, 657.99f, 28.0f, false, true);
|
||||
events2.ScheduleEvent(EVENT_KALEC_SCENE_1, 9000);
|
||||
events2.ScheduleEvent(EVENT_KALEC_SCENE_2, 16000);
|
||||
events2.ScheduleEvent(EVENT_KALEC_SCENE_3, 22000);
|
||||
Talk(SAY_GOOD_NEAR_DEATH);
|
||||
break;
|
||||
}
|
||||
else
|
||||
me->CastSpell(me, SPELL_SPECTRAL_INVISIBILITY, true);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (!who || who->GetEntry() != NPC_SATHROVARR)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit*) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH2:
|
||||
if (me->HealthBelowPct(10))
|
||||
{
|
||||
Talk(SAY_GOOD_NEAR_DEATH2);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
events.ScheduleEvent(EVENT_SPELL_REVITALIZE, 5000);
|
||||
events.ScheduleEvent(EVENT_SPELL_HEROIC_STRIKE, 3000);
|
||||
Talk(SAY_GOOD_AGGRO);
|
||||
break;
|
||||
case EVENT_SPELL_REVITALIZE:
|
||||
me->CastSpell(me, SPELL_REVITALIZE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_REVITALIZE, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_HEROIC_STRIKE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_HEROIC_STRIKE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_HEROIC_STRIKE, 5000);
|
||||
break;
|
||||
}
|
||||
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* kalecgos = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_KALECGOS)))
|
||||
kalecgos->AI()->DoAction(ACTION_KALEC_DIED);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_KALEC_SCENE_1:
|
||||
Talk(SAY_GOOD_MADRIGOSA);
|
||||
me->GetMotionMaster()->MovePoint(0, 1509.0f, 560.0f, 30.0f, false, true);
|
||||
break;
|
||||
case EVENT_KALEC_SCENE_2:
|
||||
me->CastSpell(me, SPELL_OPEN_BRUTALLUS_BACK_DOOR, true);
|
||||
me->GetInstanceScript()->SetBossState(DATA_FELMYST_DOORS, NOT_STARTED);
|
||||
me->GetInstanceScript()->SetBossState(DATA_FELMYST_DOORS, DONE);
|
||||
break;
|
||||
case EVENT_KALEC_SCENE_3:
|
||||
me->GetMotionMaster()->MovePoint(0, 1400.0f, 630.0f, 90.0f, false, true);
|
||||
me->DespawnOrUnsummon(6000);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(50))
|
||||
{
|
||||
Talk(SAY_GOOD_NEAR_DEATH);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH2:
|
||||
if (me->HealthBelowPct(10))
|
||||
{
|
||||
Talk(SAY_GOOD_NEAR_DEATH2);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
break;
|
||||
case EVENT_SPELL_REVITALIZE:
|
||||
me->CastSpell(me, SPELL_REVITALIZE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_REVITALIZE, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_HEROIC_STRIKE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_HEROIC_STRIKE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_HEROIC_STRIKE, 5000);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
class boss_sathrovarr : public CreatureScript
|
||||
struct boss_sathrovarr : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_sathrovarr() : CreatureScript("boss_sathrovarr") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_sathrovarr(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_sathrovarrAI>(creature);
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
struct boss_sathrovarrAI : public ScriptedAI
|
||||
InstanceScript* instance;
|
||||
EventMap events;
|
||||
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
{
|
||||
boss_sathrovarrAI(Creature* creature) : ScriptedAI(creature)
|
||||
return target->GetPositionZ() < 50.0f;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
me->CastSpell(me, SPELL_DEMONIC_VISUAL, true);
|
||||
me->CastSpell(me, SPELL_SPECTRAL_INVISIBILITY, true);
|
||||
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 7000);
|
||||
events.ScheduleEvent(EVENT_AGONY_CURSE, 20000);
|
||||
events.ScheduleEvent(EVENT_CORRUPTION_STRIKE, 13000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_SATH_AGGRO);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && who != me)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* target) override
|
||||
{
|
||||
if (target->IsPlayer())
|
||||
Talk(SAY_SATH_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_SATH_DEATH);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_ENRAGE || param == ACTION_ENRAGE_OTHER)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
me->CastSpell(me, SPELL_CRAZED_RAGE, true);
|
||||
events.CancelEvent(EVENT_CHECK_HEALTH);
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
EventMap events;
|
||||
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
{
|
||||
return target->GetPositionZ() < 50.0f;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
else if (param == ACTION_BANISH)
|
||||
{
|
||||
me->CastSpell(me, SPELL_BANISH, true);
|
||||
events.Reset();
|
||||
me->CastSpell(me, SPELL_DEMONIC_VISUAL, true);
|
||||
me->CastSpell(me, SPELL_SPECTRAL_INVISIBILITY, true);
|
||||
}
|
||||
}
|
||||
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 7000);
|
||||
events.ScheduleEvent(EVENT_AGONY_CURSE, 20000);
|
||||
events.ScheduleEvent(EVENT_CORRUPTION_STRIKE, 13000);
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SHADOW_BOLT:
|
||||
if (roll_chance_i(20))
|
||||
Talk(SAY_SATH_SPELL1);
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 9000);
|
||||
break;
|
||||
case EVENT_AGONY_CURSE:
|
||||
me->CastCustomSpell(SPELL_CURSE_OF_BOUNDLESS_AGONY, SPELLVALUE_MAX_TARGETS, 1, me, false);
|
||||
events.ScheduleEvent(EVENT_AGONY_CURSE, 30000);
|
||||
break;
|
||||
case EVENT_CORRUPTION_STRIKE:
|
||||
if (roll_chance_i(20))
|
||||
Talk(SAY_SATH_SPELL2);
|
||||
me->CastSpell(me->GetVictim(), SPELL_CORRUPTION_STRIKE, false);
|
||||
events.ScheduleEvent(EVENT_CORRUPTION_STRIKE, 9000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(10))
|
||||
{
|
||||
if (InstanceScript* instanceScript = me->GetInstanceScript())
|
||||
{
|
||||
if (Creature* kalecgos = ObjectAccessor::GetCreature(*me, instanceScript->GetGuidData(
|
||||
NPC_KALECGOS)))
|
||||
{
|
||||
kalecgos->AI()->DoAction(ACTION_ENRAGE_OTHER);
|
||||
}
|
||||
}
|
||||
DoAction(ACTION_ENRAGE);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH2:
|
||||
if (me->HealthBelowPct(1))
|
||||
{
|
||||
if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS))
|
||||
kalecgos->AI()->DoAction(ACTION_SATH_BANISH);
|
||||
DoAction(ACTION_BANISH);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
break;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_SATH_AGGRO);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && who != me)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* target) override
|
||||
{
|
||||
if (target->IsPlayer())
|
||||
Talk(SAY_SATH_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_SATH_DEATH);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_ENRAGE || param == ACTION_ENRAGE_OTHER)
|
||||
{
|
||||
me->CastSpell(me, SPELL_CRAZED_RAGE, true);
|
||||
events.CancelEvent(EVENT_CHECK_HEALTH);
|
||||
}
|
||||
else if (param == ACTION_BANISH)
|
||||
{
|
||||
me->CastSpell(me, SPELL_BANISH, true);
|
||||
events.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SHADOW_BOLT:
|
||||
if (roll_chance_i(20))
|
||||
Talk(SAY_SATH_SPELL1);
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 9000);
|
||||
break;
|
||||
case EVENT_AGONY_CURSE:
|
||||
me->CastCustomSpell(SPELL_CURSE_OF_BOUNDLESS_AGONY, SPELLVALUE_MAX_TARGETS, 1, me, false);
|
||||
events.ScheduleEvent(EVENT_AGONY_CURSE, 30000);
|
||||
break;
|
||||
case EVENT_CORRUPTION_STRIKE:
|
||||
if (roll_chance_i(20))
|
||||
Talk(SAY_SATH_SPELL2);
|
||||
me->CastSpell(me->GetVictim(), SPELL_CORRUPTION_STRIKE, false);
|
||||
events.ScheduleEvent(EVENT_CORRUPTION_STRIKE, 9000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(10))
|
||||
{
|
||||
if (InstanceScript* instanceScript = me->GetInstanceScript())
|
||||
{
|
||||
if (Creature *kalecgos = ObjectAccessor::GetCreature(*me, instanceScript->GetGuidData(
|
||||
NPC_KALECGOS)))
|
||||
{
|
||||
kalecgos->AI()->DoAction(ACTION_ENRAGE_OTHER);
|
||||
}
|
||||
}
|
||||
DoAction(ACTION_ENRAGE);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH2:
|
||||
if (me->HealthBelowPct(1))
|
||||
{
|
||||
if (Creature* kalecgos = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_KALECGOS)))
|
||||
kalecgos->AI()->DoAction(ACTION_SATH_BANISH);
|
||||
DoAction(ACTION_BANISH);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
class SpectralBlastCheck
|
||||
@@ -750,9 +717,9 @@ class spell_kalecgos_spectral_realm_aura : public AuraScript
|
||||
|
||||
void AddSC_boss_kalecgos()
|
||||
{
|
||||
new boss_kalecgos();
|
||||
new boss_sathrovarr();
|
||||
new boss_kalec();
|
||||
RegisterSunwellPlateauCreatureAI(boss_kalecgos);
|
||||
RegisterSunwellPlateauCreatureAI(boss_sathrovarr);
|
||||
RegisterSunwellPlateauCreatureAI(boss_kalec);
|
||||
RegisterSpellScript(spell_kalecgos_spectral_blast_dummy);
|
||||
RegisterSpellScript(spell_kalecgos_curse_of_boundless_agony_aura);
|
||||
RegisterSpellScript(spell_kalecgos_spectral_realm_dummy);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,6 @@ enum Spells
|
||||
// Entropius's spells
|
||||
SPELL_ENTROPIUS_COSMETIC_SPAWN = 46223,
|
||||
SPELL_NEGATIVE_ENERGY_PERIODIC = 46284,
|
||||
SPELL_NEGATIVE_ENERGY_CHAIN = 46285,
|
||||
SPELL_BLACK_HOLE = 46282,
|
||||
SPELL_DARKNESS = 46268,
|
||||
SPELL_SUMMON_DARK_FIEND_ENTROPIUS = 46263,
|
||||
@@ -55,277 +54,159 @@ enum Spells
|
||||
SPELL_BLACK_HOLE_EFFECT = 46230
|
||||
};
|
||||
|
||||
enum Misc
|
||||
struct boss_muru : public BossAI
|
||||
{
|
||||
EVENT_SPELL_ENRAGE = 1,
|
||||
EVENT_SUMMON_ENTROPIUS = 2,
|
||||
EVENT_SET_INVISIBLE = 3,
|
||||
EVENT_SPAWN_BLACK_HOLE = 4,
|
||||
EVENT_SPAWN_DARKNESS = 5,
|
||||
EVENT_START_BLACK_HOLE = 6,
|
||||
EVENT_SWITCH_BLACK_HOLE_TARGET = 7,
|
||||
EVENT_ENTROPIUS_AURAS = 8,
|
||||
EVENT_ENTROPIUS_COMBAT = 9,
|
||||
EVENT_SINGULARITY_DEATH = 10,
|
||||
boss_muru(Creature* creature) : BossAI(creature, DATA_MURU) { }
|
||||
|
||||
DATA_ENRAGE_TIMER = 1,
|
||||
DATA_NEGATIVE_ENERGY_TARGETS = 2
|
||||
};
|
||||
|
||||
class boss_muru : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_muru() : CreatureScript("boss_muru") { }
|
||||
|
||||
struct boss_muruAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_muruAI(Creature* creature) : BossAI(creature, DATA_MURU) { }
|
||||
BossAI::Reset();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetVisible(true);
|
||||
me->m_Events.KillAllEvents(false);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
DoCastSelf(SPELL_NEGATIVE_ENERGY, true);
|
||||
DoCastSelf(SPELL_SUMMON_BLOOD_ELVES_PERIODIC, true);
|
||||
DoCastSelf(SPELL_OPEN_PORTAL_PERIODIC, true);
|
||||
DoCastSelf(SPELL_DARKNESS_PERIODIC, true);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
DoCastSelf(SPELL_ENRAGE, true);
|
||||
|
||||
if (Creature* entropius = summons.GetCreatureWithEntry(NPC_ENTROPIUS))
|
||||
entropius->CastSpell(entropius, SPELL_ENRAGE, true);
|
||||
}, 10min);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (damage >= me->GetHealth())
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetVisible(true);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
me->CastSpell(me, SPELL_NEGATIVE_ENERGY, true);
|
||||
me->CastSpell(me, SPELL_SUMMON_BLOOD_ELVES_PERIODIC, true);
|
||||
me->CastSpell(me, SPELL_OPEN_PORTAL_PERIODIC, true);
|
||||
me->CastSpell(me, SPELL_DARKNESS_PERIODIC, true);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 600000);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (damage >= me->GetHealth())
|
||||
damage = me->GetHealth() - 1;
|
||||
if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
{
|
||||
damage = 0;
|
||||
if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->RemoveAllAuras();
|
||||
DoCastSelf(SPELL_OPEN_ALL_PORTALS, true);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&]
|
||||
{
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->RemoveAllAuras();
|
||||
me->CastSpell(me, SPELL_OPEN_ALL_PORTALS, true);
|
||||
events.ScheduleEvent(EVENT_SUMMON_ENTROPIUS, 7000);
|
||||
}
|
||||
}
|
||||
}
|
||||
DoCastAOE(SPELL_SUMMON_ENTROPIUS);
|
||||
}, 7s);
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
if (summon->GetEntry() == NPC_ENTROPIUS)
|
||||
summon->AI()->SetData(DATA_ENRAGE_TIMER, events.GetNextEventTime(EVENT_SPELL_ENRAGE));
|
||||
else
|
||||
{
|
||||
if (!summon->IsTrigger())
|
||||
summon->SetInCombatWithZone();
|
||||
summons.Summon(summon);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_ENRAGE:
|
||||
me->CastSpell(me, SPELL_ENRAGE, true);
|
||||
break;
|
||||
case EVENT_SUMMON_ENTROPIUS:
|
||||
me->CastSpell(me, SPELL_SUMMON_ENTROPIUS, false);
|
||||
events.ScheduleEvent(EVENT_SET_INVISIBLE, 1000);
|
||||
break;
|
||||
case EVENT_SET_INVISIBLE:
|
||||
me->m_Events.AddEventAtOffset([&]
|
||||
{
|
||||
me->SetVisible(false);
|
||||
break;
|
||||
}, 8s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_muruAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_entropius : public CreatureScript
|
||||
struct boss_entropius : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_entropius() : CreatureScript("boss_entropius") { }
|
||||
boss_entropius(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
struct boss_entropiusAI : public ScriptedAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_entropiusAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
scheduler.CancelAll();
|
||||
|
||||
EventMap events;
|
||||
EventMap events2;
|
||||
DoCastSelf(SPELL_ENTROPIUS_COSMETIC_SPAWN);
|
||||
DoCastSelf(SPELL_NEGATIVE_ENERGY_PERIODIC, true);
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
events2.Reset();
|
||||
events2.ScheduleEvent(EVENT_ENTROPIUS_AURAS, 0);
|
||||
events2.ScheduleEvent(EVENT_ENTROPIUS_COMBAT, 3000);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* muru = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_MURU)))
|
||||
if (!muru->IsInEvadeMode())
|
||||
muru->AI()->EnterEvadeMode(why);
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetInCombatWithZone();
|
||||
AttackStart(SelectTargetFromPlayerList(50.0f));
|
||||
}, 3s);
|
||||
}
|
||||
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_SPAWN_BLACK_HOLE, 15000);
|
||||
events.ScheduleEvent(EVENT_SPAWN_DARKNESS, 10000);
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
{
|
||||
if (type == DATA_ENRAGE_TIMER)
|
||||
events.ScheduleEvent(EVENT_SPELL_ENRAGE, data);
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 type) const override
|
||||
{
|
||||
if (type == DATA_NEGATIVE_ENERGY_TARGETS)
|
||||
return 1 + uint32(events.GetTimer() / 12000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* muru = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_MURU)))
|
||||
Unit::Kill(muru, muru);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_ENTROPIUS_AURAS:
|
||||
me->CastSpell(me, SPELL_ENTROPIUS_COSMETIC_SPAWN, false);
|
||||
me->CastSpell(me, SPELL_NEGATIVE_ENERGY_PERIODIC, true);
|
||||
break;
|
||||
case EVENT_ENTROPIUS_COMBAT:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetInCombatWithZone();
|
||||
AttackStart(SelectTargetFromPlayerList(50.0f));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!events2.Empty())
|
||||
return;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_ENRAGE:
|
||||
me->CastSpell(me, SPELL_ENRAGE, true);
|
||||
break;
|
||||
case EVENT_SPAWN_DARKNESS:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
|
||||
me->CastSpell(target, SPELL_DARKNESS, true);
|
||||
events.ScheduleEvent(EVENT_SPAWN_DARKNESS, 15000);
|
||||
break;
|
||||
case EVENT_SPAWN_BLACK_HOLE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
|
||||
me->CastSpell(target, SPELL_BLACK_HOLE, true);
|
||||
events.ScheduleEvent(EVENT_SPAWN_BLACK_HOLE, 15000);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
return GetSunwellPlateauAI<boss_entropiusAI>(creature);
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* muru = instance->GetCreature(DATA_MURU))
|
||||
if (!muru->IsInEvadeMode())
|
||||
muru->AI()->EnterEvadeMode(why);
|
||||
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
ScheduleTimedEvent(10s, [&] {
|
||||
DoCastRandomTarget(SPELL_DARKNESS, 0, 50.0f, true, true);
|
||||
}, 15s);
|
||||
|
||||
ScheduleTimedEvent(15s, [&] {
|
||||
DoCastRandomTarget(SPELL_BLACK_HOLE, 0, 50.0f, true, true);
|
||||
}, 15s);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* muru = instance->GetCreature(DATA_MURU))
|
||||
muru->KillSelf();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_singularity : public CreatureScript
|
||||
struct npc_singularity : public NullCreatureAI
|
||||
{
|
||||
public:
|
||||
npc_singularity() : CreatureScript("npc_singularity") { }
|
||||
npc_singularity(Creature* creature) : NullCreatureAI(creature) { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void Reset() override
|
||||
{
|
||||
return GetSunwellPlateauAI<npc_singularityAI>(creature);
|
||||
}
|
||||
me->DespawnOrUnsummon(18000);
|
||||
DoCastSelf(SPELL_BLACK_HOLE_SUMMON_VISUAL, true);
|
||||
DoCastSelf(SPELL_BLACK_HOLE_SUMMON_VISUAL2, true);
|
||||
|
||||
struct npc_singularityAI : public NullCreatureAI
|
||||
{
|
||||
npc_singularityAI(Creature* creature) : NullCreatureAI(creature)
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
EventMap events;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->DespawnOrUnsummon(18000);
|
||||
me->CastSpell(me, SPELL_BLACK_HOLE_SUMMON_VISUAL, true);
|
||||
me->CastSpell(me, SPELL_BLACK_HOLE_SUMMON_VISUAL2, true);
|
||||
events.ScheduleEvent(EVENT_START_BLACK_HOLE, 3500);
|
||||
events.ScheduleEvent(EVENT_SWITCH_BLACK_HOLE_TARGET, 5000);
|
||||
events.ScheduleEvent(EVENT_SINGULARITY_DEATH, 17000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
switch (events.ExecuteEvent())
|
||||
auto const& playerList = me->GetMap()->GetPlayers();
|
||||
for (auto const& playerRef : playerList)
|
||||
{
|
||||
case EVENT_SINGULARITY_DEATH:
|
||||
me->KillSelf();
|
||||
break;
|
||||
case EVENT_START_BLACK_HOLE:
|
||||
me->RemoveAurasDueToSpell(SPELL_BLACK_HOLE_SUMMON_VISUAL2);
|
||||
me->CastSpell(me, SPELL_BLACK_HOLE_VISUAL2, true);
|
||||
me->CastSpell(me, SPELL_BLACK_HOLE_PASSIVE, true);
|
||||
break;
|
||||
case EVENT_SWITCH_BLACK_HOLE_TARGET:
|
||||
if (Player* player = playerRef.GetSource())
|
||||
if (me->GetDistance2d(player) < 15.0f && player->GetPositionZ() < 72.0f && player->IsAlive() && !player->HasAura(SPELL_BLACK_HOLE_EFFECT))
|
||||
{
|
||||
Map::PlayerList const& players = me->GetMap()->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
if (Player* player = itr->GetSource())
|
||||
if (me->GetDistance2d(player) < 15.0f && player->GetPositionZ() < 72.0f && player->IsAlive() && !player->HasAura(SPELL_BLACK_HOLE_EFFECT))
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(0, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), false, true);
|
||||
events.ScheduleEvent(EVENT_SWITCH_BLACK_HOLE_TARGET, 5000);
|
||||
return;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_SWITCH_BLACK_HOLE_TARGET, 500);
|
||||
break;
|
||||
me->GetMotionMaster()->MovePoint(0, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), false, true);
|
||||
context.Repeat();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
context.Repeat(1s);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_muru_summon_blood_elves_periodic_aura : public AuraScript
|
||||
@@ -382,39 +263,6 @@ class spell_muru_darkness_aura : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_entropius_negative_energy : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_entropius_negative_energy);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_NEGATIVE_ENERGY_CHAIN });
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->IsCreature();
|
||||
}
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
Acore::Containers::RandomResize(targets, GetCaster()->GetAI()->GetData(DATA_NEGATIVE_ENERGY_TARGETS));
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
if (Unit* target = GetHitUnit())
|
||||
GetCaster()->CastSpell(target, SPELL_NEGATIVE_ENERGY_CHAIN, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_entropius_negative_energy::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_entropius_negative_energy::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_entropius_void_zone_visual_aura : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_entropius_void_zone_visual_aura);
|
||||
@@ -473,15 +321,38 @@ class spell_entropius_black_hole_effect : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 46284 - Negative Energy Periodic
|
||||
class spell_entropius_negative_energy_periodic : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_entropius_negative_energy_periodic);
|
||||
|
||||
bool Validate(SpellInfo const* spellInfo) override
|
||||
{
|
||||
return ValidateSpellInfo({ spellInfo->Effects[EFFECT_0].TriggerSpell });
|
||||
}
|
||||
|
||||
void PeriodicTick(AuraEffect const* aurEff)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
uint32 targetCount = aurEff->GetTickNumber() > 12 ? 1 : aurEff->GetTickNumber() / 12;
|
||||
GetTarget()->CastCustomSpell(aurEff->GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, SPELLVALUE_MAX_TARGETS, targetCount);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_entropius_negative_energy_periodic::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_muru()
|
||||
{
|
||||
new boss_muru();
|
||||
new boss_entropius();
|
||||
new npc_singularity();
|
||||
RegisterSunwellPlateauCreatureAI(boss_muru);
|
||||
RegisterSunwellPlateauCreatureAI(boss_entropius);
|
||||
RegisterSunwellPlateauCreatureAI(npc_singularity);
|
||||
|
||||
RegisterSpellScript(spell_muru_summon_blood_elves_periodic_aura);
|
||||
RegisterSpellScript(spell_muru_darkness_aura);
|
||||
RegisterSpellScript(spell_entropius_negative_energy);
|
||||
RegisterSpellScript(spell_entropius_void_zone_visual_aura);
|
||||
RegisterSpellScript(spell_entropius_black_hole_effect);
|
||||
RegisterSpellScript(spell_entropius_negative_energy_periodic);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,32 @@ DoorData const doorData[] =
|
||||
{ 0, 0, DOOR_TYPE_ROOM } // END
|
||||
};
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_KALECGOS, DATA_KALECGOS },
|
||||
{ NPC_BRUTALLUS, DATA_BRUTALLUS },
|
||||
{ NPC_FELMYST, DATA_FELMYST },
|
||||
{ NPC_MURU, DATA_MURU },
|
||||
{ NPC_LADY_SACROLASH, DATA_SACROLASH },
|
||||
{ NPC_GRAND_WARLOCK_ALYTHESS, DATA_ALYTHESS },
|
||||
{ NPC_MADRIGOSA, DATA_MADRIGOSA },
|
||||
{ NPC_SATHROVARR, DATA_SATHROVARR },
|
||||
{ NPC_KILJAEDEN_CONTROLLER, DATA_KJ_CONTROLLER },
|
||||
{ NPC_ANVEENA, DATA_ANVEENA },
|
||||
{ NPC_KALECGOS_KJ, DATA_KALECGOS_KJ },
|
||||
{ 0, 0, }
|
||||
};
|
||||
|
||||
ObjectData const gameObjectData[] =
|
||||
{
|
||||
{ GO_ICE_BARRIER, DATA_ICEBARRIER },
|
||||
{ GO_ORB_OF_THE_BLUE_DRAGONFLIGHT1, DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1 },
|
||||
{ GO_ORB_OF_THE_BLUE_DRAGONFLIGHT2, DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_2 },
|
||||
{ GO_ORB_OF_THE_BLUE_DRAGONFLIGHT3, DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3 },
|
||||
{ GO_ORB_OF_THE_BLUE_DRAGONFLIGHT4, DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
class instance_sunwell_plateau : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -45,35 +71,17 @@ public:
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(MAX_ENCOUNTERS);
|
||||
LoadDoorData(doorData);
|
||||
LoadObjectData(creatureData, gameObjectData);
|
||||
}
|
||||
|
||||
void OnPlayerEnter(Player* player) override
|
||||
{
|
||||
instance->LoadGrid(1477.94f, 643.22f);
|
||||
instance->LoadGrid(1641.45f, 988.08f);
|
||||
if (GameObject* gobj = instance->GetGameObject(IceBarrierGUID))
|
||||
if (GameObject* gobj = GetGameObject(DATA_ICEBARRIER))
|
||||
gobj->SendUpdateToPlayer(player);
|
||||
}
|
||||
|
||||
Player const* GetPlayerInMap() const
|
||||
{
|
||||
Map::PlayerList const& players = instance->GetPlayers();
|
||||
|
||||
if (!players.IsEmpty())
|
||||
{
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
{
|
||||
Player* player = itr->GetSource();
|
||||
if (player && !player->HasAura(45839))
|
||||
return player;
|
||||
}
|
||||
}
|
||||
//else
|
||||
// LOG_DEBUG("scripts", "Instance Sunwell Plateau: GetPlayerInMap, but PlayerList is empty!");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
{
|
||||
if (creature->GetSpawnId() > 0 || !creature->GetOwnerGUID().IsPlayer())
|
||||
@@ -81,177 +89,32 @@ public:
|
||||
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_KALECGOS:
|
||||
KalecgosDragonGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_SATHROVARR:
|
||||
SathrovarrGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_BRUTALLUS:
|
||||
BrutallusGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_MADRIGOSA:
|
||||
MadrigosaGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_FELMYST:
|
||||
FelmystGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_GRAND_WARLOCK_ALYTHESS:
|
||||
AlythessGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_LADY_SACROLASH:
|
||||
SacrolashGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_MURU:
|
||||
MuruGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_KILJAEDEN:
|
||||
KilJaedenGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_KILJAEDEN_CONTROLLER:
|
||||
KilJaedenControllerGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_ANVEENA:
|
||||
AnveenaGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_KALECGOS_KJ:
|
||||
KalecgosKjGUID = creature->GetGUID();
|
||||
break;
|
||||
|
||||
// Xinef: Felmyst encounter
|
||||
case NPC_DEMONIC_VAPOR_TRAIL:
|
||||
case NPC_UNYIELDING_DEAD:
|
||||
if (Creature* felmyst = instance->GetCreature(FelmystGUID))
|
||||
if (Creature* felmyst = GetCreature(DATA_FELMYST))
|
||||
felmyst->AI()->JustSummoned(creature);
|
||||
break;
|
||||
|
||||
// Xinef: M'uru encounter
|
||||
case NPC_DARKNESS:
|
||||
case NPC_VOID_SENTINEL:
|
||||
case NPC_VOID_SPAWN:
|
||||
if (Creature* muru = instance->GetCreature(MuruGUID))
|
||||
if (Creature* muru = GetCreature(DATA_MURU))
|
||||
muru->AI()->JustSummoned(creature);
|
||||
break;
|
||||
|
||||
// Xinef: Kil'jaeden encounter
|
||||
case NPC_FELFIRE_PORTAL:
|
||||
case NPC_VOLATILE_FELFIRE_FIEND:
|
||||
case NPC_SHIELD_ORB:
|
||||
case NPC_SINISTER_REFLECTION:
|
||||
if (Creature* kiljaedenC = instance->GetCreature(KilJaedenControllerGUID))
|
||||
if (Creature* kiljaedenC = GetCreature(DATA_KJ_CONTROLLER))
|
||||
kiljaedenC->AI()->JustSummoned(creature);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_FORCE_FIELD:
|
||||
case GO_BOSS_COLLISION_1:
|
||||
case GO_BOSS_COLLISION_2:
|
||||
case GO_FIRE_BARRIER:
|
||||
case GO_MURUS_GATE_1:
|
||||
case GO_MURUS_GATE_2:
|
||||
AddDoor(go);
|
||||
break;
|
||||
case GO_ICE_BARRIER:
|
||||
IceBarrierGUID = go->GetGUID();
|
||||
go->setActive(true);
|
||||
break;
|
||||
case GO_ORB_OF_THE_BLUE_DRAGONFLIGHT1:
|
||||
blueFlightOrbGUID[0] = go->GetGUID();
|
||||
break;
|
||||
case GO_ORB_OF_THE_BLUE_DRAGONFLIGHT2:
|
||||
blueFlightOrbGUID[1] = go->GetGUID();
|
||||
break;
|
||||
case GO_ORB_OF_THE_BLUE_DRAGONFLIGHT3:
|
||||
blueFlightOrbGUID[2] = go->GetGUID();
|
||||
break;
|
||||
case GO_ORB_OF_THE_BLUE_DRAGONFLIGHT4:
|
||||
blueFlightOrbGUID[3] = go->GetGUID();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectRemove(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_FIRE_BARRIER:
|
||||
case GO_MURUS_GATE_1:
|
||||
case GO_MURUS_GATE_2:
|
||||
case GO_BOSS_COLLISION_1:
|
||||
case GO_BOSS_COLLISION_2:
|
||||
case GO_FORCE_FIELD:
|
||||
RemoveDoor(go);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 id) const override
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case NPC_KALECGOS:
|
||||
return KalecgosDragonGUID;
|
||||
case NPC_SATHROVARR:
|
||||
return SathrovarrGUID;
|
||||
case NPC_BRUTALLUS:
|
||||
return BrutallusGUID;
|
||||
case NPC_MADRIGOSA:
|
||||
return MadrigosaGUID;
|
||||
case NPC_FELMYST:
|
||||
return FelmystGUID;
|
||||
case NPC_GRAND_WARLOCK_ALYTHESS:
|
||||
return AlythessGUID;
|
||||
case NPC_LADY_SACROLASH:
|
||||
return SacrolashGUID;
|
||||
case NPC_MURU:
|
||||
return MuruGUID;
|
||||
case NPC_ANVEENA:
|
||||
return AnveenaGUID;
|
||||
case NPC_KALECGOS_KJ:
|
||||
return KalecgosKjGUID;
|
||||
case NPC_KILJAEDEN_CONTROLLER:
|
||||
return KilJaedenControllerGUID;
|
||||
case NPC_KILJAEDEN:
|
||||
return KilJaedenGUID;
|
||||
|
||||
// Orbs
|
||||
case DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1:
|
||||
case DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_2:
|
||||
case DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3:
|
||||
case DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4:
|
||||
return blueFlightOrbGUID[id - DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1];
|
||||
}
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
protected:
|
||||
ObjectGuid KalecgosDragonGUID;
|
||||
ObjectGuid SathrovarrGUID;
|
||||
ObjectGuid BrutallusGUID;
|
||||
ObjectGuid MadrigosaGUID;
|
||||
ObjectGuid FelmystGUID;
|
||||
ObjectGuid AlythessGUID;
|
||||
ObjectGuid SacrolashGUID;
|
||||
ObjectGuid MuruGUID;
|
||||
ObjectGuid KilJaedenGUID;
|
||||
ObjectGuid KilJaedenControllerGUID;
|
||||
ObjectGuid AnveenaGUID;
|
||||
ObjectGuid KalecgosKjGUID;
|
||||
|
||||
ObjectGuid IceBarrierGUID;
|
||||
ObjectGuid blueFlightOrbGUID[4];
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
|
||||
@@ -24,24 +24,36 @@
|
||||
|
||||
#define SWPScriptName "instance_sunwell_plateau"
|
||||
|
||||
enum DataTypes
|
||||
enum BossIds
|
||||
{
|
||||
DATA_KALECGOS = 0,
|
||||
DATA_MADRIGOSA = 1,
|
||||
DATA_BRUTALLUS = 2,
|
||||
DATA_FELMYST = 3,
|
||||
DATA_FELMYST_DOORS = 4,
|
||||
DATA_EREDAR_TWINS_INTRO = 5,
|
||||
DATA_EREDAR_TWINS = 6,
|
||||
DATA_MURU = 7,
|
||||
DATA_KILJAEDEN = 8,
|
||||
MAX_ENCOUNTERS = 9,
|
||||
DATA_BRUTALLUS = 1,
|
||||
DATA_FELMYST = 2,
|
||||
DATA_FELMYST_DOORS = 3,
|
||||
DATA_EREDAR_TWINS = 4,
|
||||
DATA_MURU = 5,
|
||||
DATA_KILJAEDEN = 6,
|
||||
MAX_ENCOUNTERS
|
||||
};
|
||||
|
||||
// GameObject GUIDs
|
||||
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1 = 10,
|
||||
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_2 = 11,
|
||||
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3 = 12,
|
||||
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4 = 13
|
||||
enum DataTypes
|
||||
{
|
||||
DATA_SACROLASH = 7,
|
||||
DATA_ALYTHESS = 8,
|
||||
DATA_MADRIGOSA = 9,
|
||||
DATA_SATHROVARR = 10,
|
||||
DATA_KJ_CONTROLLER = 11,
|
||||
DATA_ANVEENA = 12,
|
||||
DATA_KALECGOS_KJ = 13
|
||||
};
|
||||
|
||||
enum DataTypesObjects
|
||||
{
|
||||
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1 = 0,
|
||||
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_2 = 1,
|
||||
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3 = 2,
|
||||
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4 = 3,
|
||||
DATA_ICEBARRIER = 4,
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
@@ -105,4 +117,6 @@ inline AI* GetSunwellPlateauAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, SWPScriptName);
|
||||
}
|
||||
|
||||
#define RegisterSunwellPlateauCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSunwellPlateauAI)
|
||||
|
||||
#endif // SUNWELL_PLATEAU_H
|
||||
|
||||
@@ -15,20 +15,13 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: boss_Akilzon
|
||||
SD%Complete: 75%
|
||||
SDComment: Missing timer for Call Lightning and Sound ID's
|
||||
SQLUpdate:
|
||||
#Temporary fix for Soaring Eagles
|
||||
|
||||
EndScriptData */
|
||||
|
||||
#include "Cell.h"
|
||||
#include "CreatureScript.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "Weather.h"
|
||||
#include "zulaman.h"
|
||||
|
||||
@@ -39,6 +32,7 @@ enum Spells
|
||||
SPELL_CALL_LIGHTNING = 43661, // Missing timer
|
||||
SPELL_GUST_OF_WIND = 43621,
|
||||
SPELL_ELECTRICAL_STORM = 43648,
|
||||
SPELL_ELECTRICAL_STORM_AREA = 44007, // Safe within the eye of the storm
|
||||
SPELL_BERSERK = 45078,
|
||||
SPELL_ELECTRICAL_OVERLOAD = 43658,
|
||||
SPELL_EAGLE_SWOOP = 44732,
|
||||
@@ -56,394 +50,310 @@ enum Says
|
||||
SAY_DEATH = 5
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
ACTION_INCREASE_STORM_COUNT = 1
|
||||
};
|
||||
|
||||
constexpr auto NPC_SOARING_EAGLE = 24858;
|
||||
|
||||
//enum Misc
|
||||
//{
|
||||
// SE_LOC_X_MAX = 400,
|
||||
// SE_LOC_X_MIN = 335,
|
||||
// SE_LOC_Y_MAX = 1435,
|
||||
// SE_LOC_Y_MIN = 1370
|
||||
//};
|
||||
|
||||
enum Events
|
||||
struct boss_akilzon : public BossAI
|
||||
{
|
||||
EVENT_STATIC_DISRUPTION = 1,
|
||||
EVENT_GUST_OF_WIND = 2,
|
||||
EVENT_CALL_LIGHTNING = 3,
|
||||
EVENT_ELECTRICAL_STORM = 4,
|
||||
EVENT_RAIN = 5,
|
||||
EVENT_SUMMON_EAGLES = 6,
|
||||
EVENT_STORM_SEQUENCE = 7,
|
||||
EVENT_ENRAGE = 8
|
||||
};
|
||||
boss_akilzon(Creature* creature) : BossAI(creature, DATA_AKILZON), _stormCount(0), _isRaining(false) { }
|
||||
|
||||
class boss_akilzon : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_akilzon() : CreatureScript("boss_akilzon") { }
|
||||
|
||||
struct boss_akilzonAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_akilzonAI(Creature* creature) : BossAI(creature, DATA_AKILZON)
|
||||
{
|
||||
}
|
||||
_Reset();
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
_targetGUID.Clear();
|
||||
_cloudGUID.Clear();
|
||||
_cycloneGUID.Clear();
|
||||
|
||||
TargetGUID.Clear();
|
||||
CloudGUID.Clear();
|
||||
CycloneGUID.Clear();
|
||||
_stormCount = 0;
|
||||
_isRaining = false;
|
||||
|
||||
for (uint8 i = 0; i < 8; ++i)
|
||||
BirdGUIDs[i].Clear();
|
||||
SetWeather(WEATHER_STATE_FINE, 0.0f);
|
||||
|
||||
StormCount = 0;
|
||||
isRaining = false;
|
||||
|
||||
SetWeather(WEATHER_STATE_FINE, 0.0f);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_STATIC_DISRUPTION, urand(10000, 20000)); // 10 to 20 seconds (bosskillers)
|
||||
events.ScheduleEvent(EVENT_GUST_OF_WIND, urand(20000, 30000)); // 20 to 30 seconds(bosskillers)
|
||||
events.ScheduleEvent(EVENT_CALL_LIGHTNING, urand(10000, 20000)); // totaly random timer. can't find any info on this
|
||||
events.ScheduleEvent(EVENT_ELECTRICAL_STORM, 60000); // 60 seconds(bosskillers)
|
||||
events.ScheduleEvent(EVENT_RAIN, urand(47000, 52000));
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 10 * MINUTE * IN_MILLISECONDS); // 10 minutes till enrage(bosskillers)
|
||||
|
||||
Talk(SAY_AGGRO);
|
||||
//DoZoneInCombat();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
{
|
||||
if (who->IsPlayer())
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
void SetWeather(uint32 weather, float grade)
|
||||
{
|
||||
Map* map = me->GetMap();
|
||||
if (!map->IsDungeon())
|
||||
return;
|
||||
|
||||
WorldPacket data(SMSG_WEATHER, (4 + 4 + 4));
|
||||
data << uint32(weather) << float(grade) << uint8(0);
|
||||
|
||||
map->SendToPlayers(&data);
|
||||
}
|
||||
|
||||
void HandleStormSequence(Unit* Cloud) // 1: begin, 2-9: tick, 10: end
|
||||
{
|
||||
if (StormCount < 10 && StormCount > 1)
|
||||
{
|
||||
// deal damage
|
||||
int32 bp0 = 800;
|
||||
for (uint8 i = 2; i < StormCount; ++i)
|
||||
bp0 *= 2;
|
||||
|
||||
std::list<Unit*> tempUnitMap;
|
||||
|
||||
Acore::AnyAoETargetUnitInObjectRangeCheck u_check(me, me, SIZE_OF_GRIDS);
|
||||
Acore::UnitListSearcher<Acore::AnyAoETargetUnitInObjectRangeCheck> searcher(me, tempUnitMap, u_check);
|
||||
Cell::VisitAllObjects(me, searcher, SIZE_OF_GRIDS);
|
||||
|
||||
// deal damage
|
||||
for (std::list<Unit*>::const_iterator i = tempUnitMap.begin(); i != tempUnitMap.end(); ++i)
|
||||
{
|
||||
if (Unit* target = (*i))
|
||||
{
|
||||
if (Cloud && !Cloud->IsWithinDist(target, 6, false))
|
||||
Cloud->CastCustomSpell(target, SPELL_ZAP, &bp0, nullptr, nullptr, true, 0, 0, me->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
// visual
|
||||
float x, y, z;
|
||||
z = me->GetPositionZ();
|
||||
for (uint8 i = 0; i < 5 + rand() % 5; ++i)
|
||||
{
|
||||
x = 343.0f + rand() % 60;
|
||||
y = 1380.0f + rand() % 60;
|
||||
if (Unit* trigger = me->SummonTrigger(x, y, z, 0, 2000))
|
||||
{
|
||||
trigger->SetFaction(FACTION_FRIENDLY);
|
||||
trigger->SetMaxHealth(100000);
|
||||
trigger->SetHealth(100000);
|
||||
trigger->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
if (Cloud)
|
||||
Cloud->CastCustomSpell(trigger, /*43661*/SPELL_ZAP, &bp0, nullptr, nullptr, true, 0, 0, Cloud->GetGUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++StormCount;
|
||||
|
||||
if (StormCount > 10)
|
||||
{
|
||||
StormCount = 0; // finish
|
||||
events.ScheduleEvent(EVENT_SUMMON_EAGLES, 5000);
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
CloudGUID.Clear();
|
||||
if (Cloud)
|
||||
Unit::DealDamage(Cloud, Cloud, Cloud->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
|
||||
SetWeather(WEATHER_STATE_FINE, 0.0f);
|
||||
isRaining = false;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_STORM_SEQUENCE, 1000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_STATIC_DISRUPTION:
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
if (target)
|
||||
{
|
||||
TargetGUID = target->GetGUID();
|
||||
DoCast(target, SPELL_STATIC_DISRUPTION, false);
|
||||
me->SetInFront(me->GetVictim());
|
||||
}
|
||||
/*if (float dist = me->IsWithinDist3d(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 5.0f) dist = 5.0f;
|
||||
SDisruptAOEVisual_Timer = 1000 + std::floor(dist / 30 * 1000.0f);*/
|
||||
events.ScheduleEvent(EVENT_STATIC_DISRUPTION, urand(10000, 18000));
|
||||
break;
|
||||
}
|
||||
case EVENT_GUST_OF_WIND:
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
if (target)
|
||||
DoCast(target, SPELL_GUST_OF_WIND);
|
||||
events.ScheduleEvent(EVENT_GUST_OF_WIND, urand(20000, 30000));
|
||||
break;
|
||||
}
|
||||
case EVENT_CALL_LIGHTNING:
|
||||
DoCastVictim(SPELL_CALL_LIGHTNING);
|
||||
events.ScheduleEvent(EVENT_CALL_LIGHTNING, urand(12000, 17000)); // totaly random timer. can't find any info on this
|
||||
break;
|
||||
case EVENT_ELECTRICAL_STORM:
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50, true);
|
||||
if (!target)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
target->CastSpell(target, 44007, true); // cloud visual
|
||||
DoCast(target, SPELL_ELECTRICAL_STORM, false); // storm cyclon + visual
|
||||
float x, y, z;
|
||||
target->GetPosition(x, y, z);
|
||||
/// @todo: fix it in correct way, that causes player to can fly until logout
|
||||
/*
|
||||
if (target)
|
||||
{
|
||||
target->SetDisableGravity(true);
|
||||
target->MonsterMoveWithSpeed(x, y, me->GetPositionZ()+15, 0);
|
||||
}
|
||||
*/
|
||||
|
||||
Unit* Cloud = me->SummonTrigger(x, y, me->GetPositionZ() + 16, 0, 15000);
|
||||
if (Cloud)
|
||||
{
|
||||
CloudGUID = Cloud->GetGUID();
|
||||
Cloud->SetDisableGravity(true);
|
||||
Cloud->StopMoving();
|
||||
Cloud->SetObjectScale(1.0f);
|
||||
Cloud->SetFaction(FACTION_FRIENDLY);
|
||||
Cloud->SetMaxHealth(9999999);
|
||||
Cloud->SetHealth(9999999);
|
||||
Cloud->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
StormCount = 1;
|
||||
events.ScheduleEvent(EVENT_ELECTRICAL_STORM, 60000); // 60 seconds(bosskillers)
|
||||
events.ScheduleEvent(EVENT_RAIN, urand(47000, 52000));
|
||||
break;
|
||||
}
|
||||
case EVENT_RAIN:
|
||||
if (!isRaining)
|
||||
{
|
||||
SetWeather(WEATHER_STATE_HEAVY_RAIN, 0.9999f);
|
||||
isRaining = true;
|
||||
}
|
||||
else
|
||||
events.ScheduleEvent(EVENT_RAIN, 1000);
|
||||
break;
|
||||
case EVENT_STORM_SEQUENCE:
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*me, CloudGUID);
|
||||
if (!target || !target->IsAlive())
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
else if (Unit* Cyclone = ObjectAccessor::GetUnit(*me, CycloneGUID))
|
||||
Cyclone->CastSpell(target, SPELL_SAND_STORM, true); // keep casting or...
|
||||
HandleStormSequence(target);
|
||||
break;
|
||||
}
|
||||
case EVENT_SUMMON_EAGLES:
|
||||
Talk(SAY_SUMMON);
|
||||
|
||||
float x, y, z;
|
||||
me->GetPosition(x, y, z);
|
||||
|
||||
for (uint8 i = 0; i < 8; ++i)
|
||||
{
|
||||
Unit* bird = ObjectAccessor::GetUnit(*me, BirdGUIDs[i]);
|
||||
if (!bird) //they despawned on die
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
x = target->GetPositionX() + irand(-10, 10);
|
||||
y = target->GetPositionY() + irand(-10, 10);
|
||||
z = target->GetPositionZ() + urand(16, 20);
|
||||
if (z > 95)
|
||||
z = 95.0f - urand(0, 5);
|
||||
}
|
||||
Creature* creature = me->SummonCreature(NPC_SOARING_EAGLE, x, y, z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
|
||||
if (creature)
|
||||
{
|
||||
creature->AddThreat(me->GetVictim(), 1.0f);
|
||||
creature->AI()->AttackStart(me->GetVictim());
|
||||
BirdGUIDs[i] = creature->GetGUID();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
Talk(SAY_ENRAGE);
|
||||
DoCast(me, SPELL_BERSERK, true);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 600000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid BirdGUIDs[8];
|
||||
ObjectGuid TargetGUID;
|
||||
ObjectGuid CycloneGUID;
|
||||
ObjectGuid CloudGUID;
|
||||
uint8 StormCount;
|
||||
bool isRaining;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetZulAmanAI<boss_akilzonAI>(creature);
|
||||
me->m_Events.KillAllEvents(false);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_akilzon_eagle : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_akilzon_eagle() : CreatureScript("npc_akilzon_eagle") { }
|
||||
|
||||
struct npc_akilzon_eagleAI : public ScriptedAI
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
npc_akilzon_eagleAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
_JustEngagedWith();
|
||||
|
||||
uint32 EagleSwoop_Timer;
|
||||
bool arrived;
|
||||
ObjectGuid TargetGUID;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
EagleSwoop_Timer = urand(5000, 10000);
|
||||
arrived = true;
|
||||
TargetGUID.Clear();
|
||||
me->SetDisableGravity(true);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
DoZoneInCombat();
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* /*who*/) override { }
|
||||
|
||||
void MovementInform(uint32, uint32) override
|
||||
{
|
||||
arrived = true;
|
||||
if (TargetGUID)
|
||||
ScheduleTimedEvent(10s, 20s, [&] {
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
if (target)
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, TargetGUID))
|
||||
DoCast(target, SPELL_EAGLE_SWOOP, true);
|
||||
TargetGUID.Clear();
|
||||
me->SetSpeed(MOVE_RUN, 1.2f);
|
||||
EagleSwoop_Timer = urand(5000, 10000);
|
||||
_targetGUID = target->GetGUID();
|
||||
DoCast(target, SPELL_STATIC_DISRUPTION, false);
|
||||
me->SetInFront(me->GetVictim());
|
||||
}
|
||||
}, 10s, 18s);
|
||||
|
||||
ScheduleTimedEvent(20s, 30s, [&] {
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
|
||||
if (!target)
|
||||
target = me->GetVictim();
|
||||
if (target)
|
||||
DoCast(target, SPELL_GUST_OF_WIND);
|
||||
}, 20s, 30s);
|
||||
|
||||
ScheduleTimedEvent(10s, 20s, [&] {
|
||||
DoCastVictim(SPELL_CALL_LIGHTNING);
|
||||
}, 12s, 17s);
|
||||
|
||||
ScheduleTimedEvent(1min, [&] {
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50, true);
|
||||
if (!target)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
target->CastSpell(target, SPELL_ELECTRICAL_STORM_AREA, true); // cloud visual
|
||||
DoCast(target, SPELL_ELECTRICAL_STORM); // storm cyclon + visual
|
||||
float x, y, z;
|
||||
target->GetPosition(x, y, z);
|
||||
|
||||
Unit* Cloud = me->SummonTrigger(x, y, me->GetPositionZ() + 16, 0, 15000);
|
||||
if (Cloud)
|
||||
{
|
||||
target->GetMotionMaster()->MoveJump(Cloud->GetPosition(), 1.0f, 1.0f);
|
||||
|
||||
_cloudGUID = Cloud->GetGUID();
|
||||
Cloud->SetDisableGravity(true);
|
||||
Cloud->StopMoving();
|
||||
Cloud->SetObjectScale(1.0f);
|
||||
Cloud->SetFaction(FACTION_FRIENDLY);
|
||||
Cloud->SetMaxHealth(9999999);
|
||||
Cloud->SetHealth(9999999);
|
||||
Cloud->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
HandleStormSequence();
|
||||
}, 3s);
|
||||
}
|
||||
|
||||
_stormCount = 1;
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
if (!_isRaining)
|
||||
{
|
||||
SetWeather(WEATHER_STATE_HEAVY_RAIN, 0.9999f);
|
||||
_isRaining = true;
|
||||
}
|
||||
}, Seconds(urand(47, 52)));
|
||||
}, 1min);
|
||||
|
||||
ScheduleTimedEvent(47s, 52s, [&] {
|
||||
if (!_isRaining)
|
||||
{
|
||||
SetWeather(WEATHER_STATE_HEAVY_RAIN, 0.9999f);
|
||||
_isRaining = true;
|
||||
}
|
||||
}, 47s, 52s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
Talk(SAY_ENRAGE);
|
||||
DoCastSelf(SPELL_BERSERK, true);
|
||||
}, 10min);
|
||||
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
_JustDied();
|
||||
me->m_Events.KillAllEvents(false);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
{
|
||||
if (who->IsPlayer())
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
void SetWeather(uint32 weather, float grade)
|
||||
{
|
||||
me->GetMap()->SetZoneWeather(me->GetZoneId(), WeatherState(weather), grade);
|
||||
}
|
||||
|
||||
void HandleStormSequence() // 1: begin, 2-9: tick, 10: end
|
||||
{
|
||||
Creature* Cloud = ObjectAccessor::GetCreature(*me, _cloudGUID);
|
||||
if (!Cloud)
|
||||
return;
|
||||
|
||||
if (_stormCount > 10)
|
||||
{
|
||||
_stormCount = 0; // finish
|
||||
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
SummonEagles();
|
||||
}, 5s);
|
||||
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
_cloudGUID.Clear();
|
||||
if (Cloud)
|
||||
Cloud->KillSelf();
|
||||
SetWeather(WEATHER_STATE_FINE, 0.0f);
|
||||
_isRaining = false;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (EagleSwoop_Timer <= diff)
|
||||
EagleSwoop_Timer = 0;
|
||||
else
|
||||
EagleSwoop_Timer -= diff;
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
Unit* target = ObjectAccessor::GetUnit(*me, _cloudGUID);
|
||||
if (!target || !target->IsAlive())
|
||||
return;
|
||||
else if (Unit* Cyclone = ObjectAccessor::GetUnit(*me, _cycloneGUID))
|
||||
Cyclone->CastSpell(target, SPELL_SAND_STORM, true); // keep casting or...
|
||||
HandleStormSequence();
|
||||
}, 1s);
|
||||
}
|
||||
|
||||
if (arrived)
|
||||
void DoAction(int32 actionId) override
|
||||
{
|
||||
if (actionId == ACTION_INCREASE_STORM_COUNT)
|
||||
++_stormCount;
|
||||
}
|
||||
|
||||
void SummonEagles()
|
||||
{
|
||||
Talk(SAY_SUMMON);
|
||||
|
||||
float x, y, z;
|
||||
me->GetPosition(x, y, z);
|
||||
|
||||
for (uint8 i = 0; i < 8; ++i)
|
||||
{
|
||||
Unit* bird = ObjectAccessor::GetUnit(*me, _birdGUIDs[i]);
|
||||
if (!bird) //they despawned on die
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
float x, y, z;
|
||||
if (EagleSwoop_Timer)
|
||||
{
|
||||
x = target->GetPositionX() + irand(-10, 10);
|
||||
y = target->GetPositionY() + irand(-10, 10);
|
||||
z = target->GetPositionZ() + urand(10, 15);
|
||||
if (z > 95)
|
||||
z = 95.0f - urand(0, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
target->GetContactPoint(me, x, y, z);
|
||||
z += 2;
|
||||
me->SetSpeed(MOVE_RUN, 5.0f);
|
||||
TargetGUID = target->GetGUID();
|
||||
}
|
||||
me->GetMotionMaster()->MovePoint(0, x, y, z);
|
||||
arrived = false;
|
||||
x = target->GetPositionX() + irand(-10, 10);
|
||||
y = target->GetPositionY() + irand(-10, 10);
|
||||
z = target->GetPositionZ() + urand(16, 20);
|
||||
if (z > 95)
|
||||
z = 95.0f - urand(0, 5);
|
||||
}
|
||||
;
|
||||
if (Creature* creature = me->SummonCreature(NPC_SOARING_EAGLE, x, y, z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0))
|
||||
{
|
||||
creature->AddThreat(me->GetVictim(), 1.0f);
|
||||
creature->AI()->AttackStart(me->GetVictim());
|
||||
_birdGUIDs[i] = creature->GetGUID();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
private:
|
||||
ObjectGuid _birdGUIDs[8];
|
||||
ObjectGuid _targetGUID;
|
||||
ObjectGuid _cycloneGUID;
|
||||
ObjectGuid _cloudGUID;
|
||||
uint8 _stormCount;
|
||||
bool _isRaining;
|
||||
};
|
||||
|
||||
struct npc_akilzon_eagle : public ScriptedAI
|
||||
{
|
||||
npc_akilzon_eagle(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 EagleSwoop_Timer;
|
||||
bool arrived;
|
||||
ObjectGuid TargetGUID;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
return GetZulAmanAI<npc_akilzon_eagleAI>(creature);
|
||||
EagleSwoop_Timer = urand(5000, 10000);
|
||||
arrived = true;
|
||||
TargetGUID.Clear();
|
||||
me->SetDisableGravity(true);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
DoZoneInCombat();
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* /*who*/) override { }
|
||||
|
||||
void MovementInform(uint32, uint32) override
|
||||
{
|
||||
arrived = true;
|
||||
if (TargetGUID)
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, TargetGUID))
|
||||
DoCast(target, SPELL_EAGLE_SWOOP, true);
|
||||
TargetGUID.Clear();
|
||||
me->SetSpeed(MOVE_RUN, 1.2f);
|
||||
EagleSwoop_Timer = urand(5000, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (EagleSwoop_Timer <= diff)
|
||||
EagleSwoop_Timer = 0;
|
||||
else
|
||||
EagleSwoop_Timer -= diff;
|
||||
|
||||
if (arrived)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
float x, y, z;
|
||||
if (EagleSwoop_Timer)
|
||||
{
|
||||
x = target->GetPositionX() + irand(-10, 10);
|
||||
y = target->GetPositionY() + irand(-10, 10);
|
||||
z = target->GetPositionZ() + urand(10, 15);
|
||||
if (z > 95)
|
||||
z = 95.0f - urand(0, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
target->GetContactPoint(me, x, y, z);
|
||||
z += 2;
|
||||
me->SetSpeed(MOVE_RUN, 5.0f);
|
||||
TargetGUID = target->GetGUID();
|
||||
}
|
||||
me->GetMotionMaster()->MovePoint(0, x, y, z);
|
||||
arrived = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 43648 - Electrical Storm
|
||||
class spell_electrial_storm : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_electrial_storm);
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster() && GetCaster()->IsCreature();
|
||||
}
|
||||
|
||||
void OnPeriodic(AuraEffect const* /*aurEff*/)
|
||||
{
|
||||
if (GetCaster())
|
||||
GetCaster()->ToCreature()->AI()->DoAction(ACTION_INCREASE_STORM_COUNT);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_electrial_storm::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_akilzon()
|
||||
{
|
||||
new boss_akilzon();
|
||||
new npc_akilzon_eagle();
|
||||
RegisterZulAmanCreatureAI(boss_akilzon);
|
||||
RegisterZulAmanCreatureAI(npc_akilzon_eagle);
|
||||
RegisterSpellScript(spell_electrial_storm);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,11 @@ enum Groups
|
||||
GROUP_MERGE = 2
|
||||
};
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_MERGE = 0
|
||||
};
|
||||
|
||||
struct boss_halazzi : public BossAI
|
||||
{
|
||||
boss_halazzi(Creature* creature) : BossAI(creature, DATA_HALAZZI)
|
||||
@@ -118,33 +123,19 @@ struct boss_halazzi : public BossAI
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && _phase != PHASE_ENRAGE)
|
||||
{
|
||||
damage = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_phase == PHASE_LYNX || _phase == PHASE_ENRAGE)
|
||||
{
|
||||
_healthCheckPercentage = 25 * (3 - _transformCount);
|
||||
if (!HealthAbovePct(_healthCheckPercentage))
|
||||
{
|
||||
EnterPhase(PHASE_SPLIT);
|
||||
}
|
||||
}
|
||||
else if (_phase == PHASE_HUMAN)
|
||||
{
|
||||
if (Creature* lynx = instance->GetCreature(DATA_SPIRIT_LYNX))
|
||||
{
|
||||
if (!HealthAbovePct(20) || !lynx->HealthAbovePct(20))
|
||||
{
|
||||
EnterPhase(PHASE_MERGE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//should not really happen
|
||||
EnterEvadeMode();
|
||||
}
|
||||
if (!HealthAbovePct(20))
|
||||
EnterPhase(PHASE_MERGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,17 +143,13 @@ struct boss_halazzi : public BossAI
|
||||
void SpellHit(Unit*, SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id == SPELL_TRANSFORM_SPLIT2)
|
||||
{
|
||||
EnterPhase(PHASE_HUMAN);
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (_phase != PHASE_MERGE)
|
||||
{
|
||||
BossAI::AttackStart(who);
|
||||
}
|
||||
}
|
||||
|
||||
void EnterPhase(PhaseHalazzi nextPhase)
|
||||
@@ -175,7 +162,7 @@ struct boss_halazzi : public BossAI
|
||||
{
|
||||
DoCastSelf(SPELL_TRANSFORM_MERGE, true);
|
||||
me->RemoveAurasDueToSpell(SPELL_TRANSFORM_SPLIT2);
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
me->ResumeChasingVictim();
|
||||
}
|
||||
summons.DespawnAll();
|
||||
me->SetMaxHealth(_lynxFormHealth);
|
||||
@@ -207,13 +194,9 @@ struct boss_halazzi : public BossAI
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
if (target->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
DoCast(target, SPELL_EARTHSHOCK);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoCast(target, SPELL_FLAMESHOCK);
|
||||
}
|
||||
}
|
||||
context.Repeat(10s, 15s);
|
||||
}).Schedule(12s, GROUP_HUMAN, [this](TaskContext context)
|
||||
@@ -236,19 +219,13 @@ struct boss_halazzi : public BossAI
|
||||
scheduler.Schedule(2s, GROUP_MERGE, [this](TaskContext context)
|
||||
{
|
||||
if (Creature* lynx = instance->GetCreature(DATA_SPIRIT_LYNX))
|
||||
{
|
||||
if (me->IsWithinDistInMap(lynx, 6.0f))
|
||||
{
|
||||
if (_transformCount < 3)
|
||||
{
|
||||
EnterPhase(PHASE_LYNX);
|
||||
}
|
||||
else
|
||||
{
|
||||
EnterPhase(PHASE_ENRAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
context.Repeat(2s);
|
||||
});
|
||||
}
|
||||
@@ -263,9 +240,13 @@ struct boss_halazzi : public BossAI
|
||||
{
|
||||
BossAI::KilledUnit(victim);
|
||||
if (victim->IsPlayer())
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 actionId) override
|
||||
{
|
||||
if (actionId == ACTION_MERGE)
|
||||
EnterPhase(PHASE_MERGE);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
@@ -281,60 +262,8 @@ private:
|
||||
uint32 _healthCheckPercentage;
|
||||
PhaseHalazzi _phase;
|
||||
};
|
||||
// Spirits Lynx AI
|
||||
struct npc_halazzi_lynx : public ScriptedAI
|
||||
{
|
||||
npc_halazzi_lynx(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
|
||||
{
|
||||
if (damage >= me->GetHealth())
|
||||
{
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
{
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
ScriptedAI::JustEngagedWith(who);
|
||||
|
||||
ScheduleTimedEvent(30s, 50s, [&]
|
||||
{
|
||||
DoCastSelf(SPELL_LYNX_FRENZY);
|
||||
}, 30s, 50s);
|
||||
ScheduleTimedEvent(4s, [&]{
|
||||
DoCastVictim(SPELL_SHRED_ARMOR);
|
||||
}, 4s);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.Update(diff);
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_halazzi()
|
||||
{
|
||||
RegisterZulAmanCreatureAI(boss_halazzi);
|
||||
RegisterZulAmanCreatureAI(npc_halazzi_lynx);
|
||||
}
|
||||
|
||||
@@ -22,16 +22,10 @@
|
||||
#include "Player.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "zulaman.h"
|
||||
/* ScriptData
|
||||
SDName: Boss_Hex_Lord_Malacrass
|
||||
SD%Complete:
|
||||
SDComment:
|
||||
SDCategory: Zul'Aman
|
||||
EndScriptData */
|
||||
|
||||
enum Says
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_AGGRO,
|
||||
SAY_KILL_ONE,
|
||||
SAY_KILL_TWO,
|
||||
SAY_DRAIN_POWER,
|
||||
@@ -117,23 +111,23 @@ enum Spells
|
||||
// Death Knight
|
||||
SPELL_DK_PLAGUE_STRIKE = 57599,
|
||||
SPELL_DK_DEATH_AND_DECAY = 43265,
|
||||
SPELL_DK_BLOOD_WORMS = 97630,
|
||||
SPELL_DK_BLOOD_WORMS = 97630
|
||||
};
|
||||
|
||||
const Position addPosition[4] =
|
||||
const Position AddPosition[4] =
|
||||
{
|
||||
{112.8827f, 921.2795f, 33.8883f, 1.5696f},
|
||||
{107.8827f, 921.2795f, 33.8883f, 1.5696f},
|
||||
{122.8827f, 921.2795f, 33.8883f, 1.5696f},
|
||||
{127.8827f, 921.2795f, 33.8883f, 1.5696f}
|
||||
{ 128.48448f, 923.04285f, 33.97255f, 1.588249564170837402f },
|
||||
{ 122.60526f, 923.24536f, 33.97256f, 1.570796370506286621f },
|
||||
{ 111.69282f, 923.15314f, 33.972576f, 1.570796370506286621f },
|
||||
{ 105.40299f, 923.3421f, 33.972588f, 1.553343057632446289f }
|
||||
};
|
||||
|
||||
static uint32 addEntrySets[4][2] =
|
||||
static uint32 AddEntrySets[4][2] =
|
||||
{
|
||||
{NPC_THURG, NPC_ALYSON_ANTILLE },
|
||||
{NPC_LORD_RADAAN, NPC_SLITHER },
|
||||
{NPC_GAZAKROTH, NPC_FENSTALKER },
|
||||
{NPC_DARKHEART, NPC_KORAGG }
|
||||
{ NPC_THURG, NPC_ALYSON_ANTILLE },
|
||||
{ NPC_LORD_RADAAN, NPC_SLITHER },
|
||||
{ NPC_GAZAKROTH, NPC_FENSTALKER },
|
||||
{ NPC_DARKHEART, NPC_KORAGG }
|
||||
};
|
||||
|
||||
enum Misc
|
||||
@@ -145,11 +139,11 @@ enum Misc
|
||||
|
||||
enum AbilityTarget
|
||||
{
|
||||
ABILITY_TARGET_SELF = 0,
|
||||
ABILITY_TARGET_VICTIM = 1,
|
||||
ABILITY_TARGET_ENEMY = 2,
|
||||
ABILITY_TARGET_HEAL = 3,
|
||||
ABILITY_TARGET_BUFF = 4,
|
||||
ABILITY_TARGET_SELF = 0,
|
||||
ABILITY_TARGET_VICTIM = 1,
|
||||
ABILITY_TARGET_ENEMY = 2,
|
||||
ABILITY_TARGET_HEAL = 3,
|
||||
ABILITY_TARGET_BUFF = 4,
|
||||
ABILITY_TARGET_SPECIAL = 5
|
||||
};
|
||||
|
||||
@@ -163,66 +157,66 @@ struct PlayerAbilityStruct
|
||||
static PlayerAbilityStruct PlayerAbility[12][3] =
|
||||
{
|
||||
// 1 warrior
|
||||
{ {SPELL_WR_SPELL_REFLECT, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_WR_WHIRLWIND, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_WR_MORTAL_STRIKE, ABILITY_TARGET_VICTIM, 6000ms}
|
||||
{ { SPELL_WR_SPELL_REFLECT, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_WR_WHIRLWIND, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_WR_MORTAL_STRIKE, ABILITY_TARGET_VICTIM, 6000ms }
|
||||
},
|
||||
// 2 paladin
|
||||
{ {SPELL_PA_CONSECRATION, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_PA_HOLY_LIGHT, ABILITY_TARGET_HEAL, 10000ms},
|
||||
{SPELL_PA_AVENGING_WRATH, ABILITY_TARGET_SELF, 10000ms}
|
||||
{ { SPELL_PA_CONSECRATION, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_PA_HOLY_LIGHT, ABILITY_TARGET_HEAL, 10000ms },
|
||||
{ SPELL_PA_AVENGING_WRATH, ABILITY_TARGET_SELF, 10000ms }
|
||||
},
|
||||
// 3 hunter
|
||||
{ {SPELL_HU_EXPLOSIVE_TRAP, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_HU_FREEZING_TRAP, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_HU_SNAKE_TRAP, ABILITY_TARGET_SELF, 10000ms}
|
||||
{ { SPELL_HU_EXPLOSIVE_TRAP, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_HU_FREEZING_TRAP, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_HU_SNAKE_TRAP, ABILITY_TARGET_SELF, 10000ms }
|
||||
},
|
||||
// 4 rogue
|
||||
{ {SPELL_RO_WOUND_POISON, ABILITY_TARGET_VICTIM, 3000ms},
|
||||
{SPELL_RO_SLICE_DICE, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_RO_BLIND, ABILITY_TARGET_ENEMY, 10000ms}
|
||||
{ { SPELL_RO_WOUND_POISON, ABILITY_TARGET_VICTIM, 3000ms },
|
||||
{ SPELL_RO_SLICE_DICE, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_RO_BLIND, ABILITY_TARGET_ENEMY, 10000ms }
|
||||
},
|
||||
// 5 priest
|
||||
{ {SPELL_PR_PAIN_SUPP, ABILITY_TARGET_HEAL, 10000ms},
|
||||
{SPELL_PR_HEAL, ABILITY_TARGET_HEAL, 10000ms},
|
||||
{SPELL_PR_PSYCHIC_SCREAM, ABILITY_TARGET_SELF, 10000ms}
|
||||
{ { SPELL_PR_PAIN_SUPP, ABILITY_TARGET_HEAL, 10000ms },
|
||||
{ SPELL_PR_HEAL, ABILITY_TARGET_HEAL, 10000ms },
|
||||
{ SPELL_PR_PSYCHIC_SCREAM, ABILITY_TARGET_SELF, 10000ms }
|
||||
},
|
||||
// 6 death knight
|
||||
{
|
||||
{SPELL_DK_PLAGUE_STRIKE, ABILITY_TARGET_ENEMY, 2000ms},
|
||||
{SPELL_DK_DEATH_AND_DECAY, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_DK_BLOOD_WORMS, ABILITY_TARGET_ENEMY, 5000ms}
|
||||
{ SPELL_DK_PLAGUE_STRIKE, ABILITY_TARGET_ENEMY, 2000ms },
|
||||
{ SPELL_DK_DEATH_AND_DECAY, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_DK_BLOOD_WORMS, ABILITY_TARGET_ENEMY, 5000ms }
|
||||
},
|
||||
// 7 shaman
|
||||
{ {SPELL_SH_FIRE_NOVA, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_SH_HEALING_WAVE, ABILITY_TARGET_HEAL, 10000ms},
|
||||
{SPELL_SH_CHAIN_LIGHT, ABILITY_TARGET_ENEMY, 8000ms}
|
||||
{ { SPELL_SH_FIRE_NOVA, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_SH_HEALING_WAVE, ABILITY_TARGET_HEAL, 10000ms },
|
||||
{ SPELL_SH_CHAIN_LIGHT, ABILITY_TARGET_ENEMY, 8000ms }
|
||||
},
|
||||
// 8 mage
|
||||
{ {SPELL_MG_FIREBALL, ABILITY_TARGET_ENEMY, 5000ms},
|
||||
{SPELL_MG_FROSTBOLT, ABILITY_TARGET_ENEMY, 5000ms},
|
||||
{SPELL_MG_ICE_LANCE, ABILITY_TARGET_SPECIAL, 2000ms}
|
||||
{ { SPELL_MG_FIREBALL, ABILITY_TARGET_ENEMY, 5000ms },
|
||||
{ SPELL_MG_FROSTBOLT, ABILITY_TARGET_ENEMY, 5000ms },
|
||||
{ SPELL_MG_ICE_LANCE, ABILITY_TARGET_SPECIAL, 2000ms }
|
||||
},
|
||||
// 9 warlock
|
||||
{ {SPELL_WL_CURSE_OF_DOOM, ABILITY_TARGET_ENEMY, 10000ms},
|
||||
{SPELL_WL_RAIN_OF_FIRE, ABILITY_TARGET_ENEMY, 10000ms},
|
||||
{SPELL_WL_UNSTABLE_AFFL, ABILITY_TARGET_ENEMY, 10000ms}
|
||||
{ { SPELL_WL_CURSE_OF_DOOM, ABILITY_TARGET_ENEMY, 10000ms },
|
||||
{ SPELL_WL_RAIN_OF_FIRE, ABILITY_TARGET_ENEMY, 10000ms },
|
||||
{ SPELL_WL_UNSTABLE_AFFL, ABILITY_TARGET_ENEMY, 10000ms }
|
||||
},
|
||||
// 10 UNK class (should never be set)
|
||||
{
|
||||
{0, ABILITY_TARGET_SELF, 0ms},
|
||||
{0, ABILITY_TARGET_SELF, 0ms},
|
||||
{0, ABILITY_TARGET_SELF, 0ms}
|
||||
{ 0, ABILITY_TARGET_SELF, 0ms},
|
||||
{ 0, ABILITY_TARGET_SELF, 0ms},
|
||||
{ 0, ABILITY_TARGET_SELF, 0ms}
|
||||
},
|
||||
// 11 druid
|
||||
{ {SPELL_DR_LIFEBLOOM, ABILITY_TARGET_HEAL, 10000ms},
|
||||
{SPELL_DR_THORNS, ABILITY_TARGET_SELF, 10000ms},
|
||||
{SPELL_DR_MOONFIRE, ABILITY_TARGET_ENEMY, 8000ms}
|
||||
{ { SPELL_DR_LIFEBLOOM, ABILITY_TARGET_HEAL, 10000ms },
|
||||
{ SPELL_DR_THORNS, ABILITY_TARGET_SELF, 10000ms },
|
||||
{ SPELL_DR_MOONFIRE, ABILITY_TARGET_ENEMY, 8000ms }
|
||||
},
|
||||
// MISC shadow priest
|
||||
{ {SPELL_PR_MIND_CONTROL, ABILITY_TARGET_ENEMY, 15000ms},
|
||||
{SPELL_PR_MIND_BLAST, ABILITY_TARGET_ENEMY, 5000ms},
|
||||
{SPELL_PR_SW_DEATH, ABILITY_TARGET_ENEMY, 10000ms}
|
||||
{ { SPELL_PR_MIND_CONTROL, ABILITY_TARGET_ENEMY, 15000ms },
|
||||
{ SPELL_PR_MIND_BLAST, ABILITY_TARGET_ENEMY, 5000ms },
|
||||
{ SPELL_PR_SW_DEATH, ABILITY_TARGET_ENEMY, 10000ms }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -243,7 +237,7 @@ struct boss_hexlord_malacrass : public BossAI
|
||||
for (uint8 i = 0; i < MAX_ADD_COUNT; ++i)
|
||||
{
|
||||
uint8 flip = urand(0, 1);
|
||||
me->SummonCreature(addEntrySets[i][flip], addPosition[i], TEMPSUMMON_DEAD_DESPAWN, 0);
|
||||
me->SummonCreature(AddEntrySets[i][flip], AddPosition[i], TEMPSUMMON_DEAD_DESPAWN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,21 +268,14 @@ struct boss_hexlord_malacrass : public BossAI
|
||||
siphonTrigger->AI()->DoCast(target, SPELL_SIPHON_SOUL, true);
|
||||
siphonTrigger->GetMotionMaster()->MoveChase(me);
|
||||
if (Player* player = target->ToPlayer())
|
||||
{
|
||||
if (player->HasAura(AURA_SHADOW_FORM))
|
||||
_currentClass = ADDITIONAL_CLASS_SPRIEST;
|
||||
else
|
||||
_currentClass = player->getClass() - 1;
|
||||
}
|
||||
_currentClass = player->HasAura(AURA_SHADOW_FORM) ? ADDITIONAL_CLASS_SPRIEST : player->getClass() - 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 40s);
|
||||
ScheduleTimedEvent(_classAbilityTimer, [&]{
|
||||
if (_currentClass)
|
||||
{
|
||||
UseAbility();
|
||||
}
|
||||
}, _classAbilityTimer);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,6 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Janalai
|
||||
SD%Complete: 100
|
||||
SDComment:
|
||||
SDCategory: Zul'Aman
|
||||
EndScriptData */
|
||||
|
||||
#include "CellImpl.h"
|
||||
#include "CreatureScript.h"
|
||||
#include "GridNotifiers.h"
|
||||
@@ -125,7 +118,13 @@ enum Misc
|
||||
|
||||
struct boss_janalai : public BossAI
|
||||
{
|
||||
boss_janalai(Creature* creature) : BossAI(creature, DATA_JANALAI) { }
|
||||
boss_janalai(Creature* creature) : BossAI(creature, DATA_JANALAI)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
@@ -134,18 +133,17 @@ struct boss_janalai : public BossAI
|
||||
_isBombing = false;
|
||||
_isFlameBreathing = false;
|
||||
|
||||
ScheduleHealthCheckEvent(25, [&]{
|
||||
DoCastSelf(SPELL_ENRAGE, true);
|
||||
});
|
||||
|
||||
ScheduleHealthCheckEvent(35, [&]{
|
||||
Talk(SAY_ALL_EGGS);
|
||||
me->AttackStop();
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->SetPosition(janalainPos);
|
||||
me->StopMovingOnCurrentPos();
|
||||
DoCastSelf(SPELL_HATCH_ALL);
|
||||
HatchAllEggs(HATCH_ALL);
|
||||
DoCastAOE(SPELL_HATCH_ALL);
|
||||
});
|
||||
|
||||
ScheduleHealthCheckEvent(25, [&] {
|
||||
DoCastSelf(SPELL_ENRAGE, true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,19 +207,19 @@ struct boss_janalai : public BossAI
|
||||
return false;
|
||||
|
||||
if (hatchAction == HATCH_RESET)
|
||||
{
|
||||
for (Creature* egg : eggList)
|
||||
egg->Respawn();
|
||||
else if (hatchAction == HATCH_ALL)
|
||||
DoCastSelf(SPELL_HATCH_EGG_ALL);
|
||||
|
||||
if (hatchAction == HATCH_RESET)
|
||||
{
|
||||
std::list<Creature* > hatchlingList;
|
||||
me->GetCreaturesWithEntryInRange(hatchlingList, 100.0f, NPC_HATCHLING);
|
||||
for (Creature* hatchling : hatchlingList)
|
||||
hatchling->DespawnOrUnsummon();
|
||||
hatchlingList.clear();
|
||||
}
|
||||
else if (hatchAction == HATCH_ALL)
|
||||
DoCastSelf(SPELL_HATCH_EGG_ALL);
|
||||
|
||||
eggList.clear();
|
||||
return true;
|
||||
}
|
||||
@@ -239,9 +237,7 @@ struct boss_janalai : public BossAI
|
||||
: me->SummonCreature(NPC_FIRE_BOMB, fireWallCoords[i].GetPositionX() - 2 + 4 * j, fireWallCoords[i].GetPositionY(), fireWallCoords[i].GetPositionZ(), fireWallCoords[i].GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 15000);
|
||||
|
||||
if (wall)
|
||||
{
|
||||
wall->AI()->DoCastSelf(SPELL_FIRE_WALL, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,18 +255,16 @@ struct boss_janalai : public BossAI
|
||||
|
||||
void Boom()
|
||||
{
|
||||
std::list<Creature*> fireBombs;
|
||||
me->GetCreaturesWithEntryInRange(fireBombs, 100.0f, NPC_FIRE_BOMB);
|
||||
|
||||
if (fireBombs.empty())
|
||||
return;
|
||||
|
||||
for (Creature* bomb : fireBombs)
|
||||
{
|
||||
bomb->AI()->DoCastSelf(SPELL_FIRE_BOMB_DAMAGE, true);
|
||||
bomb->RemoveAllAuras();
|
||||
}
|
||||
fireBombs.clear();
|
||||
summons.DoForAllSummons([&](WorldObject* summon) {
|
||||
if (summon->GetEntry() == NPC_FIRE_BOMB)
|
||||
{
|
||||
if (Creature* bomb = summon->ToCreature())
|
||||
{
|
||||
bomb->AI()->DoCastSelf(SPELL_FIRE_BOMB_DAMAGE, true);
|
||||
bomb->RemoveAllAuras();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void StartBombing()
|
||||
@@ -286,14 +280,11 @@ struct boss_janalai : public BossAI
|
||||
SpawnBombs();
|
||||
_isBombing = true;
|
||||
|
||||
if (Map* map = me->GetMap())
|
||||
me->GetMap()->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->IsAlive())
|
||||
DoTeleportPlayer(player, janalainPos.GetPositionX() - 5 + rand() % 10, janalainPos.GetPositionY() - 5 + rand() % 10, janalainPos.GetPositionZ(), 0.0f);
|
||||
});
|
||||
}
|
||||
if (player->IsAlive())
|
||||
DoTeleportPlayer(player, janalainPos.GetPositionX() - 5 + rand() % 10, janalainPos.GetPositionY() - 5 + rand() % 10, janalainPos.GetPositionZ(), 0.0f);
|
||||
});
|
||||
//DoCast(Temp, SPELL_SUMMON_PLAYERS, true) // core bug, spell does not work if too far
|
||||
ThrowBombs();
|
||||
|
||||
@@ -308,20 +299,23 @@ struct boss_janalai : public BossAI
|
||||
|
||||
void ThrowBombs()
|
||||
{
|
||||
std::list<Creature*> fireBombs;
|
||||
std::chrono::milliseconds bombTimer = 100ms;
|
||||
me->GetCreaturesWithEntryInRange(fireBombs, 100.0f, NPC_FIRE_BOMB);
|
||||
for (Creature* bomb : fireBombs)
|
||||
{
|
||||
scheduler.Schedule(bombTimer, [this, bomb](TaskContext)
|
||||
|
||||
summons.DoForAllSummons([this, &bombTimer](WorldObject* summon) {
|
||||
if (summon->GetEntry() == NPC_FIRE_BOMB)
|
||||
{
|
||||
bomb->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
DoCast(bomb, SPELL_FIRE_BOMB_THROW, true);
|
||||
bomb->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
});
|
||||
bombTimer = bombTimer + 100ms;
|
||||
}
|
||||
fireBombs.clear();
|
||||
if (Creature* bomb = summon->ToCreature())
|
||||
{
|
||||
bomb->m_Events.AddEventAtOffset([this, bomb] {
|
||||
bomb->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
DoCast(bomb, SPELL_FIRE_BOMB_THROW, true);
|
||||
bomb->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
}, bombTimer);
|
||||
}
|
||||
|
||||
bombTimer += 100ms;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool CheckEvadeIfOutOfCombatArea() const override
|
||||
@@ -333,23 +327,9 @@ private:
|
||||
bool _isFlameBreathing;
|
||||
};
|
||||
|
||||
struct npc_janalai_firebomb : public NullCreatureAI
|
||||
{
|
||||
npc_janalai_firebomb(Creature* creature) : NullCreatureAI(creature) { }
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id == SPELL_FIRE_BOMB_THROW)
|
||||
DoCastSelf(SPELL_FIRE_BOMB_DUMMY, true);
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_janalai_hatcher : public ScriptedAI
|
||||
{
|
||||
npc_janalai_hatcher(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_instance = creature->GetInstanceScript();
|
||||
}
|
||||
npc_janalai_hatcher(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
@@ -358,7 +338,6 @@ struct npc_janalai_hatcher : public ScriptedAI
|
||||
_side = (me->GetPositionY() < 1150);
|
||||
_waypoint = 0;
|
||||
_isHatching = false;
|
||||
_hasChangedSide = false;
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MovePoint(0, hatcherway[_side][0]);
|
||||
}
|
||||
@@ -368,29 +347,13 @@ struct npc_janalai_hatcher : public ScriptedAI
|
||||
if (_waypoint == 5)
|
||||
{
|
||||
_isHatching = true;
|
||||
std::list<Creature* > eggList;
|
||||
me->GetCreaturesWithEntryInRange(eggList, 50.0f, NPC_EGG);
|
||||
scheduler.Schedule(1500ms, SCHEDULER_GROUP_HATCHING, [this, eggList](TaskContext context)
|
||||
|
||||
scheduler.Schedule(1500ms, SCHEDULER_GROUP_HATCHING, [this](TaskContext context)
|
||||
{
|
||||
std::list<Creature* > unhatchedEggs;
|
||||
for (Creature* egg : eggList)
|
||||
{
|
||||
if (egg->IsAlive())
|
||||
unhatchedEggs.emplace_front(egg);
|
||||
}
|
||||
Acore::Containers::RandomResize(unhatchedEggs, 1);
|
||||
if (Creature* egg = unhatchedEggs.front())
|
||||
egg->AI()->DoCastSelf(SPELL_HATCH_EGG_SINGULAR);
|
||||
else if (!_hasChangedSide)
|
||||
{
|
||||
_side = _side ? 0 : 1;
|
||||
_isHatching = false;
|
||||
_waypoint = 3;
|
||||
MoveToNewWaypoint(_waypoint);
|
||||
_hasChangedSide = true;
|
||||
context.CancelGroup(SCHEDULER_GROUP_HATCHING);
|
||||
}
|
||||
context.Repeat(1500ms);
|
||||
me->CastCustomSpell(SPELL_HATCH_EGG_ALL, SPELLVALUE_MAX_TARGETS, context.GetRepeatCounter() + 1);
|
||||
|
||||
if (me->FindNearestCreature(NPC_EGG, 100.0f))
|
||||
context.Repeat(4s);
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -422,19 +385,14 @@ struct npc_janalai_hatcher : public ScriptedAI
|
||||
void MoveInLineOfSight(Unit* /*who*/) override { }
|
||||
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
uint8 _side;
|
||||
uint8 _waypoint;
|
||||
bool _isHatching;
|
||||
bool _hasChangedSide;
|
||||
};
|
||||
|
||||
struct npc_janalai_hatchling : public ScriptedAI
|
||||
{
|
||||
npc_janalai_hatchling(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_instance = creature->GetInstanceScript();
|
||||
}
|
||||
npc_janalai_hatchling(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
@@ -444,7 +402,6 @@ struct npc_janalai_hatchling : public ScriptedAI
|
||||
else
|
||||
me->GetMotionMaster()->MovePoint(0, hatcherway[1][3].GetPositionX() + rand() % 4 - 2, 1150.0f + rand() % 4 - 2, hatcherway[1][3].GetPositionY());
|
||||
|
||||
me->SetDisableGravity(true);
|
||||
me->SetInCombatWithZone();
|
||||
}
|
||||
|
||||
@@ -465,27 +422,11 @@ struct npc_janalai_hatchling : public ScriptedAI
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
struct npc_janalai_egg : public NullCreatureAI
|
||||
{
|
||||
npc_janalai_egg(Creature* creature) : NullCreatureAI(creature) { }
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id == SPELL_HATCH_EGG_ALL || spell->Id == SPELL_HATCH_EGG_SINGULAR)
|
||||
DoCastSelf(SPELL_SUMMON_HATCHLING);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_janalai()
|
||||
{
|
||||
RegisterZulAmanCreatureAI(boss_janalai);
|
||||
RegisterZulAmanCreatureAI(npc_janalai_firebomb);
|
||||
RegisterZulAmanCreatureAI(npc_janalai_hatcher);
|
||||
RegisterZulAmanCreatureAI(npc_janalai_hatchling);
|
||||
RegisterZulAmanCreatureAI(npc_janalai_egg);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user