Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-01-23 23:23:53 +08:00
77 changed files with 1682 additions and 1680 deletions
+72 -60
View File
@@ -18,40 +18,49 @@
#ifndef LOCKEDQUEUE_H
#define LOCKEDQUEUE_H
#include <atomic>
#include <deque>
#include <memory>
#include <mutex>
template <class T, typename StorageType = std::deque<T>>
class LockedQueue
{
//! Lock access to the queue.
std::mutex _lock;
mutable std::mutex _lock; ///< Mutex to protect access to the queue
//! Storage backing the queue.
StorageType _queue;
std::atomic<bool> _canceled{false}; ///< Flag indicating if the queue is canceled
//! Cancellation flag.
volatile bool _canceled{false};
StorageType _queue; ///< Storage container for the queue
public:
//! Create a LockedQueue.
/**
* @brief Default constructor to create an empty LockedQueue.
*/
LockedQueue() = default;
//! Destroy a LockedQueue.
/**
* @brief Destructor for LockedQueue.
*/
virtual ~LockedQueue() = default;
//! Adds an item to the queue.
/**
* @brief Adds an item to the back of the queue.
*
* @param item The item to be added to the queue.
*/
void add(const T& item)
{
lock();
_queue.push_back(item);
unlock();
std::lock_guard<std::mutex> lock(_lock);
_queue.push_back(std::move(item));
}
//! Adds items back to front of the queue
/**
* @brief Adds a range of items to the front of the queue.
*
* @param begin Iterator pointing to the beginning of the range of items to be added.
* @param end Iterator pointing to the end of the range of items to be added.
*/
template<class Iterator>
void readd(Iterator begin, Iterator end)
{
@@ -59,33 +68,42 @@ public:
_queue.insert(_queue.begin(), begin, end);
}
//! Gets the next result in the queue, if any.
/**
* @brief Gets the next item in the queue and removes it.
*
* @param result The variable where the next item will be stored.
* @return true if an item was retrieved and removed, false if the queue is empty.
*/
bool next(T& result)
{
std::lock_guard<std::mutex> lock(_lock);
if (_queue.empty())
{
return false;
}
result = _queue.front();
result = std::move(_queue.front());
_queue.pop_front();
return true;
}
/**
* @brief Retrieves the next item from the queue if it satisfies the provided checker.
*
* @param result The variable where the next item will be stored.
* @param check A checker object that will be used to validate the item.
* @return true if an item was retrieved, checked, and removed; false otherwise.
*/
template<class Checker>
bool next(T& result, Checker& check)
{
std::lock_guard<std::mutex> lock(_lock);
if (_queue.empty())
{
return false;
}
result = _queue.front();
result = std::move(_queue.front());
if (!check.Process(result))
{
return false;
@@ -95,60 +113,54 @@ public:
return true;
}
//! Peeks at the top of the queue. Check if the queue is empty before calling! Remember to unlock after use if autoUnlock == false.
T& peek(bool autoUnlock = false)
/**
* @brief Peeks at the top of the queue without removing it.
*
* @return A reference to the item at the front of the queue, assuming there's an item in the queue (as per previous implementation)
*/
T& peek()
{
lock();
T& result = _queue.front();
if (autoUnlock)
{
unlock();
}
return result;
std::lock_guard<std::mutex> lock(_lock);
return _queue.front();
}
//! Cancels the queue.
/**
* @brief Cancels the queue, preventing further processing of items.
*/
void cancel()
{
std::lock_guard<std::mutex> lock(_lock);
_canceled = true;
_canceled.store(true, std::memory_order_release);
}
//! Checks if the queue is cancelled.
bool cancelled()
/**
* @brief Checks if the queue has been canceled.
*
* @return true if the queue is canceled, false otherwise.
*/
bool cancelled() const
{
return _canceled.load(std::memory_order_acquire);
}
/**
* @brief Checks if the queue is empty.
*
* @return true if the queue is empty, false otherwise.
*/
bool empty() const
{
std::lock_guard<std::mutex> lock(_lock);
return _canceled;
return _queue.empty();
}
//! Locks the queue for access.
void lock()
{
this->_lock.lock();
}
//! Unlocks the queue.
void unlock()
{
this->_lock.unlock();
}
///! Calls pop_front of the queue
/**
* @brief Removes the item at the front of the queue.
*/
void pop_front()
{
std::lock_guard<std::mutex> lock(_lock);
_queue.pop_front();
}
///! Checks if we're empty or not with locks held
bool empty()
{
std::lock_guard<std::mutex> lock(_lock);
return _queue.empty();
}
};
#endif
+119 -30
View File
@@ -19,41 +19,81 @@
#define MPSCQueue_h__
#include <atomic>
#include <memory>
namespace Acore::Impl
{
// C++ implementation of Dmitry Vyukov's lock free MPSC queue
// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
/**
* @brief C++ implementation of Dmitry Vyukov's lock-free MPSC queue (Non-Intrusive).
*
* This queue allows multiple producers to enqueue items concurrently, but only one consumer
* can dequeue items. The queue is lock-free and non-intrusive, meaning it does not modify
* the data types that are enqueued.
*
* @tparam T The type of data that is being enqueued in the queue.
*/
template<typename T>
class MPSCQueueNonIntrusive
{
public:
MPSCQueueNonIntrusive() : _head(new Node()), _tail(_head.load(std::memory_order_relaxed))
/**
* @brief Constructs a new MPSCQueueNonIntrusive object.
*
* Initializes the queue with a dummy node and sets up atomic pointers to the head and tail.
*/
MPSCQueueNonIntrusive()
: _head(new Node(nullptr)), _tail(_head.load(std::memory_order_acquire))
{
Node* front = _head.load(std::memory_order_relaxed);
front->Next.store(nullptr, std::memory_order_relaxed);
Node* front = _head.load(std::memory_order_acquire);
front->Next.store(nullptr, std::memory_order_release); ///< Store with release to ensure visibility
}
/**
* @brief Destroys the MPSCQueueNonIntrusive object.
*
* Dequeues all items and deletes them, followed by proper cleanup of remaining nodes in the queue.
*/
~MPSCQueueNonIntrusive()
{
T* output;
while (Dequeue(output))
delete output;
Node* front = _head.load(std::memory_order_relaxed);
delete front;
// Properly delete remaining nodes
Node* front = _head.load(std::memory_order_acquire);
while (front)
{
Node* next = front->Next.load(std::memory_order_acquire);
delete front;
front = next;
}
}
/**
* @brief Enqueues a new item in the queue.
*
* This function adds a new item at the head of the queue.
*
* @param input Pointer to the item to be enqueued.
*/
void Enqueue(T* input)
{
Node* node = new Node(input);
Node* prevHead = _head.exchange(node, std::memory_order_acq_rel);
Node* prevHead = _head.exchange(node, std::memory_order_acq_rel); ///< Exchange with acquire-release semantics
prevHead->Next.store(node, std::memory_order_release);
}
/**
* @brief Dequeues an item from the queue.
*
* This function removes the item at the front of the queue and returns it.
*
* @param result Reference to a pointer where the dequeued item will be stored.
* @return True if an item was successfully dequeued, false if the queue was empty.
*/
bool Dequeue(T*& result)
{
Node* tail = _tail.load(std::memory_order_relaxed);
Node* tail = _tail.load(std::memory_order_acquire);
Node* next = tail->Next.load(std::memory_order_acquire);
if (!next)
return false;
@@ -65,39 +105,63 @@ namespace Acore::Impl
}
private:
/**
* @brief A structure representing a node in the queue.
*
* Each node holds a pointer to data and an atomic pointer to the next node in the queue.
*/
struct Node
{
Node() = default;
explicit Node(T* data) : Data(data)
{
Next.store(nullptr, std::memory_order_relaxed);
Next.store(nullptr, std::memory_order_release);
}
T* Data;
std::atomic<Node*> Next;
T* Data; ///< Data stored in the node
std::atomic<Node*> Next; ///< Atomic pointer to the next node
};
std::atomic<Node*> _head;
std::atomic<Node*> _tail;
std::atomic<Node*> _head; ///< Atomic pointer to the head node of the queue
std::atomic<Node*> _tail; ///< Atomic pointer to the tail node of the queue
MPSCQueueNonIntrusive(MPSCQueueNonIntrusive const&) = delete;
MPSCQueueNonIntrusive& operator=(MPSCQueueNonIntrusive const&) = delete;
MPSCQueueNonIntrusive(MPSCQueueNonIntrusive const&) = delete; ///< Deleted copy constructor
MPSCQueueNonIntrusive& operator=(MPSCQueueNonIntrusive const&) = delete; ///< Deleted copy assignment operator
};
// C++ implementation of Dmitry Vyukov's lock free MPSC queue
// http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
/**
* @brief C++ implementation of Dmitry Vyukov's lock-free MPSC queue (Intrusive).
*
* This queue allows multiple producers to enqueue items concurrently, but only one consumer
* can dequeue items. The queue is lock-free and intrusive, meaning that the enqueued objects
* must have an atomic link to the next item in the queue.
*
* @tparam T The type of data that is being enqueued in the queue.
* @tparam IntrusiveLink A member pointer to the atomic link used for linking the nodes.
*/
template<typename T, std::atomic<T*> T::* IntrusiveLink>
class MPSCQueueIntrusive
{
public:
MPSCQueueIntrusive() : _dummyPtr(reinterpret_cast<T*>(std::addressof(_dummy))), _head(_dummyPtr), _tail(_dummyPtr)
/**
* @brief Constructs a new MPSCQueueIntrusive object.
*
* Initializes the queue with a dummy node and sets up atomic pointers to the head and tail.
* The dummy node's atomic link is initialized.
*/
MPSCQueueIntrusive()
: _dummyPtr(reinterpret_cast<T*>(std::addressof(_dummy))), _head(_dummyPtr), _tail(_dummyPtr)
{
// _dummy is constructed from aligned_storage and is intentionally left uninitialized (it might not be default constructible)
// so we init only its IntrusiveLink here
// Initialize the intrusive link in the dummy node
std::atomic<T*>* dummyNext = new (&(_dummyPtr->*IntrusiveLink)) std::atomic<T*>();
dummyNext->store(nullptr, std::memory_order_relaxed);
dummyNext->store(nullptr, std::memory_order_release);
}
/**
* @brief Destroys the MPSCQueueIntrusive object.
*
* Dequeues all items and deletes them.
*/
~MPSCQueueIntrusive()
{
T* output;
@@ -105,16 +169,32 @@ namespace Acore::Impl
delete output;
}
/**
* @brief Enqueues a new item in the queue.
*
* This function adds a new item at the head of the queue.
*
* @param input Pointer to the item to be enqueued.
*/
void Enqueue(T* input)
{
// Set the next link to nullptr initially
(input->*IntrusiveLink).store(nullptr, std::memory_order_release);
T* prevHead = _head.exchange(input, std::memory_order_acq_rel);
T* prevHead = _head.exchange(input, std::memory_order_acq_rel); ///< Exchange with acquire-release semantics
(prevHead->*IntrusiveLink).store(input, std::memory_order_release);
}
/**
* @brief Dequeues an item from the queue.
*
* This function removes the item at the front of the queue and returns it.
*
* @param result Reference to a pointer where the dequeued item will be stored.
* @return True if an item was successfully dequeued, false if the queue was empty.
*/
bool Dequeue(T*& result)
{
T* tail = _tail.load(std::memory_order_relaxed);
T* tail = _tail.load(std::memory_order_acquire);
T* next = (tail->*IntrusiveLink).load(std::memory_order_acquire);
if (tail == _dummyPtr)
{
@@ -149,16 +229,25 @@ namespace Acore::Impl
}
private:
std::aligned_storage_t<sizeof(T), alignof(T)> _dummy;
T* _dummyPtr;
std::atomic<T*> _head;
std::atomic<T*> _tail;
std::aligned_storage_t<sizeof(T), alignof(T)> _dummy; ///< Storage for the dummy object
T* _dummyPtr; ///< Pointer to the dummy object
std::atomic<T*> _head; ///< Atomic pointer to the head node of the queue
std::atomic<T*> _tail; ///< Atomic pointer to the tail node of the queue
MPSCQueueIntrusive(MPSCQueueIntrusive const&) = delete;
MPSCQueueIntrusive& operator=(MPSCQueueIntrusive const&) = delete;
MPSCQueueIntrusive(MPSCQueueIntrusive const&) = delete; ///< Deleted copy constructor
MPSCQueueIntrusive& operator=(MPSCQueueIntrusive const&) = delete; ///< Deleted copy assignment operator
};
}
/**
* @brief Conditional type alias for MPSCQueue.
*
* This alias provides the appropriate type of MPSCQueue based on whether the queue is intrusive
* or non-intrusive.
*
* @tparam T The type of data that is being enqueued in the queue.
* @tparam IntrusiveLink If provided, the queue will be intrusive, otherwise, it will be non-intrusive.
*/
template<typename T, std::atomic<T*> T::* IntrusiveLink = nullptr>
using MPSCQueue = std::conditional_t<IntrusiveLink != nullptr, Acore::Impl::MPSCQueueIntrusive<T, IntrusiveLink>, Acore::Impl::MPSCQueueNonIntrusive<T>>;
@@ -27,14 +27,15 @@
#include "ScriptedCreature.h"
#include "SpellMgr.h"
#define AC_SAI_IS_BOOLEAN_VALID(e, value) \
{ \
if (value > 1) \
{ \
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses param {} of type Boolean with value {}, valid values are 0 or 1, skipped.", \
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), STRINGIZE(value), value); \
return false; \
} \
bool SmartAIMgr::IsSAIBoolValid(SmartScriptHolder const& e, SAIBool value)
{
if (value != 0 && value != 1)
{
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses param {} of type Boolean with value {}, valid values are 0 or 1, skipped.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), STRINGIZE(value), value);
return false;
}
return true;
}
SmartWaypointMgr* SmartWaypointMgr::instance()
@@ -513,23 +514,22 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
case SMART_TARGET_HOSTILE_LAST_AGGRO:
case SMART_TARGET_HOSTILE_RANDOM:
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP:
AC_SAI_IS_BOOLEAN_VALID(e, e.target.hostileRandom.playerOnly);
break;
return IsSAIBoolValid(e, e.target.hostileRandom.playerOnly);
case SMART_TARGET_FARTHEST:
AC_SAI_IS_BOOLEAN_VALID(e, e.target.farthest.playerOnly);
AC_SAI_IS_BOOLEAN_VALID(e, e.target.farthest.isInLos);
return IsSAIBoolValid(e, e.target.farthest.playerOnly) &&
IsSAIBoolValid(e, e.target.farthest.isInLos);
break;
case SMART_TARGET_CLOSEST_CREATURE:
AC_SAI_IS_BOOLEAN_VALID(e, e.target.unitClosest.dead);
return IsSAIBoolValid(e, e.target.unitClosest.dead);
break;
case SMART_TARGET_CLOSEST_ENEMY:
AC_SAI_IS_BOOLEAN_VALID(e, e.target.closestAttackable.playerOnly);
return IsSAIBoolValid(e, e.target.closestAttackable.playerOnly);
break;
case SMART_TARGET_CLOSEST_FRIENDLY:
AC_SAI_IS_BOOLEAN_VALID(e, e.target.closestFriendly.playerOnly);
return IsSAIBoolValid(e, e.target.closestFriendly.playerOnly);
break;
case SMART_TARGET_OWNER_OR_SUMMONER:
AC_SAI_IS_BOOLEAN_VALID(e, e.target.owner.useCharmerOrOwner);
return IsSAIBoolValid(e, e.target.owner.useCharmerOrOwner);
break;
case SMART_TARGET_STORED:
case SMART_TARGET_PLAYER_WITH_AURA:
@@ -1079,9 +1079,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_EVENT_OOC_LOS:
case SMART_EVENT_IC_LOS:
if (!IsMinMaxValid(e, e.event.los.cooldownMin, e.event.los.cooldownMax))
{
return false;
}
if (e.event.los.hostilityMode >= AsUnderlyingType(SmartEvent::LOSHostilityMode::End))
{
@@ -1090,8 +1088,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
AC_SAI_IS_BOOLEAN_VALID(e, e.event.los.playerOnly);
break;
return IsSAIBoolValid(e, e.event.los.playerOnly);
case SMART_EVENT_RESPAWN:
if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && !sMapStore.LookupEntry(e.event.respawn.map))
{
@@ -1134,8 +1131,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
if (e.event.kill.creature && !IsCreatureValid(e, e.event.kill.creature))
return false;
AC_SAI_IS_BOOLEAN_VALID(e, e.event.kill.playerOnly);
break;
return IsSAIBoolValid(e, e.event.kill.playerOnly);
case SMART_EVENT_VICTIM_CASTING:
if (e.event.targetCasting.spellId > 0 && !sSpellMgr->GetSpellInfo(e.event.targetCasting.spellId))
{
@@ -1164,14 +1160,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_EVENT_ACCEPTED_QUEST:
case SMART_EVENT_REWARD_QUEST:
if (e.event.quest.quest && !IsQuestValid(e, e.event.quest.quest))
{
return false;
}
if (!IsMinMaxValid(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax))
{
return false;
}
break;
case SMART_EVENT_RECEIVE_EMOTE:
{
@@ -1464,8 +1456,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_SOUND:
if (!IsSoundValid(e, e.action.sound.sound))
return false;
AC_SAI_IS_BOOLEAN_VALID(e, e.action.sound.onlySelf);
break;
return IsSAIBoolValid(e, e.action.sound.onlySelf);
case SMART_ACTION_RANDOM_SOUND:
if (e.action.randomSound.sound1 && !IsSoundValid(e, e.action.randomSound.sound1))
return false;
@@ -1505,8 +1496,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
if (!IsQuestValid(e, e.action.questOffer.questID))
return false;
AC_SAI_IS_BOOLEAN_VALID(e, e.action.questOffer.directAdd);
break;
return IsSAIBoolValid(e, e.action.questOffer.directAdd);
case SMART_ACTION_FAIL_QUEST:
if (!IsQuestValid(e, e.action.quest.quest))
return false;
@@ -1651,8 +1641,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
AC_SAI_IS_BOOLEAN_VALID(e, e.action.summonCreature.attackInvoker);
break;
return IsSAIBoolValid(e, e.action.summonCreature.attackInvoker);
case SMART_ACTION_CALL_KILLEDMONSTER:
if (!IsCreatureValid(e, e.action.killedMonster.creature))
return false;
@@ -1660,8 +1649,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_UPDATE_TEMPLATE:
if (!IsCreatureValid(e, e.action.updateTemplate.creature))
return false;
AC_SAI_IS_BOOLEAN_VALID(e, e.action.updateTemplate.updateLevel);
break;
return IsSAIBoolValid(e, e.action.updateTemplate.updateLevel);
case SMART_ACTION_SET_SHEATH:
if (e.action.setSheath.sheath && e.action.setSheath.sheath >= MAX_SHEATH_STATE)
{
@@ -1707,8 +1695,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_WP_STOP:
if (e.action.wpStop.quest && !IsQuestValid(e, e.action.wpStop.quest))
return false;
AC_SAI_IS_BOOLEAN_VALID(e, e.action.wpStop.fail);
break;
return IsSAIBoolValid(e, e.action.wpStop.fail);
case SMART_ACTION_WP_START:
{
if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID))
@@ -1729,9 +1716,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
AC_SAI_IS_BOOLEAN_VALID(e, e.action.wpStart.run);
AC_SAI_IS_BOOLEAN_VALID(e, e.action.wpStart.repeat);
break;
return IsSAIBoolValid(e, e.action.wpStart.run) &&
IsSAIBoolValid(e, e.action.wpStart.repeat);
}
case SMART_ACTION_CREATE_TIMED_EVENT:
{
@@ -1872,85 +1858,42 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
break;
}
case SMART_ACTION_AUTO_ATTACK:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.autoAttack.attack);
break;
}
return IsSAIBoolValid(e, e.action.autoAttack.attack);
case SMART_ACTION_ALLOW_COMBAT_MOVEMENT:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.combatMove.move);
break;
}
return IsSAIBoolValid(e, e.action.combatMove.move);
case SMART_ACTION_CALL_FOR_HELP:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.callHelp.withEmote);
break;
}
return IsSAIBoolValid(e, e.action.callHelp.withEmote);
case SMART_ACTION_SET_VISIBILITY:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.visibility.state);
break;
}
return IsSAIBoolValid(e, e.action.visibility.state);
case SMART_ACTION_SET_RUN:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setRun.run);
break;
}
return IsSAIBoolValid(e, e.action.setRun.run);
case SMART_ACTION_SET_CAN_FLY:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setFly.fly);
break;
}
return IsSAIBoolValid(e, e.action.setFly.fly);
case SMART_ACTION_SET_SWIM:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setSwim.swim);
break;
}
return IsSAIBoolValid(e, e.action.setSwim.swim);
case SMART_ACTION_SET_COUNTER:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setCounter.reset);
break;
}
return IsSAIBoolValid(e, e.action.setCounter.reset);
case SMART_ACTION_INTERRUPT_SPELL:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.interruptSpellCasting.withDelayed);
AC_SAI_IS_BOOLEAN_VALID(e, e.action.interruptSpellCasting.withInstant);
break;
}
return IsSAIBoolValid(e, e.action.interruptSpellCasting.withDelayed) &&
IsSAIBoolValid(e, e.action.interruptSpellCasting.withInstant);
case SMART_ACTION_SET_ROOT:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setRoot.root);
break;
}
return IsSAIBoolValid(e, e.action.setRoot.root);
case SMART_ACTION_DISABLE_EVADE:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.disableEvade.disable);
break;
}
return IsSAIBoolValid(e, e.action.disableEvade.disable);
case SMART_ACTION_LOAD_EQUIPMENT:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.loadEquipment.force);
break;
}
return IsSAIBoolValid(e, e.action.loadEquipment.force);
case SMART_ACTION_TALK:
AC_SAI_IS_BOOLEAN_VALID(e, e.action.talk.useTalkTarget);
if (!IsTextValid(e, e.action.talk.textGroupID))
return false;
break;
return IsSAIBoolValid(e, e.action.talk.useTalkTarget);
case SMART_ACTION_SIMPLE_TALK:
if (!IsTextValid(e, e.action.simpleTalk.textGroupID))
return false;
break;
case SMART_ACTION_SET_HEALTH_REGEN:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setHealthRegen.regenHealth);
break;
}
return IsSAIBoolValid(e, e.action.setHealthRegen.regenHealth);
case SMART_ACTION_CALL_TIMED_ACTIONLIST:
{
AC_SAI_IS_BOOLEAN_VALID(e, e.action.timedActionList.allowOverride);
break;
}
return IsSAIBoolValid(e, e.action.timedActionList.allowOverride);
case SMART_ACTION_FLEE_FOR_ASSIST:
case SMART_ACTION_MOVE_TO_POS:
case SMART_ACTION_EVADE:
@@ -2219,6 +2219,7 @@ private:
return true;
}
static bool IsSAIBoolValid(SmartScriptHolder const& e, SAIBool value);
static bool IsTextValid(SmartScriptHolder const& e, uint32 id);
static bool CheckUnusedEventParams(SmartScriptHolder const& e);
static bool CheckUnusedActionParams(SmartScriptHolder const& e);
+1 -1
View File
@@ -32,7 +32,7 @@ enum AccountOpResult
AOR_DB_INTERNAL_ERROR
};
#define MAX_ACCOUNT_STR 20
#define MAX_ACCOUNT_STR 17
#define MAX_PASS_STR 16
#define MAX_EMAIL_STR 255
@@ -85,7 +85,7 @@ bool ArenaSpectator::HandleSpectatorSpectateCommand(ChatHandler* handler, std::s
if (player->IsInCombat())
errors.push_back("Can't be in combat.");
if (player->isUsingLfg())
if (player->IsUsingLfg())
errors.push_back("Can't spectate while using LFG system.");
if (player->InBattlegroundQueue())
+1 -4
View File
@@ -185,10 +185,7 @@ void Channel::JoinChannel(Player* player, std::string const& pass)
return;
}
if (HasFlag(CHANNEL_FLAG_LFG) &&
sWorld->getBoolConfig(CONFIG_RESTRICTED_LFG_CHANNEL) &&
AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) &&
player->GetGroup())
if (IsLFG() && sWorld->getBoolConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && !player->IsUsingLfg())
{
WorldPacket data;
MakeNotInLfg(&data);
+1 -1
View File
@@ -181,7 +181,7 @@ public:
[[nodiscard]] uint32 GetChannelDBId() const { return _channelDBId; }
[[nodiscard]] bool IsConstant() const { return _channelId != 0; }
[[nodiscard]] bool IsAnnounce() const { return _announce; }
[[nodiscard]] bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; }
[[nodiscard]] bool IsLFG() const { return HasFlag(CHANNEL_FLAG_LFG); }
[[nodiscard]] std::string const& GetPassword() const { return _password; }
void SetPassword(std::string const& npassword) { _password = npassword; }
[[nodiscard]] uint32 GetNumPlayers() const { return playersStore.size(); }
@@ -1001,43 +1001,25 @@ void GameObject::Delete()
AddObjectToRemoveList();
}
void GameObject::GetFishLoot(Loot* fishloot, Player* loot_owner)
void GameObject::GetFishLoot(Loot* fishLoot, Player* lootOwner, bool junk /*= false*/)
{
fishloot->clear();
fishLoot->clear();
uint32 zone, subzone;
uint32 defaultzone = 1;
GetZoneAndAreaId(zone, subzone);
uint32 zone, area;
uint32 defaultZone = 1;
GetZoneAndAreaId(zone, area);
// if subzone loot exist use it
fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true);
if (fishloot->empty()) //use this becase if zone or subzone has set LOOT_MODE_JUNK_FISH,Even if no normal drop, fishloot->FillLoot return true. it wrong.
uint16 lootMode = junk ? LOOT_MODE_JUNK_FISH : LOOT_MODE_DEFAULT;
// Check to fill loot in the order area - zone - defaultZone.
// This is because area and zone is not set in some places, like Off the coast of Storm Peaks.
uint32 lootZones[] = { area, zone, defaultZone };
for (uint32 fillZone : lootZones)
{
//subzone no result,use zone loot
fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true);
//use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks.
if (fishloot->empty())
fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true);
}
}
fishLoot->FillLoot(fillZone, LootTemplates_Fishing, lootOwner, true, true, lootMode);
void GameObject::GetFishLootJunk(Loot* fishloot, Player* loot_owner)
{
fishloot->clear();
uint32 zone, subzone;
uint32 defaultzone = 1;
GetZoneAndAreaId(zone, subzone);
// if subzone loot exist use it
fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
if (fishloot->empty()) //use this becase if zone or subzone has normal mask drop, then fishloot->FillLoot return true.
{
//use zone loot
fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
if (fishloot->empty())
//use zone 1 as default
fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
// If the loot is filled and the loot is eligible, then we break out of the loop.
if (!fishLoot->empty() && !fishLoot->isLooted())
break;
}
}
@@ -198,8 +198,7 @@ public:
void Refresh();
void DespawnOrUnsummon(Milliseconds delay = 0ms, Seconds forcedRespawnTime = 0s);
void Delete();
void GetFishLoot(Loot* loot, Player* loot_owner);
void GetFishLootJunk(Loot* loot, Player* loot_owner);
void GetFishLoot(Loot* fishLoot, Player* lootOwner, bool junk = false);
[[nodiscard]] GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
[[nodiscard]] GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
+2 -2
View File
@@ -7896,7 +7896,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
if (loot_type == LOOT_FISHING)
go->GetFishLoot(loot, this);
else if (loot_type == LOOT_FISHING_JUNK)
go->GetFishLootJunk(loot, this);
go->GetFishLoot(loot, this, true);
if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
{
@@ -13111,7 +13111,7 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid targetPlayerGUID) const
return ERR_PARTY_RESULT_OK;
}
bool Player::isUsingLfg()
bool Player::IsUsingLfg()
{
return sLFGMgr->GetState(GetGUID()) != lfg::LFG_STATE_NONE;
}
+2 -1
View File
@@ -2062,6 +2062,7 @@ public:
bool IsInChannel(const Channel* c);
void CleanupChannels();
void ClearChannelWatch();
void UpdateLFGChannel();
void UpdateLocalChannels(uint32 newZone);
void UpdateDefense();
@@ -2397,7 +2398,7 @@ public:
void SetAtLoginFlag(AtLoginFlags f) { m_atLoginFlags |= f; }
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist = false);
bool isUsingLfg();
bool IsUsingLfg();
bool inRandomLfgDungeon();
typedef std::set<uint32> DFQuestsDoneList;
@@ -5687,7 +5687,8 @@ void Player::_LoadActions(PreparedQueryResult result)
ab->uState = ACTIONBUTTON_UNCHANGED;
else
{
LOG_ERROR("entities.player", "ActionButton loading problem, will be deleted from db...");
LOG_ERROR("entities.player", "ActionButton loading problem, will be deleted from db. player: {}, guid: {}, button: {}, action: {}, type: {}", GetName(), GetGUID().GetCounter(), button, action, type);
// Will deleted in DB at next save (it can create data until save but marked as deleted)
m_actionButtons[button].uState = ACTIONBUTTON_DELETED;
@@ -462,6 +462,44 @@ void Player::UpdateNextMailTimeAndUnreads()
}
}
void Player::UpdateLFGChannel()
{
if (!sWorld->getBoolConfig(CONFIG_RESTRICTED_LFG_CHANNEL))
return;
ChannelMgr* cMgr = ChannelMgr::forTeam(GetTeamId());
if (!cMgr)
return;
ChatChannelsEntry const* cce = sChatChannelsStore.LookupEntry(26); /*LookingForGroup*/
Channel* cLFG = cMgr->GetJoinChannel(cce->pattern[m_session->GetSessionDbcLocale()], cce->ChannelID);
if (!cLFG)
return;
Channel* cUsed = nullptr;
for (Channel* channel : m_channels)
if (channel && channel->GetChannelId() == cce->ChannelID)
{
cUsed = cLFG;
break;
}
if (IsUsingLfg())
{
if (cUsed == cLFG)
return;
cLFG->JoinChannel(this, "");
}
else
{
if (cLFG != cUsed)
return;
cLFG->LeaveChannel(this, true);
}
}
void Player::UpdateLocalChannels(uint32 newZone)
{
// pussywizard: mutex needed (tc changed opcode to THREAD UNSAFE)
+15 -3
View File
@@ -10401,6 +10401,10 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
if (meleeAttack)
AddUnitState(UNIT_STATE_MELEE_ATTACKING);
// Update leash timer when attacking creatures
if (victim->IsCreature())
victim->ToCreature()->UpdateLeashExtensionTime();
// set position before any AI calls/assistance
//if (IsCreature())
// ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
@@ -10410,6 +10414,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
SetInCombatWith(victim);
if (victim->IsPlayer())
victim->SetInCombatWith(this);
AddThreat(victim, 0.0f);
creature->SendAIReaction(AI_REACTION_HOSTILE);
@@ -13640,9 +13645,6 @@ void Unit::SetInCombatWith(Unit* enemy, uint32 duration)
}
}
if (Creature* pCreature = ToCreature())
pCreature->UpdateLeashExtensionTime();
SetInCombatState(false, enemy, duration);
}
@@ -13717,6 +13719,10 @@ void Unit::CombatStart(Unit* victim, bool initialAggro)
SetInCombatWith(victim);
victim->SetInCombatWith(this);
// Update leash timer when attacking creatures
if (victim->IsCreature())
victim->ToCreature()->UpdateLeashExtensionTime();
// Xinef: If pet started combat - put owner in combat
if (!alreadyInCombat && IsInCombat())
{
@@ -13753,6 +13759,12 @@ void Unit::CombatStartOnCast(Unit* target, bool initialAggro, uint32 duration)
// Xinef: If pet started combat - put owner in combat
if (Unit* owner = GetOwner())
owner->SetInCombatWith(target, duration);
// Update leash timer when attacking creatures
if (target->IsCreature())
target->ToCreature()->UpdateLeashExtensionTime();
else if (ToCreature()) // Reset leash if it is a spell caster, else it may evade inbetween casts
ToCreature()->UpdateLeashExtensionTime();
}
Unit* who = target->GetCharmerOrOwnerOrSelf();
+1 -1
View File
@@ -8688,7 +8688,7 @@ bool ObjectMgr::LoadModuleStringsLocale()
std::string const* ObjectMgr::GetModuleString(std::string module, uint32 id, LocaleConstant locale) const
{
ModuleString const* ms = GetModuleString(module, id);
if (ms->Content.size())
if (ms && !ms->Content.empty())
{
if (ms->Content.size() > size_t(locale) && !ms->Content[locale].empty())
return &ms->Content[locale];
@@ -47,15 +47,11 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
return;
if (channelName.size() >= 100 || !DisallowHyperlinksAndMaybeKick(channelName))
{
return;
}
if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeamId()))
{
if (Channel* channel = cMgr->GetJoinChannel(channelName, channelId))
channel->JoinChannel(GetPlayer(), password);
}
}
void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket)
@@ -70,10 +66,8 @@ void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket)
return;
if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeamId()))
{
if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
channel->LeaveChannel(GetPlayer(), true);
}
}
void WorldSession::HandleChannelList(WorldPacket& recvPacket)
+2
View File
@@ -71,6 +71,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPackets::LFG::LFGJoin& packet)
GetPlayerInfo(), packet.Roles, newDungeons.size(), packet.Comment);
sLFGMgr->JoinLfg(GetPlayer(), uint8(packet.Roles), newDungeons, packet.Comment);
GetPlayer()->UpdateLFGChannel();
}
void WorldSession::HandleLfgLeaveOpcode(WorldPackets::LFG::LFGLeave& /*packet*/)
@@ -87,6 +88,7 @@ void WorldSession::HandleLfgLeaveOpcode(WorldPackets::LFG::LFGLeave& /*packet*/)
sLFGMgr->LeaveLfg(sLFGMgr->GetState(guid) == lfg::LFG_STATE_RAIDBROWSER ? guid : gguid);
sLFGMgr->LeaveAllLfgQueues(guid, true, group ? group->GetGUID() : ObjectGuid::Empty);
}
GetPlayer()->UpdateLFGChannel();
}
void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recvData)
@@ -55,6 +55,18 @@ void InstanceScript::SaveToDB()
CharacterDatabase.Execute(stmt);
}
void InstanceScript::OnPlayerEnter(Player* player)
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsTwoFactionInstance())
player->SetFaction((_teamIdInInstance == TEAM_HORDE) ? 1610 /*FACTION_HORDE*/ : 1 /*FACTION_ALLIANCE*/);
}
void InstanceScript::OnPlayerLeave(Player* player)
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsTwoFactionInstance())
player->SetFactionForRace(player->getRace());
}
void InstanceScript::OnCreatureCreate(Creature* creature)
{
AddObject(creature);
@@ -584,6 +596,12 @@ void InstanceScript::DoRespawnGameObject(ObjectGuid uiGuid, uint32 uiTimeToDespa
LOG_DEBUG("scripts", "InstanceScript: DoRespawnGameObject failed");
}
void InstanceScript::DoRespawnGameObject(uint32 type)
{
if (GameObject* go = instance->GetGameObject(GetObjectGuid(type)))
go->Respawn();
}
void InstanceScript::DoRespawnCreature(ObjectGuid guid, bool force)
{
if (Creature* creature = instance->GetCreature(guid))
@@ -848,3 +866,21 @@ bool InstanceHasScript(WorldObject const* obj, char const* scriptName)
return false;
}
bool InstanceScript::IsTwoFactionInstance() const
{
switch (instance->GetId())
{
case 540: // Shattered Halls
case 576: // Nexus
case 631: // Icecrown Citadel
case 632: // Forge of Souls
case 649: // Trial of the Champion
case 650: // Trial of the Crusader
case 658: // Pit of Saron
case 668: // Halls of Reflection
return true;
}
return false;
}
+11 -3
View File
@@ -141,7 +141,7 @@ typedef std::map<ObjectGuid::LowType /*spawnId*/, uint8 /*state*/> ObjectStateMa
class InstanceScript : public ZoneScript
{
public:
explicit InstanceScript(Map* map) : instance(map), completedEncounters(0) {}
explicit InstanceScript(Map* map) : instance(map), completedEncounters(0), _teamIdInInstance(TEAM_NEUTRAL) {}
~InstanceScript() override {}
@@ -182,10 +182,10 @@ public:
GameObject* GetGameObject(uint32 type);
//Called when a player successfully enters the instance.
virtual void OnPlayerEnter(Player* /*player*/) {}
virtual void OnPlayerEnter(Player* /*player*/);
//Called when a player successfully leaves the instance.
virtual void OnPlayerLeave(Player* /*player*/) {}
virtual void OnPlayerLeave(Player* /*player*/);
virtual void OnPlayerAreaUpdate(Player* /*player*/, uint32 /*oldArea*/, uint32 /*newArea*/) {}
@@ -203,6 +203,9 @@ public:
//Respawns a GO having negative spawntimesecs in gameobject-table
void DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn = MINUTE);
// Respawns a GO by instance storage index
void DoRespawnGameObject(uint32 type);
// Respawns a creature.
void DoRespawnCreature(ObjectGuid guid, bool force = false);
@@ -282,6 +285,10 @@ public:
[[nodiscard]] bool AllBossesDone() const;
[[nodiscard]] bool AllBossesDone(std::initializer_list<uint32> bossIds) const;
TeamId GetTeamIdInInstance() const { return _teamIdInInstance; }
void SetTeamIdInInstance(TeamId teamId) { _teamIdInInstance = teamId; }
bool IsTwoFactionInstance() const;
TaskScheduler scheduler;
protected:
void SetHeaders(std::string const& dataHeaders);
@@ -336,6 +343,7 @@ private:
ObjectGuidMap _objectGuids;
ObjectStateMap _objectStateMap;
uint32 completedEncounters; // completed encounter mask, bit indexes are DungeonEncounter.dbc boss numbers, used for packets
TeamId _teamIdInInstance;
std::unordered_set<uint32> _activatedAreaTriggers;
};
+10 -1
View File
@@ -103,7 +103,7 @@ bool Map::ExistMap(uint32 mapid, int gx, int gy)
{
if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic)
{
LOG_ERROR("maps", "Map file '{}' is from an incompatible map version (%.*u v{}), %.*s v{} is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files.",
LOG_ERROR("maps", "Map file '{}' is from an incompatible map version ({:.4u} v{}), {:.4s} v{} is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files.",
tmp, 4, header.mapMagic, header.versionMagic, 4, MapMagic.asChar, MapVersionMagic);
}
@@ -3026,6 +3026,15 @@ bool InstanceMap::AddPlayerToMap(Player* player)
m_resetAfterUnload = false;
m_unloadWhenEmpty = false;
if (instance_data && instance_data->IsTwoFactionInstance()
&& instance_data->GetTeamIdInInstance() == TEAM_NEUTRAL)
{
instance_data->SetTeamIdInInstance(player->GetTeamId());
if (Group* group = player->GetGroup())
if (Player* leader = ObjectAccessor::FindConnectedPlayer(group->GetLeaderGUID()))
instance_data->SetTeamIdInInstance(leader->GetTeamId());
}
// this will acquire the same mutex so it cannot be in the previous block
Map::AddPlayerToMap(player);
@@ -84,6 +84,21 @@ void ScriptMgr::OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_DUMMY_EFFECT_ITEM, script->OnDummyEffect(caster, spellID, effIndex, itemTarget));
}
void ScriptMgr::OnSpellCastCancel(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool bySelf)
{
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_CAST_CANCEL, script->OnSpellCastCancel(spell, caster, spellInfo, bySelf));
}
void ScriptMgr::OnSpellCast(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool skipCheck)
{
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_CAST, script->OnSpellCast(spell, caster, spellInfo, skipCheck));
}
void ScriptMgr::OnSpellPrepare(Spell* spell, Unit* caster, SpellInfo const* spellInfo)
{
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_PREPARE, script->OnSpellPrepare(spell, caster, spellInfo));
}
AllSpellScript::AllSpellScript(char const* name, std::vector<uint16> enabledHooks)
: ScriptObject(name, ALLSPELLHOOK_END)
{
@@ -36,6 +36,9 @@ enum AllSpellHook
ALLSPELLHOOK_ON_DUMMY_EFFECT_GAMEOBJECT,
ALLSPELLHOOK_ON_DUMMY_EFFECT_CREATURE,
ALLSPELLHOOK_ON_DUMMY_EFFECT_ITEM,
ALLSPELLHOOK_ON_CAST_CANCEL,
ALLSPELLHOOK_ON_CAST,
ALLSPELLHOOK_ON_PREPARE,
ALLSPELLHOOK_END
};
@@ -100,6 +103,12 @@ public:
* @param itemTarget Contains information about the Item
*/
virtual void OnDummyEffect(WorldObject* /*caster*/, uint32 /*spellID*/, SpellEffIndex /*effIndex*/, Item* /*itemTarget*/) { }
virtual void OnSpellCastCancel(Spell* /*spell*/, Unit* /*caster*/, SpellInfo const* /*spellInfo*/, bool /*bySelf*/) { }
virtual void OnSpellCast(Spell* /*spell*/, Unit* /*caster*/, SpellInfo const* /*spellInfo*/, bool /*skipCheck*/) { }
virtual void OnSpellPrepare(Spell* /*spell*/, Unit* /*caster*/, SpellInfo const* /*spellInfo*/) { }
};
// Compatibility for old scripts
+3
View File
@@ -648,6 +648,9 @@ public: /* SpellSC */
void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, GameObject* gameObjTarget);
void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, Creature* creatureTarget);
void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, Item* itemTarget);
void OnSpellCastCancel(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool bySelf);
void OnSpellCast(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool skipCheck);
void OnSpellPrepare(Spell* spell, Unit* caster, SpellInfo const* spellInfo);
public: /* GameEventScript */
void OnGameEventStart(uint16 EventID);
+6
View File
@@ -3717,6 +3717,8 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const
TriggerGlobalCooldown();
}
sScriptMgr->OnSpellPrepare(this, m_caster, m_spellInfo);
return SPELL_CAST_OK;
}
@@ -3788,6 +3790,8 @@ void Spell::cancel(bool bySelf)
//set state back so finish will be processed
m_spellState = oldState;
sScriptMgr->OnSpellCastCancel(this, m_caster, m_spellInfo, bySelf);
finish(false);
}
@@ -4114,6 +4118,8 @@ void Spell::_cast(bool skipCheck)
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true);
sScriptMgr->OnSpellCast(this, m_caster, m_spellInfo, skipCheck);
SetExecutedCurrently(false);
}
-2
View File
@@ -2644,8 +2644,6 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
// some explicitly required dummy effect sets
switch (Id)
{
case 28441:
return false; // AB Effect 000
default:
break;
}
+12 -12
View File
@@ -207,14 +207,14 @@ public:
switch (mode)
{
case BAN_ACCOUNT:
banReturn = sBan->BanAccount(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "");
banReturn = sBan->BanAccount(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "Console");
break;
case BAN_CHARACTER:
banReturn = sBan->BanAccountByPlayerName(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "");
banReturn = sBan->BanAccountByPlayerName(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "Console");
break;
case BAN_IP:
default:
banReturn = sBan->BanIP(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "");
banReturn = sBan->BanIP(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "Console");
break;
}
@@ -444,7 +444,7 @@ public:
if (banResult)
{
Field* fields2 = banResult->Fetch();
handler->PSendSysMessage("%s", fields2[0].Get<std::string>());
handler->PSendSysMessage("{}", fields2[0].Get<std::string>());
}
} while (result->NextRow());
}
@@ -480,14 +480,14 @@ public:
if (fields2[0].Get<uint32>() == fields2[1].Get<uint32>())
{
handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|",
handler->PSendSysMessage("|{:<15.15}|{:02}-{:02}-{:02} {:02}:{:02}| permanent |{:<15.15}|{:<15.15}|",
accountName, tmBan.tm_year % 100, tmBan.tm_mon + 1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min,
fields2[2].Get<std::string>(), fields2[3].Get<std::string>());
}
else
{
tm tmUnban = Acore::Time::TimeBreakdown(fields2[1].Get<uint32>());
handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|",
handler->PSendSysMessage("|{:<15.15}|{:02}-{:02}-{:02} {:02}:{:02}|{:02}-{:02}-{:02} {:02}:{:02}|{:<15.15}|{:<15.15}|",
accountName, tmBan.tm_year % 100, tmBan.tm_mon + 1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min,
tmUnban.tm_year % 100, tmUnban.tm_mon + 1, tmUnban.tm_mday, tmUnban.tm_hour, tmUnban.tm_min,
fields2[2].Get<std::string>(), fields2[3].Get<std::string>());
@@ -534,7 +534,7 @@ public:
PreparedQueryResult banResult = CharacterDatabase.Query(stmt2);
if (banResult)
handler->PSendSysMessage("%s", (*banResult)[0].Get<std::string>());
handler->PSendSysMessage("{}", (*banResult)[0].Get<std::string>());
} while (result->NextRow());
}
// Console wide output
@@ -564,14 +564,14 @@ public:
if (banFields[0].Get<uint32>() == banFields[1].Get<uint32>())
{
handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|",
handler->PSendSysMessage("|{:<15.15}|{:02}-{:02}-{:02} {:02}:{:02}| permanent |{:<15.15}|{:<15.15}|",
char_name, tmBan.tm_year % 100, tmBan.tm_mon + 1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min,
banFields[2].Get<std::string>(), banFields[3].Get<std::string>());
}
else
{
tm tmUnban = Acore::Time::TimeBreakdown(banFields[1].Get<uint32>());
handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|",
handler->PSendSysMessage("|{:<15.15}|{:02}-{:02}-{:02} {:02}:{:02}|{:02}-{:02}-{:02} {:02}:{:02}|{:<15.15}|{:<15.15}|",
char_name, tmBan.tm_year % 100, tmBan.tm_mon + 1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min,
tmUnban.tm_year % 100, tmUnban.tm_mon + 1, tmUnban.tm_mday, tmUnban.tm_hour, tmUnban.tm_min,
banFields[2].Get<std::string>(), banFields[3].Get<std::string>());
@@ -621,7 +621,7 @@ public:
do
{
Field* fields = result->Fetch();
handler->PSendSysMessage("%s", fields[0].Get<std::string>());
handler->PSendSysMessage("{}", fields[0].Get<std::string>());
} while (result->NextRow());
}
// Console wide output
@@ -637,14 +637,14 @@ public:
tm tmBan = Acore::Time::TimeBreakdown(fields[1].Get<uint32>());
if (fields[1].Get<uint32>() == fields[2].Get<uint32>())
{
handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|",
handler->PSendSysMessage("{:<15.15}|{:02}-{:02}-{:02} {:02}:{:02}| permanent |{:<15.15}|{:<15.15}|",
fields[0].Get<std::string>(), tmBan.tm_year % 100, tmBan.tm_mon + 1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min,
fields[3].Get<std::string>(), fields[4].Get<std::string>());
}
else
{
tm tmUnban = Acore::Time::TimeBreakdown(fields[2].Get<uint32>());
handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|",
handler->PSendSysMessage("|{:<15.15}|{:02}-{:02}-{:02} {:02}:{:02}|{:02}-{:02}-{:02} {:02}:{:02}|{:<15.15}|{:<15.15}|",
fields[0].Get<std::string>(), tmBan.tm_year % 100, tmBan.tm_mon + 1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min,
tmUnban.tm_year % 100, tmUnban.tm_mon + 1, tmUnban.tm_mday, tmUnban.tm_hour, tmUnban.tm_min,
fields[3].Get<std::string>(), fields[4].Get<std::string>());
+1 -1
View File
@@ -924,7 +924,7 @@ public:
passenger->EnterVehicle(target, *seatId);
}
handler->PSendSysMessage("Unit {} entered vehicle %hhd", entry, *seatId);
handler->PSendSysMessage("Unit {} entered vehicle {:d}", entry, *seatId);
return true;
}
+1 -1
View File
@@ -280,7 +280,7 @@ public:
break;
}
if (plr->isUsingLfg())
if (plr->IsUsingLfg())
{
error = 4;
break;
+1 -1
View File
@@ -217,7 +217,7 @@ public:
static bool HandleMmapStatsCommand(ChatHandler* handler)
{
handler->PSendSysMessage("mmap stats:");
//handler->PSendSysMessage(" global mmap pathfinding is %sabled", DisableMgr::IsPathfindingEnabled(mapId) ? "en" : "dis");
//handler->PSendSysMessage(" global mmap pathfinding is {}abled", DisableMgr::IsPathfindingEnabled(mapId) ? "en" : "dis");
MMAP::MMapMgr* manager = MMAP::MMapFactory::createOrGetMMapMgr();
handler->PSendSysMessage(" {} maps loaded with {} tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
+5 -4
View File
@@ -807,8 +807,8 @@ public:
if (!result)
{
handler->SendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM);
return true;
handler->SendErrorMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetSpawnId());
return false;
}
handler->SendSysMessage("|cff00ffffDEBUG: wp show info:|r");
@@ -912,15 +912,16 @@ public:
return false;
}
wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
// Set "wpguid" column to the visual waypoint
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID);
stmt->SetData(0, int32(wpCreature->GetSpawnId()));
stmt->SetData(0, wpCreature->GetSpawnId());
stmt->SetData(1, pathid);
stmt->SetData(2, point);
WorldDatabase.Execute(stmt);
wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
if (!wpCreature->LoadCreatureFromDB(wpCreature->GetSpawnId(), map, true, true))
{
@@ -31,7 +31,8 @@ enum Says
SAY_GRAVITY_LAPSE = 3,
SAY_TIRED = 4,
SAY_RECAST_GRAVITY = 5,
SAY_DEATH = 6
SAY_DEATH = 6,
SAY_AGGRO_2 = 7
};
enum Spells
@@ -78,6 +79,8 @@ struct boss_felblood_kaelthas : public BossAI
_gravityLapseCounter = 0;
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
me->SetImmuneToAll(false);
summons.DespawnAll();
ScheduleHealthCheckEvent(50, [&]{
me->CastStop();
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true);
@@ -170,6 +173,7 @@ struct boss_felblood_kaelthas : public BossAI
if (!_hasDoneIntro && me->IsWithinDistInMap(who, 40.0f) && who->IsPlayer())
{
Talk(SAY_AGGRO);
Talk(SAY_AGGRO_2, 20s);
_hasDoneIntro = true;
_OOCScheduler.Schedule(35s, [this](TaskContext){
me->SetReactState(REACT_AGGRESSIVE);
@@ -161,7 +161,7 @@ struct boss_selin_fireheart : public BossAI
if (Creature* crystal = SelectNearestCrystal(false))
{
Talk(EMOTE_CRYSTAL);
crystal->ReplaceAllUnitFlags(UNIT_FLAG_NONE);
crystal->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
crystal->SetInCombatWithZone();
crystal->AI()->DoCast(me, SPELL_MANA_RAGE, true);
DoCast(crystal, SPELL_FEL_CRYSTAL_COSMETIC, true);
@@ -51,24 +51,34 @@ enum Misc
struct boss_vexallus : public BossAI
{
boss_vexallus(Creature* creature) : BossAI(creature, DATA_VEXALLUS) { }
boss_vexallus(Creature* creature) : BossAI(creature, DATA_VEXALLUS), _energyCooldown(false) { }
void Reset() override
{
_Reset();
_energyCooldown = false;
ScheduleHealthCheckEvent({ 85, 70, 55, 40 }, [&]
ScheduleHealthCheckEvent({ 85, 70, 55, 40, 25 }, [&]
{
Talk(SAY_ENERGY);
Talk(EMOTE_DISCHARGE_ENERGY);
if (IsHeroic())
if (!_energyCooldown)
{
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H1);
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H2);
Talk(SAY_ENERGY);
Talk(EMOTE_DISCHARGE_ENERGY);
if (IsHeroic())
{
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H1);
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H2);
}
else
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_N);
_energyCooldown = true;
scheduler.Schedule(5s, [this](TaskContext)
{
_energyCooldown = false;
});
}
else
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_N);
});
ScheduleHealthCheckEvent(20, [&]
@@ -117,6 +127,9 @@ struct boss_vexallus : public BossAI
if (killer)
killer->CastSpell(killer, SPELL_ENERGY_FEEDBACK, true, 0, 0, summon->GetGUID());
}
private:
bool _energyCooldown;
};
void AddSC_boss_vexallus()
@@ -15,50 +15,63 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureScript.h"
#include "InstanceMapScript.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "SmartAI.h"
#include "scarletmonastery.h"
#include "ScriptedCreature.h"
enum AshbringerEventMisc
{
AURA_OF_ASHBRINGER = 28282,
NPC_SCARLET_MYRIDON = 4295,
NPC_SCARLET_DEFENDER = 4298,
NPC_SCARLET_CENTURION = 4301,
NPC_SCARLET_SORCERER = 4294,
NPC_SCARLET_WIZARD = 4300,
NPC_SCARLET_ABBOT = 4303,
NPC_SCARLET_MONK = 4540,
NPC_SCARLET_CHAMPION = 4302,
NPC_SCARLET_CHAPLAIN = 4299,
NPC_FAIRBANKS = 4542,
NPC_COMMANDER_MOGRAINE = 3976,
NPC_INQUISITOR_WHITEMANE = 3977,
DOOR_HIGH_INQUISITOR_ID = 104600,
NPC_COMMANDER_MOGRAINE = 3976,
NPC_INQUISITOR_WHITEMANE = 3977,
NPC_SCARLET_SORCERER = 4294,
NPC_SCARLET_MYRIDON = 4295,
NPC_SCARLET_DEFENDER = 4298,
NPC_SCARLET_CHAPLAIN = 4299,
NPC_SCARLET_WIZARD = 4300,
NPC_SCARLET_CENTURION = 4301,
NPC_SCARLET_CHAMPION = 4302,
NPC_SCARLET_ABBOT = 4303,
NPC_SCARLET_MONK = 4540,
NPC_FAIRBANKS = 4542,
NPC_HIGHLORD_MOGRAINE = 16062,
GO_CHAPEL_DOOR = 104591,
GO_HIGH_INQUISITOR_DOOR = 104600
};
enum AshbringerSpell
{
//Highlord Mograine Spells
//Needs Fix: Increased the visual effect of spells on hit
SPELL_FORGIVENESS = 28697,
//High Inquisitor Fairbanks
//Needs Fix: Increased the visual effect of spells on hit
SPELL_TRANSFORM_GHOST = 28443
};
enum DataTypes
{
TYPE_MOGRAINE_AND_WHITE_EVENT = 1,
TYPE_MOGRAINE_AND_WHITE_EVENT = 1,
TYPE_ASHBRINGER_EVENT = 2,
DATA_MOGRAINE = 2,
DATA_WHITEMANE = 3,
DATA_DOOR_WHITEMANE = 4,
DATA_MOGRAINE = 3,
DATA_WHITEMANE = 4,
DATA_DOOR_WHITEMANE = 5,
DATA_HORSEMAN_EVENT = 6,
DATA_VORREL = 7,
DATA_ARCANIST_DOAN = 8,
DATA_DOOR_CHAPEL = 9,
DATA_HORSEMAN_EVENT = 5,
GAMEOBJECT_PUMPKIN_SHRINE = 6,
DATA_VORREL = 7,
DATA_ARCANIST_DOAN = 8
GAMEOBJECT_PUMPKIN_SHRINE = 10
};
float const CATHEDRAL_PULL_RANGE = 80.0f; // Distance from the Cathedral doors to where Mograine is standing
class instance_scarlet_monastery : public InstanceMapScript
{
public:
instance_scarlet_monastery() : InstanceMapScript("instance_scarlet_monastery", 189) { }
instance_scarlet_monastery() : InstanceMapScript("instance_scarlet_monastery", 189) {}
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
@@ -72,55 +85,18 @@ public:
SetHeaders(DataHeader);
}
void OnPlayerEnter(Player* player) override
{
if (player->HasAura(AURA_OF_ASHBRINGER))
{
std::list<Creature*> ScarletList;
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_MYRIDON, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_DEFENDER, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_CENTURION, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_SORCERER, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_WIZARD, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_ABBOT, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_MONK, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_CHAMPION, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_CHAPLAIN, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_COMMANDER_MOGRAINE, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_FAIRBANKS, 4000.0f);
if (!ScarletList.empty())
for (std::list<Creature*>::iterator itr = ScarletList.begin(); itr != ScarletList.end(); itr++) (*itr)->SetFaction(FACTION_FRIENDLY);
}
}
void OnPlayerAreaUpdate(Player* player, uint32 /*oldArea*/, uint32 /*newArea*/) override
{
if (player->HasAura(AURA_OF_ASHBRINGER))
{
std::list<Creature*> ScarletList;
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_MYRIDON, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_DEFENDER, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_CENTURION, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_SORCERER, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_WIZARD, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_ABBOT, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_MONK, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_CHAMPION, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_SCARLET_CHAPLAIN, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_COMMANDER_MOGRAINE, 4000.0f);
player->GetCreatureListWithEntryInGrid(ScarletList, NPC_FAIRBANKS, 4000.0f);
if (!ScarletList.empty())
for (std::list<Creature*>::iterator itr = ScarletList.begin(); itr != ScarletList.end(); itr++) (*itr)->SetFaction(FACTION_FRIENDLY);
}
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
//case ENTRY_PUMPKIN_SHRINE: PumpkinShrineGUID = go->GetGUID(); break;
case DOOR_HIGH_INQUISITOR_ID:
DoorHighInquisitorGUID = go->GetGUID();
// case ENTRY_PUMPKIN_SHRINE: PumpkinShrineGUID = go->GetGUID(); break;
case GO_HIGH_INQUISITOR_DOOR:
_doorHighInquisitorGUID = go->GetGUID();
break;
case GO_CHAPEL_DOOR:
_doorChapelGUID = go->GetGUID();
break;
default:
break;
}
}
@@ -129,11 +105,26 @@ public:
{
switch (creature->GetEntry())
{
case NPC_SCARLET_MYRIDON:
case NPC_SCARLET_DEFENDER:
case NPC_SCARLET_CENTURION:
case NPC_SCARLET_SORCERER:
case NPC_SCARLET_WIZARD:
case NPC_SCARLET_ABBOT:
case NPC_SCARLET_MONK:
case NPC_SCARLET_CHAMPION:
case NPC_SCARLET_CHAPLAIN:
case NPC_FAIRBANKS:
_ashbringerNpcGUID.emplace(creature->GetGUID());
break;
case NPC_COMMANDER_MOGRAINE:
MograineGUID = creature->GetGUID();
_mograineGUID = creature->GetGUID();
_ashbringerNpcGUID.emplace(creature->GetGUID());
break;
case NPC_INQUISITOR_WHITEMANE:
WhitemaneGUID = creature->GetGUID();
_whitemaneGUID = creature->GetGUID();
break;
default:
break;
}
}
@@ -145,19 +136,90 @@ public:
case TYPE_MOGRAINE_AND_WHITE_EVENT:
if (data == IN_PROGRESS)
{
DoUseDoorOrButton(DoorHighInquisitorGUID);
encounter = IN_PROGRESS;
if (Creature* mograine = instance->GetCreature(_mograineGUID))
{
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, mograine, NPC_SCARLET_MONK, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, mograine, NPC_SCARLET_ABBOT, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, mograine, NPC_SCARLET_CHAMPION, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, mograine, NPC_SCARLET_CENTURION, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, mograine, NPC_SCARLET_WIZARD, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, mograine, NPC_SCARLET_CHAPLAIN, CATHEDRAL_PULL_RANGE);
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
{
if (Creature* creature = *itr)
creature->AI()->AttackStart(mograine->GetVictim());
}
}
_encounter = IN_PROGRESS;
}
if (data == FAIL)
{
DoUseDoorOrButton(DoorHighInquisitorGUID);
encounter = FAIL;
Creature* whitemane = instance->GetCreature(_whitemaneGUID);
if (!whitemane)
return;
Creature* mograine = instance->GetCreature(_mograineGUID);
if (!mograine)
return;
if (whitemane->IsAlive() && mograine->IsAlive())
{
// When Whitemane emerges from the main gate, Whitemane will stand next to Mograine's corpse and will not reset Whitemane
if (whitemane->IsEngaged()||whitemane->IsInEvadeMode())
whitemane->DespawnOnEvade(20s);
mograine->DespawnOnEvade(20s);
_encounter = NOT_STARTED;
return;
}
// Whitemane will not be able to fight Mograine again when he dies
if (!whitemane->IsAlive())
{
mograine->DespawnOrUnsummon();
_encounter = data;
return;
}
if (whitemane->IsAlive() && !mograine->IsAlive())
{
whitemane->DespawnOnEvade(20s);
_encounter = data;
return;
}
_encounter = data;
}
if (data == SPECIAL)
encounter = SPECIAL;
if (data == DONE)
_encounter = DONE;
break;
case TYPE_ASHBRINGER_EVENT:
if (data == IN_PROGRESS)
{
// the ashbringer incident did not sniff out any data from whitemane
if (Creature* whitemane = instance->GetCreature(_whitemaneGUID))
if (whitemane->IsAlive() && !whitemane->IsEngaged())
whitemane->DespawnOrUnsummon();
if (GameObject* go = instance->GetGameObject(_doorChapelGUID))
{
go->SetGoState(GO_STATE_ACTIVE);
go->SetLootState(GO_ACTIVATED);
go->SetGameObjectFlag(GO_FLAG_IN_USE);
}
for (auto const& scarletCathedralNpcGuid : _ashbringerNpcGUID)
if (Creature* scarletNpc = instance->GetCreature(scarletCathedralNpcGuid))
if (scarletNpc->IsAlive() && !scarletNpc->IsEngaged())
scarletNpc->SetFaction(FACTION_FRIENDLY);
}
_ashencounter = data;
break;
case DATA_HORSEMAN_EVENT:
encounter = data;
_encounter = data;
break;
default:
break;
}
}
@@ -167,528 +229,49 @@ public:
switch (type)
{
case DATA_MOGRAINE:
return MograineGUID;
return _mograineGUID;
case DATA_WHITEMANE:
return WhitemaneGUID;
return _whitemaneGUID;
case DATA_DOOR_WHITEMANE:
return DoorHighInquisitorGUID;
return _doorHighInquisitorGUID;
case DATA_DOOR_CHAPEL:
return _doorChapelGUID;
default:
return ObjectGuid::Empty;
break;
}
return ObjectGuid::Empty;
}
uint32 GetData(uint32 type) const override
{
if (type == TYPE_MOGRAINE_AND_WHITE_EVENT)
return encounter;
else if (type == DATA_HORSEMAN_EVENT)
return encounter;
return 0;
}
private:
ObjectGuid DoorHighInquisitorGUID;
ObjectGuid MograineGUID;
ObjectGuid WhitemaneGUID;
uint32 encounter;
};
};
enum ScarletMonasteryTrashMisc
{
SAY_WELCOME = 0,
AURA_ASHBRINGER = 28282,
//FACTION_FRIENDLY_TO_ALL = 35,
NPC_HIGHLORD_MOGRAINE = 16440,
SPELL_COSMETIC_CHAIN = 45537,
SPELL_COSMETIC_EXPLODE = 45935,
SPELL_FORGIVENESS = 28697,
};
enum MograineEvents
{
EVENT_SPELL_CRUSADER_STRIKE = 1,
EVENT_SPELL_HAMMER_OF_JUSTICE = 2,
EVENT_PULL_CATHEDRAL = 3
};
enum WhitemaneEvents
{
EVENT_SPELL_HOLY_SMITE = 1,
EVENT_SPELL_POWER_WORLD_SHIELD = 2,
EVENT_SPELL_HEAL = 3
};
enum Spells
{
//Mograine Spells
SPELL_CRUSADER_STRIKE = 14518,
SPELL_HAMMER_OF_JUSTICE = 5589,
SPELL_LAY_ON_HANDS = 9257,
SPELL_RETRIBUTION_AURA = 8990,
SPELL_PERMANENT_FEIGN_DEATH = 29266,
//Whitemanes Spells
SPELL_SCARLET_RESURRECTION = 9232,
SPELL_DEEP_SLEEP = 9256,
SPELL_DOMINATE_MIND = 14515,
SPELL_HOLY_SMITE = 9481,
SPELL_HEAL = 12039,
SPELL_POWER_WORD_SHIELD = 22187
};
enum Says
{
//Mograine says
SAY_MO_AGGRO = 0,
SAY_MO_KILL = 1,
SAY_MO_RESURRECTED = 2,
//Whitemane says
SAY_WH_INTRO = 0,
SAY_WH_KILL = 1,
SAY_WH_RESURRECT = 2,
};
float const CATHEDRAL_PULL_RANGE = 80.0f; // Distance from the Cathedral doors to where Mograine is standing
class npc_mograine : public CreatureScript
{
public:
npc_mograine() : CreatureScript("npc_scarlet_commander_mograine") { }
struct npc_mograineAI : public ScriptedAI
{
npc_mograineAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
uint32 AshbringerEvent(uint32 uiSteps)
{
Creature* mograine = me->FindNearestCreature(NPC_HIGHLORD_MOGRAINE, 200.0f);
switch (uiSteps)
switch (type)
{
case 1:
me->GetMotionMaster()->MovePoint(0, 1152.039795f, 1398.405518f, 32.527878f);
return 2 * IN_MILLISECONDS;
case 2:
me->SetSheath(SHEATH_STATE_UNARMED);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
return 2 * IN_MILLISECONDS;
case 3:
Talk(3);
return 10 * IN_MILLISECONDS;
case 4:
me->SummonCreature(NPC_HIGHLORD_MOGRAINE, 1065.130737f, 1399.350586f, 30.763723f, 6.282961f, TEMPSUMMON_TIMED_DESPAWN, 400000)->SetName("Highlord Mograine");
me->FindNearestCreature(NPC_HIGHLORD_MOGRAINE, 200.0f)->SetFaction(FACTION_FRIENDLY);
return 30 * IN_MILLISECONDS;
case 5:
mograine->StopMovingOnCurrentPos();
mograine->AI()->Talk(0);
mograine->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
return 4 * IN_MILLISECONDS;
case 6:
me->SetStandState(UNIT_STAND_STATE_STAND);
return 2 * IN_MILLISECONDS;
case 7:
Talk(4);
return 4 * IN_MILLISECONDS;
case 8:
mograine->AI()->Talk(1);
return 11 * IN_MILLISECONDS;
case 9:
mograine->HandleEmoteCommand(EMOTE_ONESHOT_BATTLE_ROAR);
return 4 * IN_MILLISECONDS;
case 10:
me->SetSheath(SHEATH_STATE_UNARMED);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
Talk(5);
return 2 * IN_MILLISECONDS;
case 11:
mograine->CastSpell(me, SPELL_FORGIVENESS, false);
return 1 * IN_MILLISECONDS;
case 12:
mograine->CastSpell(me, SPELL_COSMETIC_CHAIN, true);
return 0.5 * IN_MILLISECONDS;
case 13:
mograine->AI()->Talk(2);
mograine->DespawnOrUnsummon(3 * IN_MILLISECONDS);
mograine->Kill(me, me, true);
return 0;
case TYPE_MOGRAINE_AND_WHITE_EVENT:
return _encounter;
break;
case DATA_HORSEMAN_EVENT:
return _encounter;
break;
case TYPE_ASHBRINGER_EVENT:
return _ashencounter;
break;
default:
if (mograine)
mograine->DespawnOrUnsummon(0);
return 0;
break;
}
}
void PullCathedral() // CallForHelp will ignore any npcs without LOS
{
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, NPC_SCARLET_MONK, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, me, NPC_SCARLET_ABBOT, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, me, NPC_SCARLET_CHAMPION, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, me, NPC_SCARLET_CENTURION, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, me, NPC_SCARLET_WIZARD, CATHEDRAL_PULL_RANGE);
GetCreatureListWithEntryInGrid(creatureList, me, NPC_SCARLET_CHAPLAIN, CATHEDRAL_PULL_RANGE);
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
{
if (Creature* creature = *itr)
creature->AI()->AttackStart(me->GetVictim());
}
}
void Reset() override
{
//Incase wipe during phase that mograine fake death
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
SayAshbringer = false;
timer = 0;
step = 1;
hasDied = false;
heal = false;
fakeDeath = false;
events.Reset();
}
void MoveInLineOfSight(Unit* who) override
{
if (who && who->GetDistance2d(me) < 15.0f)
if (Player* player = who->ToPlayer())
if (player->HasAura(AURA_ASHBRINGER) && !SayAshbringer)
{
me->SetFaction(FACTION_FRIENDLY);
me->SetSheath(SHEATH_STATE_UNARMED);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->SetFacingToObject(player);
// me->Yell(12389, LANG_UNIVERSAL, player); // Doesn't exist
SayAshbringer = true;
}
ScriptedAI::MoveInLineOfSight(who);
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_MO_AGGRO);
me->CastSpell(me, SPELL_RETRIBUTION_AURA, true);
events.ScheduleEvent(EVENT_PULL_CATHEDRAL, 1s); // Has to be done via event, otherwise mob aggroing Mograine DOES NOT aggro the room
events.ScheduleEvent(EVENT_SPELL_CRUSADER_STRIKE, 1s, 5s);
events.ScheduleEvent(EVENT_SPELL_HAMMER_OF_JUSTICE, 6s, 11s);
}
void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (damage < me->GetHealth() || hasDied || fakeDeath)
return;
//On first death, fake death and open door, as well as initiate whitemane if exist
if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_WHITEMANE)))
{
instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS);
Whitemane->GetMotionMaster()->MovePoint(1, 1163.113370f, 1398.856812f, 32.527786f);
me->GetMotionMaster()->MovementExpired();
me->GetMotionMaster()->MoveIdle();
me->SetHealth(0);
if (me->IsNonMeleeSpellCast(false))
me->InterruptNonMeleeSpells(false);
me->ClearComboPointHolders();
me->RemoveAllAuras();
me->ClearAllReactives();
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->CastSpell(me, SPELL_PERMANENT_FEIGN_DEATH, true);
hasDied = true;
fakeDeath = true;
damage = 0;
ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_WHITEMANE))->SetInCombatWithZone();
}
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_MO_KILL);
}
void SpellHit(Unit* /*who*/, SpellInfo const* spell) override
{
//When hit with resurrection say text
if (spell->Id == SPELL_SCARLET_RESURRECTION)
{
Talk(SAY_MO_RESURRECTED);
fakeDeath = false;
instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, SPECIAL);
}
}
void UpdateAI(uint32 diff) override
{
timer = timer - diff;
if (SayAshbringer && step < 15)
{
if (timer <= 0)
{
timer = AshbringerEvent(step);
step++;
}
}
if (!UpdateVictim())
return;
if (hasDied && !heal && instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == SPECIAL)
{
//On resurrection, stop fake death and heal whitemane and resume fight
if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_WHITEMANE)))
{
//Incase wipe during phase that mograine fake death
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
me->CastSpell(me, SPELL_RETRIBUTION_AURA, true);
me->CastSpell(Whitemane, SPELL_LAY_ON_HANDS, true);
events.ScheduleEvent(EVENT_SPELL_CRUSADER_STRIKE, 1s, 5s);
events.ScheduleEvent(EVENT_SPELL_HAMMER_OF_JUSTICE, 6s, 11s);
if (me->GetVictim())
me->GetMotionMaster()->MoveChase(me->GetVictim());
heal = true;
}
}
//This if-check to make sure mograine does not attack while fake death
if (fakeDeath)
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SPELL_CRUSADER_STRIKE:
me->CastSpell(me->GetVictim(), SPELL_CRUSADER_STRIKE, true);
events.ScheduleEvent(EVENT_SPELL_CRUSADER_STRIKE, 10s);
break;
case EVENT_SPELL_HAMMER_OF_JUSTICE:
me->CastSpell(me->GetVictim(), SPELL_HAMMER_OF_JUSTICE, true);
events.ScheduleEvent(EVENT_SPELL_HAMMER_OF_JUSTICE, 60s);
break;
case EVENT_PULL_CATHEDRAL:
PullCathedral();
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool SayAshbringer = false;
int timer = 0;
int step = 1;
bool hasDied;
bool heal;
bool fakeDeath;
EventMap events;
InstanceScript* instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetScarletMonasteryAI<npc_mograineAI>(creature);
}
};
class boss_high_inquisitor_whitemane : public CreatureScript
{
public:
boss_high_inquisitor_whitemane() : CreatureScript("boss_high_inquisitor_whitemane") { }
struct boss_high_inquisitor_whitemaneAI : public ScriptedAI
{
boss_high_inquisitor_whitemaneAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
void Reset() override
{
canResurrectCheck = false;
canResurrect = false;
Wait_Timer = 7000;
Heal_Timer = 10000;
}
void JustReachedHome() override
{
instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, FAIL);
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_WH_INTRO);
events.ScheduleEvent(EVENT_SPELL_HOLY_SMITE, 1s, 3s);
events.ScheduleEvent(EVENT_SPELL_POWER_WORLD_SHIELD, 6s);
events.ScheduleEvent(EVENT_SPELL_HEAL, 9s);
}
void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if ((!canResurrectCheck || canResurrect) && damage >= me->GetHealth())
damage = me->GetHealth() - 1;
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_WH_KILL);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (canResurrect)
{
//When casting resuruction make sure to delay so on rez when reinstate battle deepsleep runs out
if (Wait_Timer <= diff)
{
if (ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOGRAINE)))
{
DoCast(SPELL_SCARLET_RESURRECTION);
Talk(SAY_WH_RESURRECT);
canResurrect = false;
}
}
else Wait_Timer -= diff;
}
//Cast Deep sleep when health is less than 50%
if (!canResurrectCheck && !HealthAbovePct(50))
{
if (me->IsNonMeleeSpellCast(false))
me->InterruptNonMeleeSpells(false);
me->CastSpell(me->GetVictim(), SPELL_DEEP_SLEEP, true);
canResurrectCheck = true;
canResurrect = true;
return;
}
//while in "resurrect-mode", don't do anything
if (canResurrect)
return;
//If we are <75% hp cast healing spells at self or Mograine
if (Heal_Timer <= diff)
{
Creature* target = nullptr;
if (!HealthAbovePct(75))
target = me;
if (Creature* mograine = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOGRAINE)))
{
// checking canResurrectCheck prevents her healing Mograine while he is "faking death"
if (canResurrectCheck && mograine->IsAlive() && !mograine->HealthAbovePct(75))
target = mograine;
}
if (target)
me->CastSpell(target, SPELL_HEAL, false);
Heal_Timer = 13000;
}
else Heal_Timer -= diff;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SPELL_POWER_WORLD_SHIELD:
me->CastSpell(me, SPELL_POWER_WORD_SHIELD, false);
events.ScheduleEvent(EVENT_SPELL_POWER_WORLD_SHIELD, 15s);
break;
case EVENT_SPELL_HOLY_SMITE:
me->CastSpell(me->GetVictim(), SPELL_HOLY_SMITE, false);
events.ScheduleEvent(EVENT_SPELL_HOLY_SMITE, 6s);
break;
case EVENT_SPELL_HEAL:
me->CastSpell(me, SPELL_HEAL, false);
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
uint32 Heal_Timer;
uint32 Wait_Timer;
bool canResurrectCheck;
bool canResurrect;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetScarletMonasteryAI<boss_high_inquisitor_whitemaneAI>(creature);
}
};
class npc_fairbanks : public CreatureScript
{
public:
npc_fairbanks() : CreatureScript("npc_fairbanks") { }
struct npc_fairbanksAI : public SmartAI
{
npc_fairbanksAI(Creature* creature) : SmartAI(creature) { }
void Reset() override
{
SayAshbringer = false;
}
void MoveInLineOfSight(Unit* who) override
{
if (who && who->GetDistance2d(me) < 2.0f)
if (Player* player = who->ToPlayer())
if (player->HasAura(AURA_ASHBRINGER) && !SayAshbringer)
{
me->SetFaction(FACTION_FRIENDLY);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->CastSpell(me, 57767, true);
me->SetDisplayId(16179);
me->SetFacingToObject(player);
SayAshbringer = true;
}
SmartAI::MoveInLineOfSight(who);
}
private:
bool SayAshbringer = false;
ObjectGuid _doorHighInquisitorGUID;
ObjectGuid _doorChapelGUID;
ObjectGuid _mograineGUID;
ObjectGuid _whitemaneGUID;
uint32 _encounter{};
uint32 _ashencounter{};
GuidSet _ashbringerNpcGUID;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetScarletMonasteryAI<npc_fairbanksAI>(creature);
}
};
void AddSC_instance_scarlet_monastery()
{
new instance_scarlet_monastery();
new npc_fairbanks();
new npc_mograine();
new boss_high_inquisitor_whitemane();
}
@@ -65,7 +65,7 @@ ObjectData const creatureData[] =
{ NPC_JANALAI, DATA_JANALAI },
{ NPC_SPIRIT_LYNX, DATA_SPIRIT_LYNX },
{ NPC_HARRISON_JONES, DATA_HARRISON_JONES },
{ NPC_AMINISHI_LOOKOUT, DATA_LOOKOUT },
{ NPC_AMANISHI_LOOKOUT, DATA_LOOKOUT },
{ 0, 0 }
};
@@ -127,13 +127,18 @@ public:
{
switch (creature->GetEntry())
{
case NPC_AMANISHI_GUARDIAN:
case NPC_AMANISHI_SAVAGE:
if (creature->GetPositionY() >= 1500.0f) // gate
creature->SetImmuneToAll(true);
break;
// Akil'zon gauntlet
case NPC_AMINISHI_TEMPEST:
case NPC_AMANISHI_TEMPEST:
if (creature->GetPositionZ() >= 50.0f) // excludes Tempest in Hexlord Malacrass' trash
AkilzonTrash.insert(creature->GetGUID());
break;
case NPC_AMINISHI_LOOKOUT:
case NPC_AMINISHI_PROTECTOR:
case NPC_AMANISHI_LOOKOUT:
case NPC_AMANISHI_PROTECTOR:
case NPC_EAGLE_TRASH_AGGRO_TRIGGER:
AkilzonTrash.insert(creature->GetGUID());
break;
@@ -226,8 +231,8 @@ public:
case NPC_EAGLE_TRASH_AGGRO_TRIGGER:
creature->DisappearAndDie();
break;
case NPC_AMINISHI_LOOKOUT:
case NPC_AMINISHI_TEMPEST:
case NPC_AMANISHI_LOOKOUT:
case NPC_AMANISHI_TEMPEST:
creature->AI()->DoAction(ACTION_START_AKILZON_GAUNTLET);
break;
default:
@@ -243,7 +248,7 @@ public:
{
if (!creature->IsAlive())
creature->Respawn();
else if (creature->GetEntry() == NPC_AMINISHI_TEMPEST)
else if (creature->GetEntry() == NPC_AMANISHI_TEMPEST)
creature->AI()->DoAction(ACTION_RESET_AKILZON_GAUNTLET);
}
if (Creature* creature = GetCreature(DATA_LOOKOUT))
@@ -259,7 +264,7 @@ public:
switch (creature->GetEntry())
{
case NPC_AMINISHI_PROTECTOR:
case NPC_AMANISHI_PROTECTOR:
case NPC_AMANISHI_WIND_WALKER:
if (_akilzonGauntlet == NOT_STARTED && AkilzonTrash.contains(creature->GetGUID()))
creature->DespawnOrUnsummon(30s, 1s);
@@ -272,8 +277,8 @@ public:
{
switch (creature->GetEntry())
{
case NPC_AMINISHI_TEMPEST:
case NPC_AMINISHI_PROTECTOR:
case NPC_AMANISHI_TEMPEST:
case NPC_AMANISHI_PROTECTOR:
case NPC_AMANISHI_WIND_WALKER:
if (AkilzonTrash.contains(creature->GetGUID()))
ResetAkilzonGauntlet();
@@ -358,8 +358,7 @@ enum DisplayIds
enum EntryIds
{
NPC_HARRISON_JONES_1 = 24375,
NPC_HARRISON_JONES_2 = 24365,
NPC_AMANISHI_GUARDIAN = 23597,
NPC_HARRISON_JONES_2 = 24365
};
enum Weapons
@@ -417,7 +416,10 @@ struct npc_harrison_jones : public ScriptedAI
std::list<Creature*> creatures;
me->GetCreatureListWithEntryInGrid(creatures, NPC_AMANISHI_SAVAGE, 100.0f);
for (Creature* creature : creatures)
{
creature->SetImmuneToAll(false);
creature->SetInCombatWithZone();
}
});
_instance->StorePersistentData(DATA_TIMED_RUN, 21);
_instance->DoAction(ACTION_START_TIMED_RUN);
@@ -60,11 +60,12 @@ enum CreatureIds
NPC_AMANISHI_MEDICINE_MAN = 23581,
NPC_AMANISHI_AXE_THROWER = 23542,
NPC_AMANI_HATCHLING = 23598, // 42493
NPC_AMANISHI_GUARDIAN = 23597,
// Akil'zon gauntlet
NPC_AMANISHI_WIND_WALKER = 24179,
NPC_AMINISHI_LOOKOUT = 24175,
NPC_AMINISHI_PROTECTOR = 24180,
NPC_AMINISHI_TEMPEST = 24549,
NPC_AMANISHI_LOOKOUT = 24175,
NPC_AMANISHI_PROTECTOR = 24180,
NPC_AMANISHI_TEMPEST = 24549,
NPC_EAGLE_TRASH_AGGRO_TRIGGER = 24223
};
@@ -161,136 +161,37 @@ static float PyrewoodSpawnPoints[3][4] =
{-397.018219f, 1510.208740f, 18.868748f, 4.731330f},
};
#define WAIT_SECS 6000
class pyrewood_ambush : public CreatureScript
struct npc_deathstalker_fearleia : public ScriptedAI
{
public:
pyrewood_ambush() : CreatureScript("pyrewood_ambush") { }
bool OnQuestAccept(Player* player, Creature* creature, const Quest* quest) override
npc_deathstalker_fearleia(Creature* creature) : ScriptedAI(creature), _summons(me)
{
if (quest->GetQuestId() == QUEST_PYREWOOD_AMBUSH && !CAST_AI(pyrewood_ambush::pyrewood_ambushAI, creature->AI())->QuestInProgress)
{
CAST_AI(pyrewood_ambush::pyrewood_ambushAI, creature->AI())->QuestInProgress = true;
CAST_AI(pyrewood_ambush::pyrewood_ambushAI, creature->AI())->Phase = 0;
CAST_AI(pyrewood_ambush::pyrewood_ambushAI, creature->AI())->KillCount = 0;
CAST_AI(pyrewood_ambush::pyrewood_ambushAI, creature->AI())->PlayerGUID = player->GetGUID();
}
return true;
_questInProgress = false;
}
CreatureAI* GetAI(Creature* creature) const override
void Reset() override
{
return new pyrewood_ambushAI(creature);
if (!_questInProgress)
{
_playerGUID.Clear();
_summons.DespawnAll();
}
}
struct pyrewood_ambushAI : public ScriptedAI
void sQuestAccept(Player* player, Quest const* quest) override
{
pyrewood_ambushAI(Creature* creature) : ScriptedAI(creature), Summons(me)
if (quest->GetQuestId() == QUEST_PYREWOOD_AMBUSH && !_questInProgress)
{
QuestInProgress = false;
_questInProgress = true;
_playerGUID = player->GetGUID();
}
uint32 Phase;
int8 KillCount;
uint32 WaitTimer;
ObjectGuid PlayerGUID;
SummonList Summons;
Talk(NPCSAY_INIT, player);
bool QuestInProgress;
void Reset() override
scheduler.Schedule(6s, [this](TaskContext context)
{
WaitTimer = WAIT_SECS;
if (!QuestInProgress) //fix reset values (see UpdateVictim)
{
Phase = 0;
KillCount = 0;
PlayerGUID.Clear();
Summons.DespawnAll();
}
}
void JustEngagedWith(Unit* /*who*/) override { }
void JustSummoned(Creature* summoned) override
{
Summons.Summon(summoned);
++KillCount;
}
void SummonedCreatureDespawn(Creature* summoned) override
{
Summons.Despawn(summoned);
--KillCount;
}
void SummonCreatureWithRandomTarget(uint32 creatureId, int position)
{
if (Creature* summoned = me->SummonCreature(creatureId, PyrewoodSpawnPoints[position][0], PyrewoodSpawnPoints[position][1], PyrewoodSpawnPoints[position][2], PyrewoodSpawnPoints[position][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000))
{
Unit* target = nullptr;
if (PlayerGUID)
if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID))
if (player->IsAlive() && RAND(0, 1))
target = player;
if (!target)
target = me;
summoned->SetFaction(FACTION_STORMWIND);
summoned->AddThreat(target, 32.0f);
summoned->AI()->AttackStart(target);
}
}
void JustDied(Unit* /*killer*/) override
{
if (PlayerGUID)
if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID))
if (player->GetQuestStatus(QUEST_PYREWOOD_AMBUSH) == QUEST_STATUS_INCOMPLETE)
player->FailQuest(QUEST_PYREWOOD_AMBUSH);
}
void UpdateAI(uint32 diff) override
{
//LOG_INFO("scripts", "DEBUG: p({}) k({}) d({}) W({})", Phase, KillCount, diff, WaitTimer);
if (!QuestInProgress)
return;
if (KillCount && Phase < 6)
{
if (!UpdateVictim()) //reset() on target Despawn...
return;
DoMeleeAttackIfReady();
return;
}
switch (Phase)
switch (context.GetRepeatCounter())
{
case 0:
if (WaitTimer == WAIT_SECS)
{
if (PlayerGUID)
{
if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID))
{
me->AI()->Talk(NPCSAY_INIT, player);
}
}
}
if (WaitTimer <= diff)
{
WaitTimer -= diff;
return;
}
break;
case 1:
SummonCreatureWithRandomTarget(2060, 1);
break;
case 2:
@@ -309,21 +210,73 @@ public:
SummonCreatureWithRandomTarget(2068, 2);
break;
case 5: //end
if (PlayerGUID)
if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID))
{
if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID))
{
me->AI()->Talk(NPCSAY_END, player);
player->GroupEventHappens(QUEST_PYREWOOD_AMBUSH, me);
}
Talk(NPCSAY_END, player);
player->GroupEventHappens(QUEST_PYREWOOD_AMBUSH, me);
}
QuestInProgress = false;
_questInProgress = false;
Reset();
break;
}
++Phase; //prepare next phase
if (context.GetRepeatCounter() < 5)
context.Repeat();
});
}
void JustEngagedWith(Unit* /*who*/) override {}
void JustSummoned(Creature* summoned) override
{
_summons.Summon(summoned);
}
void SummonedCreatureDespawn(Creature* summoned) override
{
_summons.Despawn(summoned);
}
void SummonCreatureWithRandomTarget(uint32 creatureId, int position)
{
if (Creature* summoned = me->SummonCreature(creatureId, PyrewoodSpawnPoints[position][0], PyrewoodSpawnPoints[position][1], PyrewoodSpawnPoints[position][2], PyrewoodSpawnPoints[position][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000))
{
Unit* target = nullptr;
if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID))
if (player->IsAlive() && RAND(0, 1))
target = player;
if (!target)
target = me;
summoned->SetFaction(FACTION_STORMWIND);
summoned->AddThreat(target, 32.0f);
summoned->AI()->AttackStart(target);
}
};
}
void JustDied(Unit* /*killer*/) override
{
if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID))
if (player->GetQuestStatus(QUEST_PYREWOOD_AMBUSH) == QUEST_STATUS_INCOMPLETE)
player->FailQuest(QUEST_PYREWOOD_AMBUSH);
}
void UpdateAI(uint32 diff) override
{
if (_questInProgress && !_summons.IsAnyCreatureAlive())
scheduler.Update(diff);
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
ObjectGuid _playerGUID;
SummonList _summons;
bool _questInProgress;
};
/**
@@ -485,6 +438,6 @@ public:
void AddSC_silverpine_forest()
{
new npc_deathstalker_erland();
new pyrewood_ambush();
RegisterCreatureAI(npc_deathstalker_fearleia);
new npc_ravenclaw_apparition();
}
@@ -57,7 +57,6 @@ public:
}
bool CLEANED;
TeamId TeamIdInInstance;
uint32 InstanceProgress;
uint32 m_auiEncounter[MAX_ENCOUNTER];
std::string str_data;
@@ -83,7 +82,6 @@ public:
void Initialize() override
{
TeamIdInInstance = TEAM_NEUTRAL;
InstanceProgress = 0;
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
@@ -109,67 +107,49 @@ public:
void OnCreatureCreate(Creature* creature) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* pPlayer = players.begin()->GetSource())
{
if (Group* group = pPlayer->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = pPlayer->GetTeamId();
}
else
TeamIdInInstance = pPlayer->GetTeamId();
}
}
switch (creature->GetEntry())
{
// Grand Champions:
case NPC_MOKRA:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_JACOB);
break;
case NPC_ERESSEA:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_AMBROSE);
break;
case NPC_RUNOK:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_COLOSOS);
break;
case NPC_ZULTORE:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_JAELYNE);
break;
case NPC_VISCERI:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_LANA);
break;
// Grand Champion Minions:
case NPC_ORGRIMMAR_MINION:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_STORMWIND_MINION);
break;
case NPC_SILVERMOON_MINION:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_GNOMEREGAN_MINION);
break;
case NPC_THUNDER_BLUFF_MINION:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_EXODAR_MINION);
break;
case NPC_SENJIN_MINION:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_DARNASSUS_MINION);
break;
case NPC_UNDERCITY_MINION:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_IRONFORGE_MINION);
break;
@@ -183,7 +163,7 @@ public:
case NPC_JAEREN:
case NPC_ARELAS:
NPC_AnnouncerGUID = creature->GetGUID();
//if (TeamIdInInstance == TEAM_ALLIANCE)
//if (GetTeamIdInInstance() == TEAM_ALLIANCE)
// creature->UpdateEntry(NPC_ARELAS);
creature->SetReactState(REACT_PASSIVE);
break;
@@ -283,36 +263,14 @@ public:
void OnPlayerEnter(Player* player) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFaction((TeamIdInInstance == TEAM_HORDE) ? 1610 : 1);
InstanceScript::OnPlayerEnter(player);
if (DoNeedCleanup(player))
{
InstanceCleanup();
}
events.RescheduleEvent(EVENT_CHECK_PLAYERS, CLEANUP_CHECK_INTERVAL);
}
void OnPlayerLeave(Player* player) override
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFactionForRace(player->getRace());
}
bool DoNeedCleanup(Player* ignoredPlayer = nullptr)
{
uint8 aliveCount = 0;
@@ -497,7 +455,7 @@ public:
case DATA_INSTANCE_PROGRESS:
return InstanceProgress;
case DATA_TEAMID_IN_INSTANCE:
return TeamIdInInstance;
return GetTeamIdInInstance();
}
return 0;
@@ -41,7 +41,6 @@ public:
uint32 EncounterStatus;
uint32 InstanceProgress;
uint32 AttemptsLeft;
TeamId TeamIdInInstance;
uint8 Counter;
uint8 northrendBeastsMask;
uint32 AchievementTimer;
@@ -168,7 +167,6 @@ public:
EncounterStatus = NOT_STARTED;
InstanceProgress = INSTANCE_PROGRESS_INITIAL;
AttemptsLeft = 50;
TeamIdInInstance = TEAM_NEUTRAL;
Counter = 0;
northrendBeastsMask = 0;
AchievementTimer = 0;
@@ -475,7 +473,7 @@ public:
case TYPE_FACTION_CHAMPIONS_PLAYER_DIED:
if (urand(0, 2) == 0 )
{
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
{
if (Creature* pTemp = instance->GetCreature(NPC_VarianGUID))
pTemp->AI()->Talk(SAY_VARIAN_KILL_HORDE_PLAYER_1);
@@ -971,16 +969,7 @@ public:
}
case EVENT_SCENE_202:
{
Map::PlayerList const& pl = instance->GetPlayers();
for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
if (Player* plr = itr->GetSource())
if (!plr->IsGameMaster())
{
TeamIdInInstance = plr->GetTeamId();
break;
}
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
{
if (Creature* c = instance->GetCreature(NPC_GarroshGUID))
c->AI()->Talk(SAY_STAGE_2_02h);
@@ -1004,7 +993,7 @@ public:
}
case EVENT_SCENE_204:
{
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
{
if (Creature* c = instance->GetCreature(NPC_GarroshGUID))
c->AI()->Talk(SAY_STAGE_2_04h);
@@ -1022,26 +1011,26 @@ public:
}
case EVENT_SCENE_205:
{
if (Creature* c = instance->GetCreature(TeamIdInInstance == TEAM_ALLIANCE ? NPC_VarianGUID : NPC_GarroshGUID))
c->AI()->Talk(TeamIdInInstance == TEAM_ALLIANCE ? SAY_STAGE_2_05a : SAY_STAGE_2_05h);
if (Creature* c = instance->GetCreature(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_VarianGUID : NPC_GarroshGUID))
c->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_STAGE_2_05a : SAY_STAGE_2_05h);
break;
}
case EVENT_SUMMON_CHAMPIONS:
{
std::vector<uint32> vHealerEntries;
vHealerEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_DRUID_RESTORATION : NPC_ALLIANCE_DRUID_RESTORATION);
vHealerEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_PALADIN_HOLY : NPC_ALLIANCE_PALADIN_HOLY);
vHealerEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_PRIEST_DISCIPLINE : NPC_ALLIANCE_PRIEST_DISCIPLINE);
vHealerEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_SHAMAN_RESTORATION : NPC_ALLIANCE_SHAMAN_RESTORATION);
vHealerEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_DRUID_RESTORATION : NPC_ALLIANCE_DRUID_RESTORATION);
vHealerEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_PALADIN_HOLY : NPC_ALLIANCE_PALADIN_HOLY);
vHealerEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_PRIEST_DISCIPLINE : NPC_ALLIANCE_PRIEST_DISCIPLINE);
vHealerEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_SHAMAN_RESTORATION : NPC_ALLIANCE_SHAMAN_RESTORATION);
std::vector<uint32> vOtherEntries;
vOtherEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_DEATH_KNIGHT : NPC_ALLIANCE_DEATH_KNIGHT);
vOtherEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_HUNTER : NPC_ALLIANCE_HUNTER);
vOtherEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_MAGE : NPC_ALLIANCE_MAGE);
vOtherEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_ROGUE : NPC_ALLIANCE_ROGUE);
vOtherEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_WARLOCK : NPC_ALLIANCE_WARLOCK);
vOtherEntries.push_back(TeamIdInInstance == TEAM_ALLIANCE ? NPC_HORDE_WARRIOR : NPC_ALLIANCE_WARRIOR);
vOtherEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_DEATH_KNIGHT : NPC_ALLIANCE_DEATH_KNIGHT);
vOtherEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_HUNTER : NPC_ALLIANCE_HUNTER);
vOtherEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_MAGE : NPC_ALLIANCE_MAGE);
vOtherEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_ROGUE : NPC_ALLIANCE_ROGUE);
vOtherEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_WARLOCK : NPC_ALLIANCE_WARLOCK);
vOtherEntries.push_back(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_HORDE_WARRIOR : NPC_ALLIANCE_WARRIOR);
uint8 healersSubtracted = 2;
if (instance->GetSpawnMode() == RAID_DIFFICULTY_25MAN_NORMAL || instance->GetSpawnMode() == RAID_DIFFICULTY_25MAN_HEROIC )
@@ -1089,11 +1078,11 @@ public:
uint8 pos2 = 10;
for( std::vector<uint32>::iterator itr = vOtherEntries.begin(); itr != vOtherEntries.end(); ++itr )
{
if (Creature* pTemp = instance->SummonCreature(*itr, FactionChampionLoc[urand(0, 4) + (TeamIdInInstance == TEAM_ALLIANCE ? 0 : 5)]))
if (Creature* pTemp = instance->SummonCreature(*itr, FactionChampionLoc[urand(0, 4) + (GetTeamIdInInstance() == TEAM_ALLIANCE ? 0 : 5)]))
{
NPC_ChampionGUIDs.push_back(pTemp->GetGUID());
pTemp->SetHomePosition((TeamIdInInstance == TEAM_ALLIANCE ? FactionChampionLoc[pos2].GetPositionX() : (Locs[LOC_CENTER].GetPositionX() * 2 - FactionChampionLoc[pos2].GetPositionX())), FactionChampionLoc[pos2].GetPositionY(), FactionChampionLoc[pos2].GetPositionZ(), 0.0f);
pTemp->GetMotionMaster()->MoveJump((TeamIdInInstance == TEAM_ALLIANCE ? FactionChampionLoc[pos2].GetPositionX() : (Locs[LOC_CENTER].GetPositionX() * 2 - FactionChampionLoc[pos2].GetPositionX())), FactionChampionLoc[pos2].GetPositionY(), FactionChampionLoc[pos2].GetPositionZ(), 20.0f, 20.0f);
pTemp->SetHomePosition((GetTeamIdInInstance() == TEAM_ALLIANCE ? FactionChampionLoc[pos2].GetPositionX() : (Locs[LOC_CENTER].GetPositionX() * 2 - FactionChampionLoc[pos2].GetPositionX())), FactionChampionLoc[pos2].GetPositionY(), FactionChampionLoc[pos2].GetPositionZ(), 0.0f);
pTemp->GetMotionMaster()->MoveJump((GetTeamIdInInstance() == TEAM_ALLIANCE ? FactionChampionLoc[pos2].GetPositionX() : (Locs[LOC_CENTER].GetPositionX() * 2 - FactionChampionLoc[pos2].GetPositionX())), FactionChampionLoc[pos2].GetPositionY(), FactionChampionLoc[pos2].GetPositionZ(), 20.0f, 20.0f);
}
++pos2;
}
@@ -1196,35 +1185,8 @@ public:
}
case EVENT_SCENE_VALKYR_DEAD:
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& pl = instance->GetPlayers();
for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
if (Player* plr = itr->GetSource())
if (!plr->IsGameMaster())
{
if (Group* group = plr->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
{
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
break;
}
else
{
TeamIdInInstance = plr->GetTeamId();
break;
}
}
else
{
TeamIdInInstance = plr->GetTeamId();
break;
}
}
}
if (Creature* c = instance->GetCreature(TeamIdInInstance == TEAM_ALLIANCE ? NPC_VarianGUID : NPC_GarroshGUID))
c->AI()->Talk((TeamIdInInstance == TEAM_ALLIANCE ? SAY_STAGE_3_03a : SAY_STAGE_3_03h));
if (Creature* c = instance->GetCreature(GetTeamIdInInstance() == TEAM_ALLIANCE ? NPC_VarianGUID : NPC_GarroshGUID))
c->AI()->Talk((GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_STAGE_3_03a : SAY_STAGE_3_03h));
events.RescheduleEvent(EVENT_SCENE_401, 60000);
break;
@@ -1413,21 +1375,7 @@ public:
void OnPlayerEnter(Player* plr) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
if (Group* group = plr->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = plr->GetTeamId();
}
else
TeamIdInInstance = plr->GetTeamId();
}
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
plr->SetFaction((TeamIdInInstance == TEAM_HORDE) ? 1610 : 1);
InstanceScript::OnPlayerEnter(plr);
if (instance->IsHeroic())
{
@@ -1448,12 +1396,6 @@ public:
events.RescheduleEvent(EVENT_CHECK_PLAYERS, 5s);
}
void OnPlayerLeave(Player* player) override
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFactionForRace(player->getRace());
}
bool DoNeedCleanup(Player* ignoredPlayer = nullptr)
{
uint8 aliveCount = 0;
@@ -96,12 +96,6 @@ public:
}
}
void OnPlayerLeave(Player* player) override
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFactionForRace(player->getRace());
}
void OnCreatureCreate(Creature* creature) override
{
if (teamIdInInstance == TEAM_NEUTRAL)
@@ -144,7 +144,6 @@ public:
};
uint32 EncounterMask;
TeamId TeamIdInInstance;
ObjectGuid NPC_FalricGUID;
ObjectGuid NPC_MarwynGUID;
ObjectGuid NPC_LichKingIntroGUID;
@@ -190,7 +189,6 @@ public:
void Initialize() override
{
EncounterMask = 0;
TeamIdInInstance = TEAM_NEUTRAL;
memset(&TrashActive, 0, sizeof(TrashActive));
TrashCounter = 0;
memset(&chosenComposition, 0, sizeof(chosenComposition));
@@ -214,69 +212,15 @@ public:
return (instance->HavePlayers() && WaveNumber) || IsDuringLKFight; // during LK fight npcs are active and will unset this variable
}
void OnPlayerEnter(Player* player) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFaction((TeamIdInInstance == TEAM_HORDE) ? 1610 : 1);
}
void OnPlayerLeave(Player* player) override
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFactionForRace(player->getRace());
}
void OnCreatureCreate(Creature* creature) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* p = itr->GetSource())
if (!p->IsGameMaster())
{
if (Group* group = p->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
{
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
break;
}
else
{
TeamIdInInstance = p->GetTeamId();
break;
}
}
else
{
TeamIdInInstance = p->GetTeamId();
break;
}
}
}
switch (creature->GetEntry())
{
case NPC_SYLVANAS_PART1:
creature->SetVisible(false);
creature->SetSpeed(MOVE_RUN, 1.1);
NPC_LeaderIntroGUID = creature->GetGUID();
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JAINA_PART1);
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
@@ -284,7 +228,7 @@ public:
case NPC_DARK_RANGER_LORALEN:
creature->SetVisible(false);
NPC_GuardGUID = creature->GetGUID();
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ARCHMAGE_KORELN);
break;
case NPC_UTHER:
@@ -345,7 +289,7 @@ public:
creature->CastSpell(creature, SPELL_SOUL_REAPER, true);
}
else if (!(EncounterMask & (1 << DATA_LICH_KING)))
creature->AddAura(TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, creature);
creature->AddAura(GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, creature);
else
creature->SetVisible(false);
@@ -359,7 +303,7 @@ public:
NPC_LeaderGUID = creature->GetGUID();
creature->SetWalk(false);
creature->SetSheath(SHEATH_STATE_MELEE);
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JAINA_PART2);
creature->SetWalk(false);
creature->SetHealth(creature->GetMaxHealth() / 20);
@@ -368,9 +312,9 @@ public:
if (!(EncounterMask & (1 << DATA_LK_INTRO)))
{
creature->SetSheath(SHEATH_STATE_MELEE);
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, TeamIdInInstance == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H); //the fight cannot be in the form of an emote, it is causing bugs.
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, GetTeamIdInInstance() == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H); //the fight cannot be in the form of an emote, it is causing bugs.
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
creature->CastSpell(creature, TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_BARRIER : SPELL_SYLVANAS_CLOAK_OF_DARKNESS, true);
creature->CastSpell(creature, GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_BARRIER : SPELL_SYLVANAS_CLOAK_OF_DARKNESS, true);
}
else if (!(EncounterMask & (1 << DATA_LICH_KING)))
{
@@ -577,7 +521,7 @@ public:
if (!c->IsAlive())
{
c->Respawn();
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
c->UpdateEntry(NPC_JAINA_PART2);
}
c->GetThreatMgr().ClearAllThreat();
@@ -605,7 +549,7 @@ public:
c->UpdatePosition(c->GetHomePosition(), true);
c->StopMovingOnCurrentPos();
c->RemoveAllAuras();
c->AddAura(TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, c);
c->AddAura(GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, c);
c->AI()->Reset();
c->setActive(false);
c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
@@ -1126,18 +1070,18 @@ public:
break;
case 2:
{
uint32 entry = TeamIdInInstance == TEAM_ALLIANCE ? GO_THE_SKYBREAKER : GO_ORGRIMS_HAMMER;
uint32 entry = GetTeamIdInInstance() == TEAM_ALLIANCE ? GO_THE_SKYBREAKER : GO_ORGRIMS_HAMMER;
T1 = sTransportMgr->CreateTransport(entry, 0, instance);
++outroStep;
outroTimer = TeamIdInInstance == TEAM_ALLIANCE ? 10000 : 10500;
outroTimer = GetTeamIdInInstance() == TEAM_ALLIANCE ? 10000 : 10500;
}
break;
case 3:
if (T1)
T1->EnableMovement(false);
if (Creature* c = instance->GetCreature(NPC_ShipCaptainGUID))
c->AI()->Talk(TeamIdInInstance == TEAM_ALLIANCE ? SAY_FIRE_ALLY : SAY_FIRE_HORDE);
c->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_FIRE_ALLY : SAY_FIRE_HORDE);
if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
{
c->RemoveAllAuras();
@@ -1185,10 +1129,10 @@ public:
T1->EnableMovement(false);
if (Creature* leader = instance->GetCreature(NPC_LeaderGUID))
{
uint8 index = TeamIdInInstance == TEAM_ALLIANCE ? 0 : 1;
uint8 index = GetTeamIdInInstance() == TEAM_ALLIANCE ? 0 : 1;
for (uint8 i = 0; i < 3; ++i)
if (StairsPos[index][i].GetPositionX())
if (GameObject* go = leader->SummonGameObject(TeamIdInInstance == TEAM_ALLIANCE ? GO_STAIRS_ALLIANCE : GO_STAIRS_HORDE, StairsPos[index][i].GetPositionX(), StairsPos[index][i].GetPositionY(), StairsPos[index][i].GetPositionZ(), StairsPos[index][i].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400, false))
if (GameObject* go = leader->SummonGameObject(GetTeamIdInInstance() == TEAM_ALLIANCE ? GO_STAIRS_ALLIANCE : GO_STAIRS_HORDE, StairsPos[index][i].GetPositionX(), StairsPos[index][i].GetPositionY(), StairsPos[index][i].GetPositionZ(), StairsPos[index][i].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400, false))
go->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
//Position pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyPortalPos : HordePortalPos;
//leader->SummonGameObject(GO_PORTAL_TO_DALARAN, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400);
@@ -1200,7 +1144,7 @@ public:
break;
case 8:
if (Creature* c = instance->GetCreature(NPC_ShipCaptainGUID))
c->AI()->Talk(TeamIdInInstance == TEAM_ALLIANCE ? SAY_ONBOARD_ALLY : SAY_ONBOARD_HORDE);
c->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_ONBOARD_ALLY : SAY_ONBOARD_HORDE);
if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
{
c->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
@@ -1212,7 +1156,7 @@ public:
break;
case 9:
if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
c->AI()->Talk(TeamIdInInstance == TEAM_ALLIANCE ? SAY_JAINA_FINAL_1 : SAY_SYLVANA_FINAL);
c->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_JAINA_FINAL_1 : SAY_SYLVANA_FINAL);
HandleGameObject(GO_CaveInGUID, true);
++outroStep;
outroTimer = 11000;
@@ -1223,7 +1167,7 @@ public:
for (Map::PlayerList::const_iterator itr = instance->GetPlayers().begin(); itr != instance->GetPlayers().end(); ++itr)
if (Player* p = itr->GetSource())
p->KilledMonsterCredit(NPC_WRATH_OF_THE_LICH_KING_CREDIT);
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
{
c->AI()->Talk(SAY_JAINA_FINAL_2);
@@ -35,7 +35,6 @@ public:
}
uint32 m_auiEncounter[MAX_ENCOUNTER];
TeamId teamIdInInstance;
uint32 InstanceProgress;
std::string str_data;
@@ -61,7 +60,6 @@ public:
void Initialize() override
{
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
teamIdInInstance = TEAM_NEUTRAL;
InstanceProgress = INSTANCE_PROGRESS_NONE;
bAchievEleven = true;
@@ -78,62 +76,24 @@ public:
void OnPlayerEnter(Player* player) override
{
if (teamIdInInstance == TEAM_NEUTRAL)
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
teamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
teamIdInInstance = player->GetTeamId();
}
else
teamIdInInstance = player->GetTeamId();
}
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFaction((teamIdInInstance == TEAM_HORDE) ? 1610 : 1);
InstanceScript::OnPlayerEnter(player);
instance->LoadGrid(LeaderIntroPos.GetPositionX(), LeaderIntroPos.GetPositionY());
if (Creature* c = instance->GetCreature(GetGuidData(DATA_LEADER_FIRST_GUID)))
c->AI()->SetData(DATA_START_INTRO, 0);
}
void OnPlayerLeave(Player* player) override
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFactionForRace(player->getRace());
}
uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override
{
if (teamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* player = players.begin()->GetSource())
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
teamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
teamIdInInstance = player->GetTeamId();
}
else
teamIdInInstance = player->GetTeamId();
}
}
uint32 entry = data->id1;
switch (entry)
{
case NPC_RESCUED_ALLIANCE_SLAVE:
if (teamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
return 0;
break;
case NPC_RESCUED_HORDE_SLAVE:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
return 0;
break;
}
@@ -143,28 +103,10 @@ public:
void OnCreatureCreate(Creature* creature) override
{
if (teamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* player = players.begin()->GetSource())
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
teamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
teamIdInInstance = player->GetTeamId();
}
else
teamIdInInstance = player->GetTeamId();
}
}
switch (creature->GetEntry())
{
case NPC_SYLVANAS_PART1:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JAINA_PART1);
NPC_LeaderFirstGUID = creature->GetGUID();
@@ -183,7 +125,7 @@ public:
}
break;
case NPC_SYLVANAS_PART2:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JAINA_PART2);
NPC_LeaderSecondGUID = creature->GetGUID();
break;
@@ -213,50 +155,50 @@ public:
}
break;
case NPC_LORALEN:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ELANDRA);
if (!NPC_GuardFirstGUID)
NPC_GuardFirstGUID = creature->GetGUID();
break;
case NPC_KALIRA:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_KORELN);
if (!NPC_GuardSecondGUID)
NPC_GuardSecondGUID = creature->GetGUID();
break;
case NPC_HORDE_SLAVE_1:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ALLIANCE_SLAVE_1);
break;
case NPC_HORDE_SLAVE_2:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ALLIANCE_SLAVE_2);
break;
case NPC_HORDE_SLAVE_3:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ALLIANCE_SLAVE_3);
break;
case NPC_HORDE_SLAVE_4:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ALLIANCE_SLAVE_4);
break;
case NPC_GORKUN_IRONSKULL_1:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_MARTIN_VICTUS_1);
break;
case NPC_GARFROST:
NPC_GarfrostGUID = creature->GetGUID();
break;
case NPC_FREED_SLAVE_1_HORDE:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_FREED_SLAVE_1_ALLIANCE);
break;
case NPC_FREED_SLAVE_2_HORDE:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_FREED_SLAVE_2_ALLIANCE);
break;
case NPC_FREED_SLAVE_3_HORDE:
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_FREED_SLAVE_3_ALLIANCE);
break;
case NPC_GORKUN_IRONSKULL_2:
@@ -266,7 +208,7 @@ public:
c->AI()->DoAction(1); // despawn summons
c->DespawnOrUnsummon();
}
if (teamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_MARTIN_VICTUS_2);
NPC_MartinOrGorkunGUID = creature->GetGUID();
break;
@@ -370,7 +312,7 @@ public:
case DATA_INSTANCE_PROGRESS:
return InstanceProgress;
case DATA_TEAMID_IN_INSTANCE:
return teamIdInInstance;
return GetTeamIdInInstance();
case DATA_GARFROST:
return m_auiEncounter[0];
case DATA_ICK:
@@ -218,7 +218,6 @@ public:
LoadBossBoundaries(boundaries);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
TeamIdInInstance = TEAM_NEUTRAL;
HeroicAttempts = MaxHeroicAttempts;
IsBonedEligible = true;
IsOozeDanceEligible = true;
@@ -261,22 +260,7 @@ public:
void OnPlayerEnter(Player* player) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFaction((TeamIdInInstance == TEAM_HORDE) ? 1610 : 1);
InstanceScript::OnPlayerEnter(player);
// for professor putricide hc
DoRemoveAurasDueToSpellOnPlayers(SPELL_GAS_VARIABLE);
DoRemoveAurasDueToSpellOnPlayers(SPELL_OOZE_VARIABLE);
@@ -306,32 +290,8 @@ public:
}
}
void OnPlayerLeave(Player* player) override
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFactionForRace(player->getRace());
}
void OnCreatureCreate(Creature* creature) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* player = players.begin()->GetSource())
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
}
// apply ICC buff to pets/summons
if (GetData(DATA_BUFF_AVAILABLE) && creature->GetOwnerGUID().IsPlayer() && creature->HasUnitTypeMask(UNIT_MASK_MINION | UNIT_MASK_GUARDIAN | UNIT_MASK_CONTROLABLE_GUARDIAN) && creature->CanHaveThreatList())
if (Unit* owner = creature->GetOwner())
@@ -377,39 +337,39 @@ public:
switch (creature->GetEntry())
{
case NPC_KOR_KRON_GENERAL:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ALLIANCE_COMMANDER);
break;
case NPC_KOR_KRON_LIEUTENANT:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_SKYBREAKER_LIEUTENANT);
break;
case NPC_TORTUNOK:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ALANA_MOONSTRIKE);
break;
case NPC_GERARDO_THE_SUAVE:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_TALAN_MOONSTRIKE);
break;
case NPC_UVLUS_BANEFIRE:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_MALFUS_GRIMFROST);
break;
case NPC_IKFIRUS_THE_VILE:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_YILI);
break;
case NPC_VOL_GUK:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JEDEBIA);
break;
case NPC_HARAGG_THE_UNSEEN:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_NIBY_THE_ALMIGHTY);
break;
case NPC_GARROSH_HELLSCREAM:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_KING_VARIAN_WRYNN);
// Xinef: summon in case of instance unload
@@ -428,7 +388,7 @@ public:
DeathbringerSaurfangGUID = creature->GetGUID();
break;
case NPC_SE_HIGH_OVERLORD_SAURFANG:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
{
creature->UpdateEntry(NPC_SE_MURADIN_BRONZEBEARD, true);
creature->LoadEquipment();
@@ -440,14 +400,14 @@ public:
DeathbringerSaurfangEventGUID = creature->GetGUID();
break;
case NPC_HIGH_OVERLORD_SAURFANG_DUMMY:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
{
creature->UpdateEntry(NPC_MURADIN_BRONZEBEARD_DUMMY, creature->GetCreatureData());
creature->LoadEquipment();
}
break;
case NPC_SE_KOR_KRON_REAVER:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_SE_SKYBREAKER_MARINE);
break;
case NPC_FESTERGUT:
@@ -579,52 +539,34 @@ public:
uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* player = players.begin()->GetSource())
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
}
uint32 entry = data->id1;
switch (entry)
{
case NPC_HORDE_GUNSHIP_CANNON:
case NPC_ORGRIMS_HAMMER_CREW:
case NPC_SKY_REAVER_KORM_BLACKSCAR:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
return 0;
break;
case NPC_ALLIANCE_GUNSHIP_CANNON:
case NPC_SKYBREAKER_DECKHAND:
case NPC_HIGH_CAPTAIN_JUSTIN_BARTLETT:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
return 0;
break;
case NPC_ZAFOD_BOOMBOX:
if (GameObjectTemplate const* go = sObjectMgr->GetGameObjectTemplate(GO_THE_SKYBREAKER_A))
if ((TeamIdInInstance == TEAM_ALLIANCE && data->mapid == go->moTransport.mapID) ||
(TeamIdInInstance == TEAM_HORDE && data->mapid != go->moTransport.mapID))
if ((GetTeamIdInInstance() == TEAM_ALLIANCE && data->mapid == go->moTransport.mapID) ||
(GetTeamIdInInstance() == TEAM_HORDE && data->mapid != go->moTransport.mapID))
return entry;
return 0;
case NPC_IGB_MURADIN_BRONZEBEARD:
if ((TeamIdInInstance == TEAM_ALLIANCE && data->posX > 10.0f) ||
(TeamIdInInstance == TEAM_HORDE && data->posX < 10.0f))
if ((GetTeamIdInInstance() == TEAM_ALLIANCE && data->posX > 10.0f) ||
(GetTeamIdInInstance() == TEAM_HORDE && data->posX < 10.0f))
return entry;
return 0;
case NPC_SPIRE_FROSTWYRM:
if ((TeamIdInInstance == TEAM_ALLIANCE && data->posY < 2200.0f) || (TeamIdInInstance == TEAM_HORDE && data->posY > 2200.0f))
if ((GetTeamIdInInstance() == TEAM_ALLIANCE && data->posY < 2200.0f) || (GetTeamIdInInstance() == TEAM_HORDE && data->posY > 2200.0f))
return 0;
break;
}
@@ -634,38 +576,20 @@ public:
uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* player = players.begin()->GetSource())
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
}
switch (entry)
{
case GO_GUNSHIP_ARMORY_H_10N:
case GO_GUNSHIP_ARMORY_H_25N:
case GO_GUNSHIP_ARMORY_H_10H:
case GO_GUNSHIP_ARMORY_H_25H:
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
return 0;
break;
case GO_GUNSHIP_ARMORY_A_10N:
case GO_GUNSHIP_ARMORY_A_25N:
case GO_GUNSHIP_ARMORY_A_10H:
case GO_GUNSHIP_ARMORY_A_25H:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
return 0;
break;
}
@@ -748,24 +672,6 @@ public:
void OnGameObjectCreate(GameObject* go) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* player = players.begin()->GetSource())
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
}
switch (go->GetEntry())
{
case GO_SPIRIT_ALARM_1:
@@ -1021,7 +927,7 @@ public:
case DATA_COLDFLAME_JETS:
return ColdflameJetsState;
case DATA_TEAMID_IN_INSTANCE:
return TeamIdInInstance;
return GetTeamIdInInstance();
case DATA_BLOOD_QUICKENING_STATE:
return BloodQuickeningState;
case DATA_HEROIC_ATTEMPTS:
@@ -1315,7 +1221,7 @@ public:
if (!GunshipGUID && instance->HavePlayers())
{
SetBossState(DATA_ICECROWN_GUNSHIP_BATTLE, NOT_STARTED);
uint32 gunshipEntry = TeamIdInInstance == TEAM_HORDE ? GO_ORGRIMS_HAMMER_H : GO_THE_SKYBREAKER_A;
uint32 gunshipEntry = GetTeamIdInInstance() == TEAM_HORDE ? GO_ORGRIMS_HAMMER_H : GO_THE_SKYBREAKER_A;
if (MotionTransport* gunship = sTransportMgr->CreateTransport(gunshipEntry, 0, instance))
{
GunshipGUID = gunship->GetGUID();
@@ -1880,7 +1786,7 @@ public:
}
break;
case EVENT_ENEMY_GUNSHIP_COMBAT:
if (Creature* captain = source->FindNearestCreature(TeamIdInInstance == TEAM_HORDE ? NPC_IGB_HIGH_OVERLORD_SAURFANG : NPC_IGB_MURADIN_BRONZEBEARD, 200.0f))
if (Creature* captain = source->FindNearestCreature(GetTeamIdInInstance() == TEAM_HORDE ? NPC_IGB_HIGH_OVERLORD_SAURFANG : NPC_IGB_MURADIN_BRONZEBEARD, 200.0f))
{
captain->AI()->DoAction(ACTION_ENEMY_GUNSHIP_TALK);
}
@@ -1900,7 +1806,7 @@ public:
//After movement is stopped remove the backpack
RemoveBackPack();
}
if (Creature* captain = source->FindNearestCreature(TeamIdInInstance == TEAM_HORDE ? NPC_IGB_HIGH_OVERLORD_SAURFANG : NPC_IGB_MURADIN_BRONZEBEARD, 200.0f))
if (Creature* captain = source->FindNearestCreature(GetTeamIdInInstance() == TEAM_HORDE ? NPC_IGB_HIGH_OVERLORD_SAURFANG : NPC_IGB_MURADIN_BRONZEBEARD, 200.0f))
captain->AI()->DoAction(ACTION_EXIT_SHIP);
break;
@@ -2066,7 +1972,6 @@ public:
ObjectGuid FrozenBolvarGUID;
ObjectGuid PillarsChainedGUID;
ObjectGuid PillarsUnchainedGUID;
TeamId TeamIdInInstance;
uint32 ColdflameJetsState;
std::set<ObjectGuid::LowType> FrostwyrmGUIDs;
std::set<ObjectGuid::LowType> SpinestalkerTrash;
@@ -25,6 +25,8 @@
#include "ScriptedCreature.h"
#include "naxxramas.h"
static constexpr uint8 HorsemanCount = 4;
const float HeiganPos[2] = {2796, -3707};
const float HeiganEruptionSlope[3] =
{
@@ -94,13 +96,12 @@ public:
PatchwerkRoomTrash.clear();
// Controls
_horsemanKilled = 0;
_speakTimer = 0;
_horsemanTimer = 0;
_screamTimer = 2 * MINUTE * IN_MILLISECONDS;
_hadThaddiusGreet = false;
_currentWingTaunt = SAY_FIRST_WING_TAUNT;
_horsemanLoadDoneState = false;
_horsemanLoaded = 0;
// Achievements
abominationsKilled = 0;
@@ -167,14 +168,13 @@ public:
ObjectGuid _lichkingGUID;
// Controls
uint8 _horsemanKilled;
uint32 _speakTimer;
uint32 _horsemanTimer;
uint32 _screamTimer;
bool _hadThaddiusGreet;
EventMap events;
uint8 _currentWingTaunt;
bool _horsemanLoadDoneState;
uint8 _horsemanLoaded;
// Achievements
uint8 abominationsKilled;
@@ -251,15 +251,19 @@ public:
return;
case NPC_LADY_BLAUMEUX:
_blaumeuxGUID = creature->GetGUID();
++_horsemanLoaded;
return;
case NPC_SIR_ZELIEK:
_zeliekGUID = creature->GetGUID();
++_horsemanLoaded;
return;
case NPC_BARON_RIVENDARE:
_rivendareGUID = creature->GetGUID();
++_horsemanLoaded;
return;
case NPC_THANE_KORTHAZZ:
_korthazzGUID = creature->GetGUID();
++_horsemanLoaded;
return;
case NPC_SAPPHIRON:
_sapphironGUID = creature->GetGUID();
@@ -272,6 +276,9 @@ public:
return;
}
if (_horsemanLoaded == HorsemanCount)
SetBossState(BOSS_HORSEMAN, GetBossState(BOSS_HORSEMAN));
InstanceScript::OnCreatureCreate(creature);
}
@@ -681,13 +688,25 @@ public:
}
// Horseman handling
if (bossId == BOSS_HORSEMAN && !_horsemanLoadDoneState)
if (bossId == BOSS_HORSEMAN && _horsemanLoaded == HorsemanCount)
{
uint8 horsemanKilled {};
if (Creature* cr = instance->GetCreature(_blaumeuxGUID))
horsemanKilled += !cr->IsAlive();
if (Creature* cr = instance->GetCreature(_rivendareGUID))
horsemanKilled += !cr->IsAlive();
if (Creature* cr = instance->GetCreature(_zeliekGUID))
horsemanKilled += !cr->IsAlive();
if (Creature* cr = instance->GetCreature(_korthazzGUID))
horsemanKilled += !cr->IsAlive();
if (state == DONE)
{
_horsemanTimer++;
_horsemanKilled++;
if (_horsemanKilled < 4)
if (horsemanKilled < HorsemanCount)
{
return false;
}
@@ -699,10 +718,9 @@ public:
}
// respawn
else if (state == NOT_STARTED && _horsemanKilled > 0)
else if (state == NOT_STARTED && horsemanKilled > 0)
{
Creature* cr;
_horsemanKilled = 0;
if ((cr = instance->GetCreature(_blaumeuxGUID)))
{
if (!cr->IsAlive())
@@ -49,85 +49,40 @@ public:
SetHeaders(DataHeader);
SetBossNumber(MAX_ENCOUNTERS);
LoadDoorData(doorData);
TeamIdInInstance = TEAM_NEUTRAL;
}
void OnCreatureCreate(Creature* creature) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* pPlayer = players.begin()->GetSource())
{
if (Group* group = pPlayer->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = pPlayer->GetTeamId();
}
else
TeamIdInInstance = pPlayer->GetTeamId();
}
}
switch (creature->GetEntry())
{
case NPC_ALLIANCE_RANGER:
creature->SetFaction(FACTION_MONSTER_2);
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_HORDE_RANGER);
break;
case NPC_ALLIANCE_BERSERKER:
creature->SetFaction(FACTION_MONSTER_2);
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_HORDE_BERSERKER);
break;
case NPC_ALLIANCE_COMMANDER:
creature->SetFaction(FACTION_MONSTER_2);
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_HORDE_COMMANDER);
break;
case NPC_ALLIANCE_CLERIC:
creature->SetFaction(FACTION_MONSTER_2);
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_HORDE_CLERIC);
break;
case NPC_COMMANDER_STOUTBEARD:
creature->SetFaction(FACTION_MONSTER_2);
if (TeamIdInInstance == TEAM_ALLIANCE)
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_COMMANDER_KOLURG);
break;
}
}
void OnPlayerEnter(Player* player) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFaction((TeamIdInInstance == TEAM_HORDE) ? 1610 : 1);
}
void OnPlayerLeave(Player* player) override
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFactionForRace(player->getRace());
}
void OnGameObjectCreate(GameObject* gameObject) override
{
switch (gameObject->GetEntry())
@@ -194,8 +149,6 @@ public:
(*i)->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
return true;
}
protected:
TeamId TeamIdInInstance;
};
};
@@ -33,12 +33,8 @@ enum bloodFurnace
DATA_KELIDAN = 2,
MAX_ENCOUNTER = 3,
DATA_DOOR1 = 10,
DATA_DOOR2 = 11,
DATA_DOOR3 = 12,
DATA_BROGGOK_REAR_DOOR = 13,
DATA_BROGGOK_LEVER = 14,
DATA_DOOR6 = 15,
DATA_PRISON_CELL1 = 20,
DATA_PRISON_CELL2 = 21,
@@ -62,7 +58,11 @@ enum BloodFurnaceGO
{
GO_BROGGOK_DOOR_FRONT = 181822,
GO_BROGGOK_DOOR_REAR = 181819,
GO_BROGGOK_LEVER = 181982
GO_BROGGOK_LEVER = 181982,
GO_KELIDAN_DOOR_EXIT1 = 181823,
GO_KELIDAN_DOOR_EXIT2 = 181766,
GO_MAKER_DOOR_FRONT = 181811,
GO_MAKER_DOOR_REAR = 181812
};
template <class AI, class T>
@@ -101,15 +101,10 @@ public:
bool OnGossipHello(Player* /*player*/, GameObject* go) override
{
if (InstanceScript* instance = go->GetInstanceScript())
{
if (instance->GetBossState(DATA_BROGGOK) == NOT_STARTED)
{
if (Creature* broggok = instance->GetCreature(DATA_BROGGOK))
{
broggok->AI()->DoAction(ACTION_PREPARE_BROGGOK);
}
}
}
go->UseDoorOrButton();
return false;
}
@@ -67,10 +67,6 @@ struct boss_kelidan_the_breaker : public BossAI
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
DoCastSelf(SPELL_EVOCATION);
if (instance)
{
instance->SetData(DATA_KELIDAN, NOT_STARTED);
}
}
void JustEngagedWith(Unit* /*who*/) override
@@ -78,10 +74,7 @@ struct boss_kelidan_the_breaker : public BossAI
Talk(SAY_WAKE);
_JustEngagedWith();
me->InterruptNonMeleeSpells(false);
if (instance)
{
instance->SetData(DATA_KELIDAN, IN_PROGRESS);
}
scheduler.Schedule(1s, [this](TaskContext context)
{
DoCastAOE(SPELL_SHADOW_BOLT_VOLLEY);
@@ -97,9 +90,7 @@ struct boss_kelidan_the_breaker : public BossAI
me->AddAura(SPELL_BURNING_NOVA, me);
ApplyImmunities(true);
if (IsHeroic())
{
DoCastAOE(SPELL_VORTEX);
}
scheduler.DelayGroup(0, 6s);
scheduler.Schedule(5s, [this](TaskContext /*context*/)
{
@@ -112,41 +103,29 @@ struct boss_kelidan_the_breaker : public BossAI
void KilledUnit(Unit* /*victim*/) override
{
if (urand(0, 1))
{
Talk(SAY_KILL);
}
}
void DoAction(int32 param) override
{
if (param == ACTION_CHANNELER_DIED)
{
if (me->FindNearestCreature(NPC_SHADOWMOON_CHANNELER, 100.0f))
if (!me->FindNearestCreature(NPC_SHADOWMOON_CHANNELER, 100.0f))
{
return;
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_AGGRESSIVE);
me->SetInCombatWithZone();
}
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_AGGRESSIVE);
me->SetInCombatWithZone();
}
else if (param == ACTION_CHANNELER_AGGRO)
{
Talk(SAY_ADD_AGGRO);
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
_JustDied();
if (instance)
{
me->GetMap()->LoadGrid(0, -111.0f);
instance->SetData(DATA_KELIDAN, DONE);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR1), true);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR6), true);
}
me->GetMap()->LoadGrid(0, -111.0f);
}
void ApplyImmunities(bool apply)
@@ -42,22 +42,10 @@ struct boss_the_maker : public BossAI
});
}
void Reset() override
{
_Reset();
if (instance)
{
instance->SetData(DATA_THE_MAKER, NOT_STARTED);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true);
}
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
instance->SetData(DATA_THE_MAKER, IN_PROGRESS);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), false);
scheduler.Schedule(6s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_EXPLODING_BEAKER);
@@ -72,30 +60,13 @@ struct boss_the_maker : public BossAI
void KilledUnit(Unit* victim) override
{
if (victim->IsPlayer() && urand(0, 1))
{
Talk(SAY_KILL);
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DIE);
_JustDied();
instance->SetData(DATA_THE_MAKER, DONE);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true);
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR3), true);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
};
@@ -22,9 +22,13 @@
DoorData const doorData[] =
{
{ GO_BROGGOK_DOOR_FRONT, DATA_BROGGOK, DOOR_TYPE_ROOM },
{ GO_BROGGOK_DOOR_REAR, DATA_BROGGOK, DOOR_TYPE_PASSAGE },
{ 0, 0, DOOR_TYPE_ROOM } // END
{ GO_MAKER_DOOR_FRONT, DATA_THE_MAKER, DOOR_TYPE_ROOM },
{ GO_MAKER_DOOR_REAR, DATA_THE_MAKER, DOOR_TYPE_PASSAGE },
{ GO_BROGGOK_DOOR_FRONT, DATA_BROGGOK, DOOR_TYPE_ROOM },
{ GO_BROGGOK_DOOR_REAR, DATA_BROGGOK, DOOR_TYPE_PASSAGE },
{ GO_KELIDAN_DOOR_EXIT1, DATA_KELIDAN, DOOR_TYPE_PASSAGE },
{ GO_KELIDAN_DOOR_EXIT2, DATA_KELIDAN, DOOR_TYPE_PASSAGE },
{ 0, 0, DOOR_TYPE_ROOM } // END
};
ObjectData const gameobjectData[] =
@@ -56,26 +60,15 @@ public:
LoadObjectData(creatureData, gameobjectData);
}
uint32 _auiEncounter[MAX_ENCOUNTER];
ObjectGuid _doorGUIDs[6];
ObjectGuid _prisonGUIDs[4];
GuidSet _prisonersCell[4];
uint8 _prisonerCounter[4];
void Initialize() override
{
memset(&_auiEncounter, 0, sizeof(_auiEncounter));
memset(&_prisonerCounter, 0, sizeof(_prisonerCounter));
}
void OnCreatureCreate(Creature* creature) override
{
if (creature->GetEntry() == NPC_NASCENT_FEL_ORC)
{
StorePrisoner(creature);
}
InstanceScript::OnCreatureCreate(creature);
}
@@ -88,20 +81,6 @@ public:
void OnGameObjectCreate(GameObject* go) override
{
if (go->GetEntry() == 181766) //Final exit door
_doorGUIDs[0] = go->GetGUID();
if (go->GetEntry() == 181811) //The Maker Front door
_doorGUIDs[1] = go->GetGUID();
if (go->GetEntry() == 181812) //The Maker Rear door
{
_doorGUIDs[2] = go->GetGUID();
if (GetData(DATA_THE_MAKER) == DONE)
HandleGameObject(go->GetGUID(), true);
}
if (go->GetEntry() == 181823) //Kelidan exit door
_doorGUIDs[5] = go->GetGUID();
if (go->GetEntry() == 181821) //Broggok prison cell front right
_prisonGUIDs[0] = go->GetGUID();
if (go->GetEntry() == 181818) //Broggok prison cell back right
@@ -118,12 +97,6 @@ public:
{
switch (data)
{
case DATA_DOOR1:
case DATA_DOOR2:
case DATA_DOOR3:
case DATA_DOOR6:
return _doorGUIDs[data - DATA_DOOR1];
case DATA_PRISON_CELL1:
case DATA_PRISON_CELL2:
case DATA_PRISON_CELL3:
@@ -142,50 +115,17 @@ public:
if (type == DATA_BROGGOK)
{
if (state == IN_PROGRESS)
{
ActivateCell(DATA_PRISON_CELL1);
HandleGameObject(_doorGUIDs[3], false);
}
else if (state == NOT_STARTED)
{
ResetPrisons();
HandleGameObject(_doorGUIDs[4], false);
HandleGameObject(_doorGUIDs[3], true);
if (GameObject* lever = GetGameObject(DATA_BROGGOK_LEVER))
{
lever->Respawn();
}
DoRespawnGameObject(DATA_BROGGOK_LEVER);
}
}
return true;
}
void SetData(uint32 type, uint32 data) override
{
switch (type)
{
case DATA_THE_MAKER:
case DATA_KELIDAN:
_auiEncounter[type] = data;
break;
}
if (data == DONE)
SaveToDB();
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_THE_MAKER:
case DATA_KELIDAN:
return _auiEncounter[type];
}
return 0;
}
void ResetPrisons()
{
for (uint8 i = 0; i < 4; ++i)
@@ -273,13 +213,9 @@ public:
break;
case DATA_BROGGOK_REAR_DOOR:
if (GameObject* go = GetGameObject(DATA_BROGGOK_REAR_DOOR))
{
HandleGameObject(ObjectGuid::Empty, true, go);
}
if (Creature* broggok = GetCreature(DATA_BROGGOK))
{
broggok->AI()->DoAction(ACTION_ACTIVATE_BROGGOK);
}
break;
}
}
@@ -294,6 +230,11 @@ public:
prisoner->SetInCombatWithZone();
}
}
private:
ObjectGuid _prisonGUIDs[4];
GuidSet _prisonersCell[4];
uint8 _prisonerCounter[4];
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
@@ -59,56 +59,11 @@ public:
SetBossNumber(ENCOUNTER_COUNT);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
TeamIdInInstance = TEAM_NEUTRAL;
RescueTimer = 100 * MINUTE * IN_MILLISECONDS;
}
void OnPlayerEnter(Player* player) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFaction((TeamIdInInstance == TEAM_HORDE) ? 1610 : 1);
}
void OnPlayerLeave(Player* player) override
{
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
player->SetFactionForRace(player->getRace());
}
void OnCreatureCreate(Creature* creature) override
{
if (TeamIdInInstance == TEAM_NEUTRAL)
{
Map::PlayerList const& players = instance->GetPlayers();
if (!players.IsEmpty())
if (Player* player = players.begin()->GetSource())
{
if (Group* group = player->GetGroup())
{
if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
TeamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
else
TeamIdInInstance = player->GetTeamId();
}
else
TeamIdInInstance = player->GetTeamId();
}
}
switch (creature->GetEntry())
{
case NPC_SHATTERED_EXECUTIONER:
@@ -117,22 +72,22 @@ public:
ExecutionerGUID = creature->GetGUID();
break;
case NPC_RIFLEMAN_BROWNBEARD:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_KORAG_PROUDMANE);
PrisonerGUID[0] = creature->GetGUID();
break;
case NPC_CAPTAIN_ALINA:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_CAPTAIN_BONESHATTER);
PrisonerGUID[1] = creature->GetGUID();
break;
case NPC_PRIVATE_JACINT:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_SCOUT_ORGARR);
PrisonerGUID[2] = creature->GetGUID();
break;
case NPC_RANDY_WHIZZLESPROCKET:
if (TeamIdInInstance == TEAM_HORDE)
if (GetTeamIdInInstance() == TEAM_HORDE)
creature->UpdateEntry(NPC_DRISELLA);
break;
}
@@ -147,7 +102,7 @@ public:
instance->LoadGrid(230, -80);
if (Creature* kargath = GetCreature(DATA_KARGATH))
sCreatureTextMgr->SendChat(kargath, TeamIdInInstance == TEAM_ALLIANCE ? 3 : 4, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP);
sCreatureTextMgr->SendChat(kargath, GetTeamIdInInstance() == TEAM_ALLIANCE ? 3 : 4, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP);
RescueTimer = 80 * MINUTE * IN_MILLISECONDS;
}
@@ -213,7 +168,6 @@ public:
ObjectGuid ExecutionerGUID;
ObjectGuid PrisonerGUID[3];
uint32 RescueTimer;
TeamId TeamIdInInstance;
};
};