Merge branch 'master' into Playerbot
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#include "RealmList.h"
|
||||
#include "SecretMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SteadyTimer.h"
|
||||
#include "Util.h"
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
@@ -179,17 +180,13 @@ int main(int argc, char** argv)
|
||||
int32 dbPingInterval = sConfigMgr->GetOption<int32>("MaxPingTime", 30);
|
||||
std::shared_ptr<boost::asio::steady_timer> dbPingTimer = std::make_shared<boost::asio::steady_timer>(*ioContext);
|
||||
|
||||
// Calculate the expiration time
|
||||
auto expirationTime = std::chrono::steady_clock::now() + std::chrono::seconds(dbPingInterval);
|
||||
dbPingTimer->expires_at(expirationTime);
|
||||
dbPingTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(dbPingInterval * MINUTE));
|
||||
dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, std::weak_ptr<boost::asio::steady_timer>(dbPingTimer), dbPingInterval, std::placeholders::_1));
|
||||
|
||||
int32 banExpiryCheckInterval = sConfigMgr->GetOption<int32>("BanExpiryCheckInterval", 60);
|
||||
std::shared_ptr<boost::asio::steady_timer> banExpiryCheckTimer = std::make_shared<boost::asio::steady_timer>(*ioContext);
|
||||
|
||||
// Calculate the expiration time
|
||||
auto expirationTimeBanExpiry = std::chrono::steady_clock::now() + std::chrono::seconds(banExpiryCheckInterval);
|
||||
banExpiryCheckTimer->expires_at(expirationTimeBanExpiry);
|
||||
banExpiryCheckTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(banExpiryCheckInterval));
|
||||
banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, std::weak_ptr<boost::asio::steady_timer>(banExpiryCheckTimer), banExpiryCheckInterval, std::placeholders::_1));
|
||||
|
||||
// Start the io service worker loop
|
||||
@@ -252,9 +249,7 @@ void KeepDatabaseAliveHandler(std::weak_ptr<boost::asio::steady_timer> dbPingTim
|
||||
LOG_INFO("server.authserver", "Ping MySQL to keep connection alive");
|
||||
LoginDatabase.KeepAlive();
|
||||
|
||||
// Calculate the expiration time
|
||||
auto expirationTime = std::chrono::steady_clock::now() + std::chrono::seconds(dbPingInterval);
|
||||
dbPingTimer->expires_at(expirationTime);
|
||||
dbPingTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(dbPingInterval));
|
||||
dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, dbPingTimerRef, dbPingInterval, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
@@ -269,9 +264,7 @@ void BanExpiryHandler(std::weak_ptr<boost::asio::steady_timer> banExpiryCheckTim
|
||||
LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
|
||||
LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS));
|
||||
|
||||
// Calculate the expiration time
|
||||
auto expirationTime = std::chrono::steady_clock::now() + std::chrono::seconds(banExpiryCheckInterval);
|
||||
banExpiryCheckTimer->expires_at(expirationTime);
|
||||
banExpiryCheckTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(banExpiryCheckInterval));
|
||||
banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, banExpiryCheckTimerRef, banExpiryCheckInterval, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "SecretMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SteadyTimer.h"
|
||||
#include "World.h"
|
||||
#include "WorldSocket.h"
|
||||
#include "WorldSocketMgr.h"
|
||||
@@ -90,9 +91,7 @@ public:
|
||||
|
||||
static void Start(std::shared_ptr<FreezeDetector> const& freezeDetector)
|
||||
{
|
||||
// Calculate the expiration time 5seconds from now
|
||||
auto expirationTime = std::chrono::steady_clock::now() + std::chrono::seconds(5);
|
||||
freezeDetector->_timer.expires_at(expirationTime);
|
||||
freezeDetector->_timer.expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(5));
|
||||
freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, std::weak_ptr<FreezeDetector>(freezeDetector), std::placeholders::_1));
|
||||
}
|
||||
|
||||
@@ -644,9 +643,7 @@ void FreezeDetector::Handler(std::weak_ptr<FreezeDetector> freezeDetectorRef, bo
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the expiration time
|
||||
auto expirationTime = std::chrono::steady_clock::now() + std::chrono::seconds(1);
|
||||
freezeDetector->_timer.expires_at(expirationTime);
|
||||
freezeDetector->_timer.expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(1));
|
||||
freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, freezeDetectorRef, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2047,11 +2047,18 @@ WaterBreath.Timer = 180000
|
||||
EnableLowLevelRegenBoost = 1
|
||||
|
||||
#
|
||||
# Rate.MoveSpeed
|
||||
# Description: Movement speed rate.
|
||||
# Rate.MoveSpeed.Player
|
||||
# Description: Movement speed rate for players.
|
||||
# Default: 1
|
||||
|
||||
Rate.MoveSpeed = 1
|
||||
Rate.MoveSpeed.Player = 1
|
||||
|
||||
#
|
||||
# Rate.MoveSpeed.NPC
|
||||
# Description: Movement speed rate for NPCs.
|
||||
# Default: 1
|
||||
|
||||
Rate.MoveSpeed.NPC = 1
|
||||
|
||||
#
|
||||
# Rate.Damage.Fall
|
||||
|
||||
@@ -86,6 +86,7 @@ void WorldDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id1, id2, id3, map, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(WORLD_DEL_GAME_EVENT_CREATURE, "DELETE FROM game_event_creature WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(WORLD_DEL_GAME_EVENT_MODEL_EQUIP, "DELETE FROM game_event_model_equip WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(WORLD_SEL_GAME_EVENT_NPC_VENDOR, "SELECT eventEntry, guid, item, maxcount, incrtime, ExtendedCost FROM game_event_npc_vendor ORDER BY guid, slot ASC", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_INS_GAMEOBJECT, "INSERT INTO gameobject (guid, id, map, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(WORLD_INS_DISABLES, "INSERT INTO disables (entry, sourceType, flags, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(WORLD_SEL_DISABLES, "SELECT entry FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_SYNCH);
|
||||
|
||||
@@ -92,6 +92,7 @@ enum WorldDatabaseStatements : uint32
|
||||
WORLD_INS_CREATURE,
|
||||
WORLD_DEL_GAME_EVENT_CREATURE,
|
||||
WORLD_DEL_GAME_EVENT_MODEL_EQUIP,
|
||||
WORLD_SEL_GAME_EVENT_NPC_VENDOR,
|
||||
WORLD_INS_GAMEOBJECT,
|
||||
WORLD_SEL_DISABLES,
|
||||
WORLD_INS_DISABLES,
|
||||
|
||||
@@ -156,7 +156,7 @@ void AuctionHouseWorkerThread::SearchListRequest(AuctionSearchListRequest const&
|
||||
|
||||
if (!searchListRequest.searchInfo.sorting.empty() && auctionEntries.size() > MAX_AUCTIONS_PER_PAGE)
|
||||
{
|
||||
AuctionSorter sorter(&searchListRequest.searchInfo.sorting, searchListRequest.playerInfo.locdbc_idx);
|
||||
AuctionSorter sorter(&searchListRequest.searchInfo.sorting, searchListRequest.playerInfo.loc_idx);
|
||||
std::sort(auctionEntries.begin(), auctionEntries.end(), sorter);
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ void AuctionHouseWorkerThread::BuildListAuctionItems(AuctionSearchListRequest co
|
||||
// No need to do any of this if no search term was entered
|
||||
if (!searchRequest.searchInfo.wsearchedname.empty())
|
||||
{
|
||||
if (Aitem.itemName[searchRequest.playerInfo.locdbc_idx].find(searchRequest.searchInfo.wsearchedname) == std::wstring::npos)
|
||||
if (Aitem.itemName[searchRequest.playerInfo.loc_idx].find(searchRequest.searchInfo.wsearchedname) == std::wstring::npos)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,6 +274,11 @@ void TempSummon::InitSummon()
|
||||
}
|
||||
}
|
||||
|
||||
void TempSummon::UpdateObjectVisibilityOnCreate()
|
||||
{
|
||||
WorldObject::UpdateObjectVisibility(true);
|
||||
}
|
||||
|
||||
void TempSummon::SetTempSummonType(TempSummonType type)
|
||||
{
|
||||
m_type = type;
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
virtual void InitStats(uint32 lifetime);
|
||||
virtual void InitSummon();
|
||||
virtual void UnSummon(uint32 msTime = 0);
|
||||
void UpdateObjectVisibilityOnCreate() override;
|
||||
void RemoveFromWorld() override;
|
||||
void SetTempSummonType(TempSummonType type);
|
||||
void SaveToDB(uint32 /*mapid*/, uint8 /*spawnMask*/, uint32 /*phaseMask*/) override {}
|
||||
|
||||
@@ -2274,7 +2274,9 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert
|
||||
|
||||
summon->InitSummon();
|
||||
|
||||
//ObjectAccessor::UpdateObjectVisibility(summon);
|
||||
// call MoveInLineOfSight for nearby creatures
|
||||
Acore::AIRelocationNotifier notifier(*summon);
|
||||
Cell::VisitAllObjects(summon, notifier, GetVisibilityRange());
|
||||
|
||||
return summon;
|
||||
}
|
||||
|
||||
@@ -558,6 +558,7 @@ public:
|
||||
|
||||
void DestroyForNearbyPlayers();
|
||||
virtual void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false);
|
||||
virtual void UpdateObjectVisibilityOnCreate() { UpdateObjectVisibility(true); }
|
||||
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& player_set) override;
|
||||
void GetCreaturesWithEntryInRange(std::list<Creature*>& creatureList, float radius, uint32 entry);
|
||||
|
||||
|
||||
@@ -1362,11 +1362,11 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
}
|
||||
case NPC_ARMY_OF_THE_DEAD:
|
||||
{
|
||||
AddAura(SPELL_HUNTER_PET_SCALING_04, this);
|
||||
AddAura(SPELL_DK_PET_SCALING_01, this);
|
||||
AddAura(SPELL_DK_ARMY_OF_THE_DEAD_PASSIVE, this);
|
||||
AddAura(SPELL_DK_PET_SCALING_02, this);
|
||||
AddAura(SPELL_DK_PET_SCALING_03, this);
|
||||
AddAura(SPELL_PET_AVOIDANCE, this);
|
||||
AddAura(SPELL_DK_AVOIDANCE, this);
|
||||
AddAura(SPELL_PET_SCALING_MASTER_06, this);
|
||||
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
||||
|
||||
@@ -134,7 +134,9 @@ enum NPCEntries
|
||||
enum PetScalingSpells
|
||||
{
|
||||
SPELL_PET_AVOIDANCE = 32233,
|
||||
SPELL_PET_SCALING_MASTER_06 = 67561, // Serverside - Pet Scaling - Master Spell 06 - Spell Hit, Expertise, Spell Penetration
|
||||
|
||||
// Hunter
|
||||
SPELL_HUNTER_PET_SCALING_01 = 34902,
|
||||
SPELL_HUNTER_PET_SCALING_02 = 34903,
|
||||
SPELL_HUNTER_PET_SCALING_03 = 34904,
|
||||
@@ -190,9 +192,11 @@ enum PetScalingSpells
|
||||
// Death Knight
|
||||
SPELL_ORC_RACIAL_COMMAND_DK = 65221,
|
||||
SPELL_NIGHT_OF_THE_DEAD_AVOIDANCE = 62137,
|
||||
SPELL_DK_PET_SCALING_01 = 51996,
|
||||
SPELL_DK_PET_SCALING_02 = 54566,
|
||||
SPELL_DK_PET_SCALING_03 = 61697
|
||||
SPELL_DK_PET_SCALING_01 = 54566,
|
||||
SPELL_DK_PET_SCALING_02 = 51996,
|
||||
SPELL_DK_PET_SCALING_03 = 61697,
|
||||
SPELL_DK_AVOIDANCE = 65220,
|
||||
SPELL_DK_ARMY_OF_THE_DEAD_PASSIVE = 49040,
|
||||
};
|
||||
|
||||
#define PET_FOLLOW_DIST 1.0f
|
||||
|
||||
@@ -2419,7 +2419,7 @@ void Player::GiveXP(uint32 xp, Unit* victim, float group_rate, bool isLFGReward)
|
||||
// Favored experience increase START
|
||||
uint32 zone = GetZoneId();
|
||||
float favored_exp_mult = 0;
|
||||
if ((zone == 3483 || zone == 3562 || zone == 3836 || zone == 3713 || zone == 3714) && (HasAura(32096) || HasAura(32098)))
|
||||
if ((zone == 3483 || zone == 3562 || zone == 3836 || zone == 3713 || zone == 3714) && HasAnyAuras(32096 /*Thrallmar's Favor*/, 32098 /*Honor Hold's Favor*/))
|
||||
favored_exp_mult = 0.05f; // Thrallmar's Favor and Honor Hold's Favor
|
||||
|
||||
xp = uint32(xp * (1 + favored_exp_mult));
|
||||
|
||||
@@ -444,7 +444,7 @@ struct Runes
|
||||
|
||||
struct EnchantDuration
|
||||
{
|
||||
EnchantDuration() = default;;
|
||||
EnchantDuration() = default;
|
||||
EnchantDuration(Item* _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot),
|
||||
leftduration(_leftduration) { ASSERT(item); };
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ void Player::_LoadCharacterSettings(PreparedQueryResult result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
std::string source = fields[0].Get<std::string>();;
|
||||
std::string source = fields[0].Get<std::string>();
|
||||
std::string data = fields[1].Get<std::string>();
|
||||
|
||||
std::vector<std::string_view> tokens = Acore::Tokenize(data, ' ', false);
|
||||
|
||||
@@ -6723,7 +6723,7 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map
|
||||
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, target_map, this))
|
||||
{
|
||||
GetSession()->SendAreaTriggerMessage("%s", GetSession()->GetAcoreString(LANG_INSTANCE_CLOSED));
|
||||
GetSession()->SendAreaTriggerMessage("{}", GetSession()->GetAcoreString(LANG_INSTANCE_CLOSED));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -5695,6 +5695,29 @@ uint32 Unit::GetAuraCount(uint32 spellId) const
|
||||
return count;
|
||||
}
|
||||
|
||||
bool Unit::HasAuras(SearchMethod sm, std::vector<uint32>& spellIds) const
|
||||
{
|
||||
if (sm == SearchMethod::MatchAll)
|
||||
{
|
||||
for (auto const& spellId : spellIds)
|
||||
if (!HasAura(spellId))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
else if (sm == SearchMethod::MatchAny)
|
||||
{
|
||||
for (auto const& spellId : spellIds)
|
||||
if (HasAura(spellId))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("entities.unit", "Unit::HasAuras using non-supported SearchMethod {}", sm);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const
|
||||
{
|
||||
if (GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask))
|
||||
@@ -21307,7 +21330,7 @@ bool Unit::IsInDisallowedMountForm() const
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(shapeshift->flags1 & 0x1))
|
||||
if (!(shapeshift->flags1 & SHAPESHIFT_FLAG_STANCE))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -558,6 +558,12 @@ enum CommandStates : uint8
|
||||
COMMAND_ABANDON = 3
|
||||
};
|
||||
|
||||
enum class SearchMethod
|
||||
{
|
||||
MatchAll,
|
||||
MatchAny
|
||||
};
|
||||
|
||||
typedef std::list<Player*> SharedVisionList;
|
||||
|
||||
struct AttackPosition {
|
||||
@@ -1367,6 +1373,50 @@ public:
|
||||
|
||||
[[nodiscard]] bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster = ObjectGuid::Empty) const;
|
||||
[[nodiscard]] uint32 GetAuraCount(uint32 spellId) const;
|
||||
|
||||
/**
|
||||
* @brief Check if unit has ANY or ALL specified auras.
|
||||
*
|
||||
* @param sm The search method to use
|
||||
* - SearchMethod::MatchAll : The function checks for all of the spell id's on the unit.
|
||||
* - SearchMethod::MatchAny : The function checks for any of the spell id's on the unit.
|
||||
*
|
||||
* @param spellIds List of spell id's to check for on the unit.
|
||||
*
|
||||
* @return Returns true if the search method condition is met. Otherwise false.
|
||||
*/
|
||||
bool HasAuras(SearchMethod sm, std::vector<uint32>& spellIds) const;
|
||||
|
||||
/**
|
||||
* @brief Checks if the unit has ANY specified auras.
|
||||
*
|
||||
* @tparam Auras Can be any type convertible to uint32.
|
||||
* @param spellIds List of spell id's to check for on the unit.
|
||||
*
|
||||
* @return Returns true if the unit has ANY of the specified auras. Otherwise false.
|
||||
*/
|
||||
template <typename... Auras>
|
||||
bool HasAnyAuras(Auras... spellIds) const
|
||||
{
|
||||
std::vector<uint32> spellList = { static_cast<uint32>(spellIds)... };
|
||||
return HasAuras(SearchMethod::MatchAny, spellList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the unit has ALL specified auras.
|
||||
*
|
||||
* @tparam Auras Can be any type convertible to uint32.
|
||||
* @param spellIds List of spell id's to check for on the unit.
|
||||
*
|
||||
* @return Returns true if the unit has ALL of the specified auras. Otherwise false.
|
||||
*/
|
||||
template <typename... Auras>
|
||||
bool HasAllAuras(Auras... spellIds) const
|
||||
{
|
||||
std::vector<uint32> spellList = { static_cast<uint32>(spellIds)... };
|
||||
return HasAuras(SearchMethod::MatchAll, spellList);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool HasAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid itemCasterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0) const;
|
||||
[[nodiscard]] bool HasAuraType(AuraType auraType) const;
|
||||
[[nodiscard]] bool HasAuraTypeWithCaster(AuraType auratype, ObjectGuid caster) const;
|
||||
|
||||
@@ -99,6 +99,27 @@ enum ShapeshiftForm
|
||||
FORM_SPIRITOFREDEMPTION = 0x20
|
||||
};
|
||||
|
||||
enum ShapeshiftFlags
|
||||
{
|
||||
SHAPESHIFT_FLAG_STANCE = 0x00000001, // Form allows various player activities, which normally cause "You can't X while shapeshifted." errors (npc/go interaction, item use, etc)
|
||||
SHAPESHIFT_FLAG_NOT_TOGGLEABLE = 0x00000002, // NYI
|
||||
SHAPESHIFT_FLAG_PERSIST_ON_DEATH = 0x00000004, // NYI
|
||||
SHAPESHIFT_FLAG_CAN_NPC_INTERACT = 0x00000008, // Form unconditionally allows talking to NPCs while shapeshifted (even if other activities are disabled)
|
||||
SHAPESHIFT_FLAG_DONT_USE_WEAPON = 0x00000010, // NYI
|
||||
SHAPESHIFT_FLAG_AGILITY_ATTACK_BONUS = 0x00000020, // Druid Cat form
|
||||
SHAPESHIFT_FLAG_CAN_USE_EQUIPPED_ITEMS = 0x00000040, // NYI
|
||||
SHAPESHIFT_FLAG_CAN_USE_ITEMS = 0x00000080, // NYI
|
||||
SHAPESHIFT_FLAG_DONT_AUTO_UNSHIFT = 0x00000100, // Handled at client side
|
||||
SHAPESHIFT_FLAG_CONSIDERED_DEAD = 0x00000200, // NYI
|
||||
SHAPESHIFT_FLAG_CAN_ONLY_CAST_SHAPESHIFT_SPELLS = 0x00000400, // NYI
|
||||
SHAPESHIFT_FLAG_STANCE_CANCEL_AT_FLIGHTMASTER = 0x00000800, // NYI
|
||||
SHAPESHIFT_FLAG_NO_EMOTE_SOUNDS = 0x00001000, // NYI
|
||||
SHAPESHIFT_FLAG_NO_TRIGGER_TELEPORT = 0x00002000, // NYI
|
||||
SHAPESHIFT_FLAG_CANNOT_CHANGE_EQUIPPED_ITEMS = 0x00004000, // NYI
|
||||
SHAPESHIFT_FLAG_RESUMMON_PETS_ON_UNSHIFT = 0x00008000, // NYI
|
||||
SHAPESHIFT_FLAG_CANNOT_USE_GAME_OBJECTS = 0x00010000, // NYI
|
||||
};
|
||||
|
||||
// low byte (0 from 0..3) of UNIT_FIELD_BYTES_2
|
||||
enum SheathState
|
||||
{
|
||||
|
||||
@@ -236,6 +236,92 @@ void GameEventMgr::StopEvent(uint16 event_id, bool overwrite)
|
||||
sScriptMgr->OnGameEventStop(event_id);
|
||||
}
|
||||
|
||||
void GameEventMgr::LoadEventVendors()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_GAME_EVENT_NPC_VENDOR);
|
||||
PreparedQueryResult result = WorldDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 Vendor Additions In Game Events. DB Table `game_event_npc_vendor` Is Empty.");
|
||||
LOG_INFO("server.loading", " ");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
std::unordered_set<uint8> processedEvents;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint8 eventId = fields[0].Get<uint8>();
|
||||
ObjectGuid::LowType guid = fields[1].Get<uint32>();
|
||||
|
||||
if (eventId >= mGameEventVendors.size())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Table `game_event_npc_vendor` has invalid eventEntry ({}) for GUID ({}), skipped.", eventId, guid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clear existing vendors for this event only once
|
||||
if (processedEvents.find(eventId) == processedEvents.end())
|
||||
{
|
||||
// Remove vendor items from in-memory data
|
||||
for (auto& entry : mGameEventVendors[eventId])
|
||||
{
|
||||
sObjectMgr->RemoveVendorItem(entry.entry, entry.item, false);
|
||||
}
|
||||
mGameEventVendors[eventId].clear();
|
||||
processedEvents.insert(eventId);
|
||||
}
|
||||
|
||||
NPCVendorList& vendors = mGameEventVendors[eventId];
|
||||
NPCVendorEntry newEntry;
|
||||
newEntry.item = fields[2].Get<uint32>();
|
||||
newEntry.maxcount = fields[3].Get<uint32>();
|
||||
newEntry.incrtime = fields[4].Get<uint32>();
|
||||
newEntry.ExtendedCost = fields[5].Get<uint32>();
|
||||
|
||||
// Get the event NPC flag for validity check
|
||||
uint32 event_npc_flag = 0;
|
||||
NPCFlagList& flist = mGameEventNPCFlags[eventId];
|
||||
for (NPCFlagList::const_iterator itr = flist.begin(); itr != flist.end(); ++itr)
|
||||
{
|
||||
if (itr->first == guid)
|
||||
{
|
||||
event_npc_flag = itr->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get creature entry
|
||||
newEntry.entry = 0;
|
||||
if (CreatureData const* data = sObjectMgr->GetCreatureData(guid))
|
||||
newEntry.entry = data->id1;
|
||||
|
||||
// Validate vendor item
|
||||
if (!sObjectMgr->IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, nullptr, nullptr, event_npc_flag))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Table `game_event_npc_vendor` has invalid item ({}) for guid ({}) for event ({}), skipped.",
|
||||
newEntry.item, newEntry.entry, eventId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the item to the vendor if event is active
|
||||
if (IsEventActive(eventId))
|
||||
sObjectMgr->AddVendorItem(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, false);
|
||||
|
||||
vendors.push_back(newEntry);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Vendor Additions In Game Events in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
|
||||
}
|
||||
|
||||
void GameEventMgr::LoadFromDB()
|
||||
{
|
||||
{
|
||||
@@ -852,69 +938,7 @@ void GameEventMgr::LoadFromDB()
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", "Loading Game Event Vendor Additions Data...");
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2 3 4 5
|
||||
QueryResult result = WorldDatabase.Query("SELECT eventEntry, guid, item, maxcount, incrtime, ExtendedCost FROM game_event_npc_vendor ORDER BY guid, slot ASC");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 Vendor Additions In Game Events. DB Table `game_event_npc_vendor` Is Empty.");
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint8 event_id = fields[0].Get<uint8>();
|
||||
|
||||
if (event_id >= mGameEventVendors.size())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`game_event_npc_vendor` game event id ({}) is out of range compared to max event id in `game_event`", event_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
NPCVendorList& vendors = mGameEventVendors[event_id];
|
||||
NPCVendorEntry newEntry;
|
||||
ObjectGuid::LowType guid = fields[1].Get<uint32>();
|
||||
newEntry.item = fields[2].Get<uint32>();
|
||||
newEntry.maxcount = fields[3].Get<uint32>();
|
||||
newEntry.incrtime = fields[4].Get<uint32>();
|
||||
newEntry.ExtendedCost = fields[5].Get<uint32>();
|
||||
// get the event npc flag for checking if the npc will be vendor during the event or not
|
||||
uint32 event_npc_flag = 0;
|
||||
NPCFlagList& flist = mGameEventNPCFlags[event_id];
|
||||
for (NPCFlagList::const_iterator itr = flist.begin(); itr != flist.end(); ++itr)
|
||||
{
|
||||
if (itr->first == guid)
|
||||
{
|
||||
event_npc_flag = itr->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// get creature entry
|
||||
newEntry.entry = 0;
|
||||
|
||||
if (CreatureData const* data = sObjectMgr->GetCreatureData(guid))
|
||||
newEntry.entry = data->id1;
|
||||
|
||||
// check validity with event's npcflag
|
||||
if (!sObjectMgr->IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, nullptr, nullptr, event_npc_flag))
|
||||
continue;
|
||||
|
||||
vendors.push_back(newEntry);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Vendor Additions In Game Events in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
}
|
||||
LoadEventVendors();
|
||||
|
||||
LOG_INFO("server.loading", "Loading Game Event Battleground Data...");
|
||||
{
|
||||
|
||||
@@ -121,6 +121,8 @@ public:
|
||||
void StopEvent(uint16 event_id, bool overwrite = false);
|
||||
void HandleQuestComplete(uint32 quest_id); // called on world event type quest completions
|
||||
uint32 GetNPCFlag(Creature* cr);
|
||||
// Load the game event npc vendor table from the DB
|
||||
void LoadEventVendors();
|
||||
[[nodiscard]] uint32 GetHolidayEventId(uint32 holidayId) const;
|
||||
private:
|
||||
void SendWorldStateUpdate(Player* player, uint16 event_id);
|
||||
|
||||
@@ -268,7 +268,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
|
||||
wstrToLower(wpacketPlayerName);
|
||||
wstrToLower(wpacketGuildName);;
|
||||
wstrToLower(wpacketGuildName);
|
||||
|
||||
// client send in case not set max level value 100 but Acore supports 255 max level,
|
||||
// update it to show GMs with characters after 100 level
|
||||
|
||||
@@ -108,7 +108,7 @@ class InstanceSaveMgr
|
||||
friend class InstanceSave;
|
||||
|
||||
private:
|
||||
InstanceSaveMgr() = default;;
|
||||
InstanceSaveMgr() = default;
|
||||
~InstanceSaveMgr();
|
||||
|
||||
public:
|
||||
|
||||
@@ -561,7 +561,7 @@ bool Map::AddToMap(T* obj, bool checkTransport)
|
||||
if (obj->IsInWorld())
|
||||
{
|
||||
ASSERT(obj->IsInGrid());
|
||||
obj->UpdateObjectVisibility(true);
|
||||
obj->UpdateObjectVisibilityOnCreate();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5832,7 +5832,7 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
if (effInfo->ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT)
|
||||
{
|
||||
SpellShapeshiftFormEntry const* shapeShiftEntry = sSpellShapeshiftFormStore.LookupEntry(effInfo->MiscValue);
|
||||
if (shapeShiftEntry && (shapeShiftEntry->flags1 & 1) == 0) // unk flag
|
||||
if (shapeShiftEntry && (shapeShiftEntry->flags1 & SHAPESHIFT_FLAG_STANCE) == 0)
|
||||
checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1457,7 +1457,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
LOG_ERROR("spells", "GetErrorAtShapeshiftedCast: unknown shapeshift {}", form);
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
actAsShifted = !(shapeInfo->flags1 & 1); // shapeshift acts as normal form for spells
|
||||
actAsShifted = !(shapeInfo->flags1 & SHAPESHIFT_FLAG_STANCE); // shapeshift acts as normal form for spells
|
||||
}
|
||||
|
||||
if (actAsShifted)
|
||||
@@ -1477,7 +1477,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
// Check if stance disables cast of not-stance spells
|
||||
// Example: cannot cast any other spells in zombie or ghoul form
|
||||
/// @todo: Find a way to disable use of these spells clientside
|
||||
if (shapeInfo && shapeInfo->flags1 & 0x400)
|
||||
if (shapeInfo && (shapeInfo->flags1 & SHAPESHIFT_FLAG_CAN_ONLY_CAST_SHAPESHIFT_SPELLS))
|
||||
{
|
||||
if (!(stanceMask & Stances))
|
||||
return SPELL_FAILED_ONLY_SHAPESHIFT;
|
||||
|
||||
@@ -2913,16 +2913,6 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPELL_AURA_PERIODIC_HEAL:
|
||||
case SPELL_AURA_PERIODIC_DAMAGE:
|
||||
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
|
||||
case SPELL_AURA_PERIODIC_LEECH:
|
||||
case SPELL_AURA_PERIODIC_MANA_LEECH:
|
||||
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
|
||||
case SPELL_AURA_PERIODIC_ENERGIZE:
|
||||
case SPELL_AURA_OBS_MOD_HEALTH:
|
||||
case SPELL_AURA_OBS_MOD_POWER:
|
||||
case SPELL_AURA_POWER_BURN:
|
||||
case SPELL_AURA_TRACK_CREATURES:
|
||||
case SPELL_AURA_MOD_RANGED_HASTE:
|
||||
case SPELL_AURA_MOD_POSSESS_PET:
|
||||
|
||||
@@ -518,7 +518,8 @@ enum Rates
|
||||
RATE_DURABILITY_LOSS_PARRY,
|
||||
RATE_DURABILITY_LOSS_ABSORB,
|
||||
RATE_DURABILITY_LOSS_BLOCK,
|
||||
RATE_MOVESPEED,
|
||||
RATE_MOVESPEED_PLAYER,
|
||||
RATE_MOVESPEED_NPC,
|
||||
RATE_MISS_CHANCE_MULTIPLIER_TARGET_CREATURE,
|
||||
RATE_MISS_CHANCE_MULTIPLIER_TARGET_PLAYER,
|
||||
MAX_RATES
|
||||
|
||||
@@ -576,13 +576,24 @@ void World::LoadConfigSettings(bool reload)
|
||||
LOG_ERROR("server.loading", "Rate.Talent.Pet ({}) must be > 0. Using 1 instead.", _rate_values[RATE_TALENT_PET]);
|
||||
_rate_values[RATE_TALENT_PET] = 1.0f;
|
||||
}
|
||||
_rate_values[RATE_MOVESPEED] = sConfigMgr->GetOption<float>("Rate.MoveSpeed", 1.0f);
|
||||
if (_rate_values[RATE_MOVESPEED] < 0)
|
||||
// Controls Player movespeed rate.
|
||||
_rate_values[RATE_MOVESPEED_PLAYER] = sConfigMgr->GetOption<float>("Rate.MoveSpeed.Player", 1.0f);
|
||||
if (_rate_values[RATE_MOVESPEED_PLAYER] < 0)
|
||||
{
|
||||
LOG_ERROR("server.loading", "Rate.MoveSpeed ({}) must be > 0. Using 1 instead.", _rate_values[RATE_MOVESPEED]);
|
||||
_rate_values[RATE_MOVESPEED] = 1.0f;
|
||||
LOG_ERROR("server.loading", "Rate.MoveSpeed.Player ({}) must be > 0. Using 1 instead.", _rate_values[RATE_MOVESPEED_PLAYER]);
|
||||
_rate_values[RATE_MOVESPEED_PLAYER] = 1.0f;
|
||||
}
|
||||
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) playerBaseMoveSpeed[i] = baseMoveSpeed[i] * _rate_values[RATE_MOVESPEED];
|
||||
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) playerBaseMoveSpeed[i] = baseMoveSpeed[i] * _rate_values[RATE_MOVESPEED_PLAYER];
|
||||
|
||||
// Controls all npc movespeed rate.
|
||||
_rate_values[RATE_MOVESPEED_NPC] = sConfigMgr->GetOption<float>("Rate.MoveSpeed.NPC", 1.0f);
|
||||
if (_rate_values[RATE_MOVESPEED_NPC] < 0)
|
||||
{
|
||||
LOG_ERROR("server.loading", "Rate.MoveSpeed.NPC ({}) must be > 0. Using 1 instead.", _rate_values[RATE_MOVESPEED_NPC]);
|
||||
_rate_values[RATE_MOVESPEED_NPC] = 1.0f;
|
||||
}
|
||||
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) baseMoveSpeed[i] *= _rate_values[RATE_MOVESPEED_NPC];
|
||||
|
||||
_rate_values[RATE_CORPSE_DECAY_LOOTED] = sConfigMgr->GetOption<float>("Rate.Corpse.Decay.Looted", 0.5f);
|
||||
|
||||
_rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = sConfigMgr->GetOption<float>("DurabilityLoss.OnDeath", 10.0f);
|
||||
|
||||
@@ -374,20 +374,24 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleNpcDeleteCommand(ChatHandler* handler)
|
||||
static bool HandleNpcDeleteCommand(ChatHandler* handler, Optional<ObjectGuid::LowType> lowGuid)
|
||||
{
|
||||
Creature* unit = handler->getSelectedCreature();
|
||||
Creature* creature;
|
||||
if (lowGuid.has_value())
|
||||
creature = handler->GetCreatureFromPlayerMapByDbGuid(*lowGuid);
|
||||
else
|
||||
creature = handler->getSelectedCreature();
|
||||
|
||||
if (!unit || unit->IsPet() || unit->IsTotem())
|
||||
if (!creature || creature->IsPet() || creature->IsTotem())
|
||||
{
|
||||
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete the creature
|
||||
unit->CombatStop();
|
||||
unit->DeleteFromDB();
|
||||
unit->AddObjectToRemoveList();
|
||||
creature->CombatStop();
|
||||
creature->DeleteFromDB();
|
||||
creature->AddObjectToRemoveList();
|
||||
|
||||
handler->SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
|
||||
|
||||
@@ -712,25 +716,33 @@ public:
|
||||
}
|
||||
|
||||
//move selected creature
|
||||
static bool HandleNpcMoveCommand(ChatHandler* handler)
|
||||
static bool HandleNpcMoveCommand(ChatHandler* handler, Optional<ObjectGuid::LowType> guid)
|
||||
{
|
||||
Creature* creature = handler->getSelectedCreature();
|
||||
Creature* creature;
|
||||
if (guid.has_value())
|
||||
creature = handler->GetCreatureFromPlayerMapByDbGuid(*guid);
|
||||
else
|
||||
creature = handler->getSelectedCreature();
|
||||
|
||||
if (!creature)
|
||||
return false;
|
||||
|
||||
ObjectGuid::LowType lowguid = creature->GetSpawnId();
|
||||
ObjectGuid::LowType lowGuid;
|
||||
if (guid.has_value())
|
||||
lowGuid = *guid;
|
||||
else
|
||||
lowGuid = creature->GetSpawnId();
|
||||
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
|
||||
if (!data)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
|
||||
handler->SendErrorMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handler->GetSession()->GetPlayer()->GetMapId() != data->mapid)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
|
||||
handler->SendErrorMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowGuid);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -764,7 +776,7 @@ public:
|
||||
stmt->SetData(1, y);
|
||||
stmt->SetData(2, z);
|
||||
stmt->SetData(3, o);
|
||||
stmt->SetData(4, lowguid);
|
||||
stmt->SetData(4, lowGuid);
|
||||
|
||||
WorldDatabase.Execute(stmt);
|
||||
|
||||
|
||||
@@ -135,6 +135,7 @@ public:
|
||||
{ "npc_spellclick_spells", HandleReloadSpellClickSpellsCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "npc_trainer", HandleReloadNpcTrainerCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "npc_vendor", HandleReloadNpcVendorCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "game_event_npc_vendor", HandleReloadGameEventNPCVendorCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "page_text", HandleReloadPageTextsCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "pickpocketing_loot_template", HandleReloadLootTemplatesPickpocketingCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "points_of_interest", HandleReloadPointsOfInterestCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
@@ -765,6 +766,14 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReloadGameEventNPCVendorCommand(ChatHandler* handler)
|
||||
{
|
||||
LOG_INFO("server.loading", "Reloading `game_event_npc_vendor` Table!");
|
||||
sGameEventMgr->LoadEventVendors();
|
||||
handler->SendGlobalGMSysMessage("DB table `game_event_npc_vendor` reloaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReloadPointsOfInterestCommand(ChatHandler* handler)
|
||||
{
|
||||
LOG_INFO("server.loading", "Reloading `points_of_interest` Table!");
|
||||
|
||||
+1
-4
@@ -188,11 +188,8 @@ public:
|
||||
{
|
||||
DoCast(player, afflictionSpellID, true);
|
||||
|
||||
if (player->HasAura(SPELL_BROODAF_BLUE) && player->HasAura(SPELL_BROODAF_BLACK) && player->HasAura(SPELL_BROODAF_RED) &&
|
||||
player->HasAura(SPELL_BROODAF_BRONZE) && player->HasAura(SPELL_BROODAF_GREEN))
|
||||
{
|
||||
if (player->HasAllAuras(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN))
|
||||
DoCast(player, SPELL_CHROMATIC_MUT_1);
|
||||
}
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_AFFLICTION, 10s);
|
||||
|
||||
@@ -1424,6 +1424,7 @@ struct npc_chesspiece : public ScriptedAI
|
||||
_instance = creature->GetInstanceScript();
|
||||
|
||||
_currentOrientation = GetDefaultOrientationForTeam();
|
||||
_homePosition = creature->GetPosition();
|
||||
|
||||
_nextMoveTimer = urand(8 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
|
||||
|
||||
@@ -1457,6 +1458,8 @@ struct npc_chesspiece : public ScriptedAI
|
||||
{
|
||||
me->SetResistance(SpellSchools(i), 0);
|
||||
}
|
||||
|
||||
me->NearTeleportTo(_homePosition);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
@@ -2044,6 +2047,7 @@ private:
|
||||
KarazhanChessOrientationType _currentOrientation;
|
||||
|
||||
bool _teamControlledByRaid;
|
||||
Position _homePosition;
|
||||
};
|
||||
|
||||
struct npc_chess_move_trigger : public ScriptedAI
|
||||
|
||||
@@ -271,9 +271,6 @@ public:
|
||||
piece->RemoveAllAuras();
|
||||
piece->setDeathState(DeathState::JustRespawned);
|
||||
piece->SetHealth(piece->GetMaxHealth());
|
||||
float x, y, z, o;
|
||||
piece->GetHomePosition(x, y, z, o);
|
||||
piece->NearTeleportTo(x, y, z, o);
|
||||
piece->AI()->DoAction(ACTION_CHESS_PIECE_RESET_ORIENTATION);
|
||||
piece->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
piece->AI()->Reset();
|
||||
|
||||
@@ -161,13 +161,13 @@ struct boss_zuljin : public BossAI
|
||||
Talk(SAY_AGGRO, 37s);
|
||||
|
||||
// Phase 1: Default (troll)
|
||||
ScheduleTimedEvent(7s, [&] {
|
||||
ScheduleTimedEvent(12s, 29s, [&] {
|
||||
DoCastAOE(SPELL_WHIRLWIND);
|
||||
}, 15s, 20s);
|
||||
}, 12s, 29s);
|
||||
|
||||
ScheduleTimedEvent(8s, [&] {
|
||||
ScheduleTimedEvent(7s, 23s, [&] {
|
||||
DoCastRandomTarget(SPELL_GRIEVOUS_THROW, 0, 100.0f);
|
||||
}, 10s);
|
||||
}, 7s, 23s);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&]() {
|
||||
DoCastSelf(SPELL_BERSERK, true);
|
||||
@@ -177,9 +177,9 @@ struct boss_zuljin : public BossAI
|
||||
// Phase 2: Bear Form.
|
||||
ScheduleHealthCheckEvent({ 80 }, [&] {
|
||||
EnterPhase(PHASE_BEAR);
|
||||
ScheduleTimedEvent(7s, [&] {
|
||||
ScheduleTimedEvent(8s, [&] {
|
||||
DoCastAOE(SPELL_CREEPING_PARALYSIS);
|
||||
}, 20s);
|
||||
}, 26s, 30s);
|
||||
|
||||
ScheduleTimedEvent(1s, [&] {
|
||||
if (!me->HasSpellCooldown(SPELL_OVERPOWER) && me->GetVictim() && me->GetComboPoints())
|
||||
@@ -229,17 +229,17 @@ struct boss_zuljin : public BossAI
|
||||
me->m_Events.CancelEventGroup(GROUP_LYNX);
|
||||
EnterPhase(PHASE_DRAGONHAWK);
|
||||
|
||||
ScheduleTimedEvent(5s, [&] {
|
||||
ScheduleTimedEvent(12s, 26s, [&] {
|
||||
DoCastSelf(SPELL_FLAME_WHIRL);
|
||||
}, 12s);
|
||||
}, 12s, 26s);
|
||||
|
||||
ScheduleTimedEvent(6s, [&] {
|
||||
ScheduleTimedEvent(11s, 42s, [&] {
|
||||
DoCastRandomTarget(SPELL_SUMMON_PILLAR);
|
||||
}, 10s);
|
||||
}, 5s, 25s);
|
||||
|
||||
ScheduleTimedEvent(7s, [&] {
|
||||
ScheduleTimedEvent(16s, 26s, [&] {
|
||||
DoCastAOE(SPELL_FLAME_BREATH);
|
||||
}, 10s);
|
||||
}, 6s, 25s);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -49,11 +49,15 @@ Position const HarrisonJonesLoc = {120.687f, 1674.0f, 42.0217f, 1.59044f};
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{ GO_ZULJIN_FIREWALL, DATA_ZULJIN, DOOR_TYPE_ROOM },
|
||||
{ GO_DOOR_HALAZZI, DATA_HALAZZI, DOOR_TYPE_PASSAGE },
|
||||
{ GO_LYNX_TEMPLE_ENTRANCE, DATA_HALAZZI, DOOR_TYPE_ROOM },
|
||||
{ GO_DOOR_AKILZON, DATA_AKILZON, DOOR_TYPE_ROOM },
|
||||
{ 0, 0, DOOR_TYPE_ROOM } // END
|
||||
{ GO_ZULJIN_FIREWALL, DATA_ZULJIN, DOOR_TYPE_ROOM },
|
||||
{ GO_DOOR_HALAZZI, DATA_HALAZZI, DOOR_TYPE_PASSAGE },
|
||||
{ GO_LYNX_TEMPLE_ENTRANCE, DATA_HALAZZI, DOOR_TYPE_ROOM },
|
||||
{ GO_DOOR_AKILZON, DATA_AKILZON, DOOR_TYPE_ROOM },
|
||||
{ GO_ALTAR_TORCH_EAGLE_GOD, DATA_AKILZON, DOOR_TYPE_PASSAGE },
|
||||
{ GO_ALTAR_TORCH_DRAGONHAWK_GOD, DATA_JANALAI, DOOR_TYPE_PASSAGE },
|
||||
{ GO_ALTAR_TORCH_LYNX_GOD, DATA_HALAZZI, DOOR_TYPE_PASSAGE },
|
||||
{ GO_ALTAR_TORCH_BEAR_GOD, DATA_NALORAKK, DOOR_TYPE_PASSAGE },
|
||||
{ 0, 0, DOOR_TYPE_ROOM } // END
|
||||
};
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
@@ -82,7 +86,12 @@ ObjectData const summonData[] =
|
||||
|
||||
BossBoundaryData const boundaries =
|
||||
{
|
||||
{ DATA_HEXLORD, new RectangleBoundary(80.50557f, 920.9858f, 155.88986f, 1015.27563f)}
|
||||
{ DATA_AKILZON, new ZRangeBoundary(72.0f, 100.0f)},
|
||||
{ DATA_HALAZZI, new RectangleBoundary(304.0f, 432.0f, 1052.0f, 1156.0f)},
|
||||
{ DATA_HEXLORD, new RectangleBoundary(80.50557f, 920.9858f, 155.88986f, 1015.27563f)},
|
||||
{ DATA_JANALAI, new ZRangeBoundary(16.0f, 46.0f)},
|
||||
{ DATA_NALORAKK, new ZRangeBoundary(38.0f, 68.0f)},
|
||||
{ DATA_ZULJIN, new ZRangeBoundary(43.0f, 73.0f)}
|
||||
};
|
||||
|
||||
class instance_zulaman : public InstanceMapScript
|
||||
@@ -103,6 +112,7 @@ public:
|
||||
LoadBossBoundaries(boundaries);
|
||||
LoadDoorData(doorData);
|
||||
LoadSummonData(summonData);
|
||||
_chestLooted = 0;
|
||||
|
||||
for (uint8 i = 0; i < RAND_VENDOR; ++i)
|
||||
RandVendor[i] = NOT_STARTED;
|
||||
@@ -200,6 +210,8 @@ public:
|
||||
else if (data == DONE)
|
||||
_akilzonGauntlet = DONE;
|
||||
}
|
||||
else if (type == DATA_CHEST_LOOTED)
|
||||
++_chestLooted;
|
||||
}
|
||||
|
||||
void StartAkilzonGauntlet()
|
||||
@@ -226,8 +238,12 @@ public:
|
||||
_akilzonGauntlet = NOT_STARTED;
|
||||
for (ObjectGuid guid : AkilzonTrash)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
{
|
||||
if (!creature->IsAlive())
|
||||
creature->Respawn();
|
||||
else if (creature->GetEntry() == NPC_AMINISHI_TEMPEST)
|
||||
creature->AI()->DoAction(ACTION_RESET_AKILZON_GAUNTLET);
|
||||
}
|
||||
if (Creature* creature = GetCreature(DATA_LOOKOUT))
|
||||
if (creature->isMoving())
|
||||
creature->Respawn(true);
|
||||
@@ -320,6 +336,8 @@ public:
|
||||
return RandVendor[1];
|
||||
else if (type == TYPE_AKILZON_GAUNTLET)
|
||||
return _akilzonGauntlet;
|
||||
else if (type == DATA_CHEST_LOOTED)
|
||||
return _chestLooted;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -330,6 +348,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
uint16 _chestLooted;
|
||||
uint32 RandVendor[RAND_VENDOR];
|
||||
GuidSet AkilzonTrash;
|
||||
EncounterState _akilzonGauntlet = NOT_STARTED;
|
||||
|
||||
@@ -290,13 +290,17 @@ public:
|
||||
|
||||
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
|
||||
creature->GetInstanceScript()->SetData(DATA_CHEST_LOOTED, 0);
|
||||
|
||||
float x, y, z;
|
||||
creature->GetPosition(x, y, z);
|
||||
for (uint8 i = 0; i < 4; ++i)
|
||||
{
|
||||
if (HostageEntry[i] == creature->GetEntry())
|
||||
{
|
||||
creature->SummonGameObject(ChestEntry[i], x - 2, y, z, 0, 0, 0, 0, 0, 0);
|
||||
GameObject* obj = creature->SummonGameObject(ChestEntry[i], x - 2, y, z, 0, 0, 0, 0, 0, 0);
|
||||
if (obj)
|
||||
obj->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -586,7 +590,6 @@ private:
|
||||
|
||||
enum AmanishiTempest
|
||||
{
|
||||
ACTION_START_GAUNTLET = 1,
|
||||
GROUP_AKILZON_GAUNTLET = 1,
|
||||
SPELL_SUMMON_EAGLE = 43487,
|
||||
SPELL_SUMMON_WARRIOR = 43486,
|
||||
@@ -601,6 +604,11 @@ struct npc_amanishi_tempest : public ScriptedAI
|
||||
{
|
||||
_summons.DespawnAll();
|
||||
scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
scheduler.CancelGroup(GROUP_AKILZON_GAUNTLET);
|
||||
scheduler.Schedule(9s, 11s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_THUNDERCLAP);
|
||||
@@ -623,8 +631,15 @@ struct npc_amanishi_tempest : public ScriptedAI
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_START_GAUNTLET)
|
||||
if (action == ACTION_START_AKILZON_GAUNTLET)
|
||||
ScheduleEvents();
|
||||
else if (action == ACTION_RESET_AKILZON_GAUNTLET)
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SummonedCreatureEvade(Creature* /*summon*/) override
|
||||
{
|
||||
EnterEvadeMode(EVADE_REASON_OTHER);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
@@ -635,7 +650,6 @@ struct npc_amanishi_tempest : public ScriptedAI
|
||||
|
||||
void ScheduleEvents()
|
||||
{
|
||||
me->SetInCombatWithZone();
|
||||
scheduler.Schedule(29s, 53s, GROUP_AKILZON_GAUNTLET, [this](TaskContext context)
|
||||
{
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
@@ -652,11 +666,6 @@ struct npc_amanishi_tempest : public ScriptedAI
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
if (!me->IsEngaged())
|
||||
return;
|
||||
Unit* victim = me->SelectVictim();
|
||||
if (!victim || me->GetExactDist(victim) > me->GetAggroRange(victim))
|
||||
return;
|
||||
ScriptedAI::UpdateAI(diff);
|
||||
}
|
||||
|
||||
@@ -665,26 +674,6 @@ private:
|
||||
SummonList _summons;
|
||||
};
|
||||
|
||||
struct npc_eagle_trash_aggro_trigger : public ScriptedAI
|
||||
{
|
||||
npc_eagle_trash_aggro_trigger(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) {}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (!me->IsWithinDist(who, 10.0f, false)) // distance not confirmed
|
||||
return;
|
||||
|
||||
Player* player = who->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if (!player || player->IsGameMaster())
|
||||
return;
|
||||
|
||||
if (_instance->GetData(TYPE_AKILZON_GAUNTLET) == NOT_STARTED)
|
||||
_instance->SetData(TYPE_AKILZON_GAUNTLET, IN_PROGRESS);
|
||||
}
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
void AddSC_zulaman()
|
||||
{
|
||||
RegisterZulAmanCreatureAI(npc_forest_frog);
|
||||
@@ -693,5 +682,4 @@ void AddSC_zulaman()
|
||||
RegisterSpellScript(spell_ritual_of_power);
|
||||
RegisterZulAmanCreatureAI(npc_amanishi_lookout);
|
||||
RegisterZulAmanCreatureAI(npc_amanishi_tempest);
|
||||
RegisterZulAmanCreatureAI(npc_eagle_trash_aggro_trigger);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ enum DataTypes
|
||||
DATA_HARRISON_JONES = 13,
|
||||
TYPE_AKILZON_GAUNTLET = 14,
|
||||
DATA_LOOKOUT = 15,
|
||||
DATA_ZULJIN_GATE = 16
|
||||
DATA_ZULJIN_GATE = 16,
|
||||
DATA_CHEST_LOOTED = 17 // Used for hostage loot DB conditions
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
@@ -79,7 +80,11 @@ enum GameobjectIds
|
||||
GO_TANZARS_TRUNK = 186648,
|
||||
GO_ASHLIS_BAG = 186672,
|
||||
GO_KRAZS_PACKAGE = 186667,
|
||||
GO_STRANGE_GONG = 187359
|
||||
GO_STRANGE_GONG = 187359,
|
||||
GO_ALTAR_TORCH_EAGLE_GOD = 187035,
|
||||
GO_ALTAR_TORCH_DRAGONHAWK_GOD = 187036,
|
||||
GO_ALTAR_TORCH_LYNX_GOD = 187037,
|
||||
GO_ALTAR_TORCH_BEAR_GOD = 186860
|
||||
};
|
||||
|
||||
enum MiscIds
|
||||
@@ -87,6 +92,7 @@ enum MiscIds
|
||||
DATA_TIMED_RUN = 0,
|
||||
ACTION_START_TIMED_RUN = 0,
|
||||
ACTION_START_AKILZON_GAUNTLET = 1,
|
||||
ACTION_RESET_AKILZON_GAUNTLET = 2,
|
||||
GROUP_TIMED_RUN = 1
|
||||
};
|
||||
|
||||
|
||||
@@ -190,6 +190,8 @@ public:
|
||||
|
||||
if (creature->IsSummon() && _bossWave != TO_BE_DECIDED)
|
||||
{
|
||||
if (_currentWave == 0)
|
||||
creature->SetDisableReputationGain(true);
|
||||
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, ++trash); // Update the instance wave count on new trash spawn
|
||||
_encounterNPCs.insert(creature->GetGUID()); // Used for despawning on wipe
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ class spell_mutate_explode_bug : public SpellScript
|
||||
if (target->GetEntry() != NPC_QIRAJI_SCARAB && target->GetEntry() != NPC_QIRAJI_SCORPION)
|
||||
return true;
|
||||
if (Creature const* creature = target->ToCreature())
|
||||
if (creature->HasAura(SPELL_EXPLODE_BUG) || creature->HasAura(SPELL_MUTATE_BUG))
|
||||
if (creature->HasAnyAuras(SPELL_EXPLODE_BUG, SPELL_MUTATE_BUG))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -473,7 +473,7 @@ public:
|
||||
{
|
||||
if (spell->Id == SPELL_KODO_KOMBO_ITEM)
|
||||
{
|
||||
if (!(caster->HasAura(SPELL_KODO_KOMBO_PLAYER_BUFF) || me->HasAura(SPELL_KODO_KOMBO_DESPAWN_BUFF))
|
||||
if (!caster->HasAnyAuras(SPELL_KODO_KOMBO_PLAYER_BUFF, SPELL_KODO_KOMBO_DESPAWN_BUFF)
|
||||
&& (me->GetEntry() == NPC_AGED_KODO || me->GetEntry() == NPC_DYING_KODO || me->GetEntry() == NPC_ANCIENT_KODO))
|
||||
{
|
||||
me->UpdateEntry(NPC_TAMED_KODO, nullptr, false);
|
||||
@@ -494,7 +494,7 @@ public:
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
if (player->HasAura(SPELL_KODO_KOMBO_PLAYER_BUFF) && creature->HasAura(SPELL_KODO_KOMBO_DESPAWN_BUFF))
|
||||
if (player->HasAllAuras(SPELL_KODO_KOMBO_PLAYER_BUFF, SPELL_KODO_KOMBO_DESPAWN_BUFF))
|
||||
{
|
||||
player->TalkedToCreature(creature->GetEntry(), ObjectGuid::Empty);
|
||||
player->RemoveAurasDueToSpell(SPELL_KODO_KOMBO_PLAYER_BUFF);
|
||||
|
||||
@@ -63,9 +63,9 @@ public:
|
||||
{
|
||||
pInstance = me->GetInstanceScript();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_RIMEFANG_GUID)))
|
||||
if (Creature* rimefang = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_RIMEFANG_GUID)))
|
||||
{
|
||||
c->SetCanFly(true);
|
||||
rimefang->SetCanFly(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,28 +76,27 @@ public:
|
||||
{
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
events.Reset();
|
||||
if (me->HasReactState(REACT_AGGRESSIVE)) // Reset() called by EnterEvadeMode()
|
||||
{
|
||||
if (!pInstance)
|
||||
return;
|
||||
if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_MARTIN_OR_GORKUN_GUID)))
|
||||
{
|
||||
c->AI()->DoAction(1);
|
||||
c->DespawnOrUnsummon();
|
||||
pInstance->SetGuidData(DATA_MARTIN_OR_GORKUN_GUID, ObjectGuid::Empty);
|
||||
}
|
||||
if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_RIMEFANG_GUID)))
|
||||
{
|
||||
c->GetMotionMaster()->Clear();
|
||||
c->GetMotionMaster()->MoveIdle();
|
||||
pInstance->SetData(DATA_TYRANNUS, NOT_STARTED);
|
||||
}
|
||||
|
||||
c->RemoveAllAuras();
|
||||
c->UpdatePosition(1017.3f, 168.974f, 642.926f, 5.2709f, true);
|
||||
c->StopMovingOnCurrentPos();
|
||||
if (Vehicle* v = c->GetVehicleKit())
|
||||
v->InstallAllAccessories(false);
|
||||
}
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
if (!pInstance)
|
||||
return;
|
||||
|
||||
if (Creature* creature = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_MARTIN_OR_GORKUN_GUID)))
|
||||
{
|
||||
creature->AI()->DoAction(1);
|
||||
creature->DespawnOrUnsummon();
|
||||
pInstance->SetGuidData(DATA_MARTIN_OR_GORKUN_GUID, ObjectGuid::Empty);
|
||||
}
|
||||
|
||||
// Tyrannus is temporarily spawned as Rimefang's rider. If he evades, despawn Rimefang.
|
||||
// Tyrannus will be respawned once Rimefang respawns.
|
||||
if (Creature* rimefang = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_RIMEFANG_GUID)))
|
||||
rimefang->DespawnOnEvade();
|
||||
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
@@ -140,7 +139,7 @@ public:
|
||||
if (TSDistCheckPos.GetExactDist(x, y, z) > 100.0f || z > TSDistCheckPos.GetPositionZ() + 20.0f || z < TSDistCheckPos.GetPositionZ() - 20.0f)
|
||||
{
|
||||
me->SetHealth(me->GetMaxHealth());
|
||||
EnterEvadeMode();
|
||||
EnterEvadeMode(EVADE_REASON_OTHER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ enum Spells
|
||||
SPELL_FRENZIED_BLOODTHIRST_VISUAL = 71949,
|
||||
SPELL_VAMPIRIC_BITE = 71726,
|
||||
SPELL_VAMPIRIC_BITE_DUMMY = 71837,
|
||||
SPELL_ESSENCE_OF_BLOOD_QUEEN = 70867,
|
||||
SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR = 70879,
|
||||
SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL = 70872,
|
||||
SPELL_FRENZIED_BLOODTHIRST = 70877,
|
||||
@@ -79,25 +80,10 @@ enum Shadowmourne
|
||||
SPELL_THIRST_QUENCHED = 72154,
|
||||
};
|
||||
|
||||
#define ESSENCE_OF_BLOOD_QUEEN RAID_MODE<uint32>(70867, 71473, 71532, 71533)
|
||||
#define ESSENCE_OF_BLOOD_QUEEN_PLR RAID_MODE<uint32>(70879, 71525, 71530, 71531)
|
||||
#define FRENZIED_BLOODTHIRST RAID_MODE<uint32>(70877, 71474, 70877, 71474)
|
||||
#define DELIRIOUS_SLASH RAID_MODE<uint32>(71623, 71624, 71625, 71626)
|
||||
#define PRESENCE_OF_THE_DARKFALLEN RAID_MODE<uint32>(70994, 71962, 71963, 71964)
|
||||
|
||||
uint32 const vampireAuras[3][MAX_DIFFICULTY] =
|
||||
{
|
||||
{70867, 71473, 71532, 71533},
|
||||
{70879, 71525, 71530, 71531},
|
||||
{70877, 71474, 70877, 71474},
|
||||
};
|
||||
|
||||
bool IsVampire(Unit const* unit)
|
||||
{
|
||||
uint8 spawnMode = unit->GetMap()->GetSpawnMode();
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
if (unit->HasAura(vampireAuras[i][spawnMode]))
|
||||
return true;
|
||||
if (unit->HasAnyAuras(SPELL_ESSENCE_OF_BLOOD_QUEEN, SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, SPELL_FRENZIED_BLOODTHIRST))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -134,6 +120,31 @@ Position const centerPos = {4595.7090f, 2769.4190f, 400.6368f, 0.000000f};
|
||||
Position const airPos = {4595.7090f, 2769.4190f, 422.3893f, 0.000000f};
|
||||
Position const mincharPos = {4629.3711f, 2782.6089f, 424.6390f, 0.000000f};
|
||||
|
||||
struct VampiricBiteTargetSelector
|
||||
{
|
||||
public:
|
||||
VampiricBiteTargetSelector(Creature* source) : _source(source) { }
|
||||
bool operator()(Unit const* target) const
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (!target->IsPlayer())
|
||||
return false;
|
||||
|
||||
if (target->HasAura(SPELL_BLOOD_MIRROR_DAMAGE))
|
||||
return false;
|
||||
|
||||
if (IsVampire(target))
|
||||
return false;
|
||||
|
||||
return target != _source->GetVictim();
|
||||
}
|
||||
|
||||
private:
|
||||
Creature const* _source;
|
||||
};
|
||||
|
||||
class boss_blood_queen_lana_thel : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -327,22 +338,7 @@ public:
|
||||
break;
|
||||
case EVENT_VAMPIRIC_BITE:
|
||||
{
|
||||
Player* target = nullptr;
|
||||
float maxThreat = 0.0f;
|
||||
const Map::PlayerList& pl = me->GetMap()->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
|
||||
if (Player* p = itr->GetSource())
|
||||
if (p->IsAlive() && p != me->GetVictim() && p->GetGUID() != _offtankGUID && !p->IsGameMaster() && p->GetDistance(me) < 70.0f)
|
||||
{
|
||||
float th = me->GetThreatMgr().getThreatWithoutTemp(p);
|
||||
if (!target || th > maxThreat)
|
||||
{
|
||||
target = p;
|
||||
maxThreat = th;
|
||||
}
|
||||
}
|
||||
|
||||
if (target)
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, VampiricBiteTargetSelector(me)))
|
||||
{
|
||||
me->CastSpell(target, SPELL_VAMPIRIC_BITE, false);
|
||||
me->CastSpell((Unit*)nullptr, SPELL_VAMPIRIC_BITE_DUMMY, true);
|
||||
@@ -513,17 +509,17 @@ public:
|
||||
|
||||
void CleanAuras()
|
||||
{
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(ESSENCE_OF_BLOOD_QUEEN);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(ESSENCE_OF_BLOOD_QUEEN_PLR);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(FRENZIED_BLOODTHIRST);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_ESSENCE_OF_BLOOD_QUEEN);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FRENZIED_BLOODTHIRST);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FRENZIED_BLOODTHIRST_VISUAL);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_UNCONTROLLABLE_FRENZY);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLOOD_MIRROR_DAMAGE);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLOOD_MIRROR_VISUAL);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLOOD_MIRROR_DUMMY);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(DELIRIOUS_SLASH);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_DELIRIOUS_SLASH);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PACT_OF_THE_DARKFALLEN);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(PRESENCE_OF_THE_DARKFALLEN);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PRESENCE_OF_THE_DARKFALLEN_DUMMY);
|
||||
}
|
||||
|
||||
bool WasVampire(ObjectGuid guid)
|
||||
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
if (target->HasAura(SPELL_FROST_IMBUED_BLADE))
|
||||
return false;
|
||||
|
||||
if (target->IsImmunedToDamageOrSchool(SPELL_SCHOOL_MASK_ALL) || target->HasAura(SPELL_ICE_TOMB_UNTARGETABLE) || target->HasAura(SPELL_ICE_TOMB_DAMAGE) || target->HasAura(SPELL_TANK_MARKER_AURA) || target->HasSpiritOfRedemptionAura())
|
||||
if (target->IsImmunedToDamageOrSchool(SPELL_SCHOOL_MASK_ALL) || target->HasAnyAuras(SPELL_ICE_TOMB_UNTARGETABLE, SPELL_ICE_TOMB_DAMAGE, SPELL_TANK_MARKER_AURA) || target->HasSpiritOfRedemptionAura())
|
||||
return false;
|
||||
|
||||
return target != _source->GetVictim();
|
||||
|
||||
@@ -451,7 +451,7 @@ public:
|
||||
return false;
|
||||
if (_source->GetExactDist(target) > 100.0f)
|
||||
return false;
|
||||
if (target->HasAura(SPELL_HARVEST_SOUL_VALKYR) || target->HasAura(SPELL_VALKYR_TARGET_SEARCH))
|
||||
if (target->HasAnyAuras(SPELL_HARVEST_SOUL_VALKYR, SPELL_VALKYR_TARGET_SEARCH))
|
||||
return false;
|
||||
if (!_source->IsWithinLOSInMap(target))
|
||||
return false;
|
||||
@@ -603,7 +603,7 @@ public:
|
||||
{
|
||||
if (!unit || !unit->IsPlayer() || unit == _sourceObj || _sourceObj->GetVictim() == unit || !unit->isTargetableForAttack())
|
||||
return false;
|
||||
if (unit->HasAura(SPELL_PLAGUE_AVOIDANCE) || unit->HasAura(SPELL_BOSS_HITTIN_YA_AURA) || unit->HasAura(_notAura1) || unit->HasAura(_notAura2))
|
||||
if (unit->HasAnyAuras(SPELL_PLAGUE_AVOIDANCE, SPELL_BOSS_HITTIN_YA_AURA, _notAura1, _notAura2))
|
||||
return false;
|
||||
if (!_sourceObj->IsWithinLOSInMap(unit))
|
||||
return false;
|
||||
|
||||
@@ -1835,7 +1835,7 @@ public:
|
||||
{
|
||||
if (InstanceScript* instance = creature->GetInstanceScript())
|
||||
if (instance->GetBossState(DATA_ROTFACE) == DONE && instance->GetBossState(DATA_FESTERGUT) == DONE && !creature->FindCurrentSpellBySpellId(SPELL_HARVEST_BLIGHT_SPECIMEN) && !creature->FindCurrentSpellBySpellId(SPELL_HARVEST_BLIGHT_SPECIMEN25))
|
||||
if (player->HasAura(SPELL_ORANGE_BLIGHT_RESIDUE) && player->HasAura(SPELL_GREEN_BLIGHT_RESIDUE))
|
||||
if (player->HasAllAuras(SPELL_ORANGE_BLIGHT_RESIDUE, SPELL_GREEN_BLIGHT_RESIDUE))
|
||||
creature->CastSpell(creature, SPELL_HARVEST_BLIGHT_SPECIMEN, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public:
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasAura(SPELL_PLANAR_SHIFT) || me->HasAura(SPELL_DRAKE_STOP_TIME))
|
||||
if (me->HasAnyAuras(SPELL_PLANAR_SHIFT, SPELL_DRAKE_STOP_TIME))
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
@@ -1527,7 +1527,7 @@ public:
|
||||
|
||||
bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override
|
||||
{
|
||||
return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_10);
|
||||
return player && player->HasAllAuras(SPELL_MAGE_TOASTY_FIRE_AURA, SPELL_DRUID_STARLIGHT_AREA_AURA, SPELL_SHAMAN_STORM_POWER_10);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1538,7 +1538,7 @@ public:
|
||||
|
||||
bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override
|
||||
{
|
||||
return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_25);
|
||||
return player && player->HasAllAuras(SPELL_MAGE_TOASTY_FIRE_AURA, SPELL_DRUID_STARLIGHT_AREA_AURA, SPELL_SHAMAN_STORM_POWER_25);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -454,8 +454,7 @@ public:
|
||||
|
||||
if (!player || player->IsGameMaster() || player->IsBeingTeleported() || (player->GetPositionZ() > 670 && player->GetVehicle()) ||
|
||||
// If player has Disguise aura for quest A Meeting With The Magister or An Audience With The Arcanist, do not teleport it away but let it pass
|
||||
player->HasAura(SPELL_SUNREAVER_DISGUISE_FEMALE) || player->HasAura(SPELL_SUNREAVER_DISGUISE_MALE) ||
|
||||
player->HasAura(SPELL_SILVER_COVENANT_DISGUISE_FEMALE) || player->HasAura(SPELL_SILVER_COVENANT_DISGUISE_MALE))
|
||||
player->HasAnyAuras(SPELL_SUNREAVER_DISGUISE_FEMALE, SPELL_SUNREAVER_DISGUISE_MALE, SPELL_SILVER_COVENANT_DISGUISE_FEMALE, SPELL_SILVER_COVENANT_DISGUISE_MALE))
|
||||
return;
|
||||
|
||||
switch (me->GetEntry())
|
||||
|
||||
@@ -1496,7 +1496,7 @@ public:
|
||||
if (!who || !who->IsPlayer() || !me->IsHostileTo(who) || !me->isInBackInMap(who, 5.0f))
|
||||
return;
|
||||
|
||||
if (who->HasAura(SPELL_TRESPASSER_H) || who->HasAura(SPELL_TRESPASSER_A))
|
||||
if (who->HasAnyAuras(SPELL_TRESPASSER_H, SPELL_TRESPASSER_A))
|
||||
return;
|
||||
|
||||
if (who->ToPlayer()->GetTeamId() == TEAM_ALLIANCE)
|
||||
|
||||
+22
-26
@@ -26,14 +26,6 @@
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{ GO_LADY_VASHJ_BRIDGE_CONSOLE, DATA_BRIDGE_EMERGED, DOOR_TYPE_PASSAGE },
|
||||
{ GO_COILFANG_BRIDGE1, DATA_BRIDGE_EMERGED, DOOR_TYPE_PASSAGE },
|
||||
{ GO_COILFANG_BRIDGE2, DATA_BRIDGE_EMERGED, DOOR_TYPE_PASSAGE },
|
||||
{ GO_COILFANG_BRIDGE3, DATA_BRIDGE_EMERGED, DOOR_TYPE_PASSAGE }
|
||||
};
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_LEOTHERAS_THE_BLIND, DATA_LEOTHERAS_THE_BLIND },
|
||||
@@ -45,8 +37,12 @@ ObjectData const creatureData[] =
|
||||
|
||||
ObjectData const gameObjectData[] =
|
||||
{
|
||||
{ GO_STRANGE_POOL, DATA_STRANGE_POOL },
|
||||
{ 0, 0 }
|
||||
{ GO_STRANGE_POOL, DATA_STRANGE_POOL },
|
||||
{ GO_LADY_VASHJ_BRIDGE_CONSOLE, DATA_CONSOLE },
|
||||
{ GO_COILFANG_BRIDGE1, DATA_BRIDGE_PART1 },
|
||||
{ GO_COILFANG_BRIDGE2, DATA_BRIDGE_PART2 },
|
||||
{ GO_COILFANG_BRIDGE3, DATA_BRIDGE_PART3 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
MinionData const minionData[] =
|
||||
@@ -64,6 +60,15 @@ BossBoundaryData const boundaries =
|
||||
{ DATA_LADY_VASHJ, new CircleBoundary(Position(29.99f, -922.409f), 83.65f) }
|
||||
};
|
||||
|
||||
ObjectData const summonData[] =
|
||||
{
|
||||
{ NPC_ENCHANTED_ELEMENTAL, DATA_LADY_VASHJ },
|
||||
{ NPC_COILFANG_ELITE, DATA_LADY_VASHJ },
|
||||
{ NPC_COILFANG_STRIDER, DATA_LADY_VASHJ },
|
||||
{ NPC_TAINTED_ELEMENTAL, DATA_LADY_VASHJ },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
class instance_serpent_shrine : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -77,10 +82,10 @@ public:
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(MAX_ENCOUNTERS);
|
||||
LoadDoorData(doorData);
|
||||
LoadObjectData(creatureData, gameObjectData);
|
||||
LoadMinionData(minionData);
|
||||
LoadBossBoundaries(boundaries);
|
||||
LoadSummonData(summonData);
|
||||
|
||||
_aliveKeepersCount = 0;
|
||||
}
|
||||
@@ -108,6 +113,12 @@ public:
|
||||
case GO_SHIELD_GENERATOR4:
|
||||
_shieldGeneratorGUID[go->GetEntry() - GO_SHIELD_GENERATOR1] = go->GetGUID();
|
||||
break;
|
||||
case GO_LADY_VASHJ_BRIDGE_CONSOLE:
|
||||
case GO_COILFANG_BRIDGE1:
|
||||
case GO_COILFANG_BRIDGE2:
|
||||
case GO_COILFANG_BRIDGE3:
|
||||
go->AllowSaveToDB(true);
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnGameObjectCreate(go);
|
||||
@@ -125,13 +136,6 @@ public:
|
||||
case NPC_CYCLONE_KARATHRESS:
|
||||
creature->GetMotionMaster()->MoveRandom(50.0f);
|
||||
break;
|
||||
case NPC_ENCHANTED_ELEMENTAL:
|
||||
case NPC_COILFANG_ELITE:
|
||||
case NPC_COILFANG_STRIDER:
|
||||
case NPC_TAINTED_ELEMENTAL:
|
||||
if (Creature* vashj = GetCreature(DATA_LADY_VASHJ))
|
||||
vashj->AI()->JustSummoned(creature);
|
||||
break;
|
||||
case NPC_SEER_OLUM:
|
||||
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
creature->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
|
||||
@@ -148,19 +152,11 @@ public:
|
||||
{
|
||||
case DATA_PLATFORM_KEEPER_RESPAWNED:
|
||||
if (_aliveKeepersCount < MAX_KEEPER_COUNT)
|
||||
{
|
||||
++_aliveKeepersCount;
|
||||
}
|
||||
break;
|
||||
case DATA_PLATFORM_KEEPER_DIED:
|
||||
if (_aliveKeepersCount > MIN_KEEPER_COUNT)
|
||||
{
|
||||
--_aliveKeepersCount;
|
||||
}
|
||||
break;
|
||||
case DATA_BRIDGE_ACTIVATED:
|
||||
SetBossState(DATA_BRIDGE_EMERGED, NOT_STARTED);
|
||||
SetBossState(DATA_BRIDGE_EMERGED, DONE);
|
||||
break;
|
||||
case DATA_ACTIVATE_SHIELD:
|
||||
if (Creature* vashj = GetCreature(DATA_LADY_VASHJ))
|
||||
|
||||
@@ -31,17 +31,19 @@ enum DataTypes
|
||||
DATA_LEOTHERAS_THE_BLIND = 2,
|
||||
DATA_FATHOM_LORD_KARATHRESS = 3,
|
||||
DATA_MOROGRIM_TIDEWALKER = 4,
|
||||
DATA_BRIDGE_EMERGED = 5,
|
||||
DATA_LADY_VASHJ = 6,
|
||||
MAX_ENCOUNTERS = 7,
|
||||
DATA_LADY_VASHJ = 5,
|
||||
MAX_ENCOUNTERS = 6,
|
||||
|
||||
DATA_PLATFORM_KEEPER_RESPAWNED = 20,
|
||||
DATA_PLATFORM_KEEPER_DIED = 21,
|
||||
DATA_ALIVE_KEEPERS = 22,
|
||||
DATA_BRIDGE_ACTIVATED = 23,
|
||||
DATA_ACTIVATE_SHIELD = 24,
|
||||
DATA_STRANGE_POOL = 25,
|
||||
DATA_SEER_OLUM = 26
|
||||
DATA_ACTIVATE_SHIELD = 23,
|
||||
DATA_STRANGE_POOL = 24,
|
||||
DATA_SEER_OLUM = 25,
|
||||
DATA_CONSOLE = 26, // Used by the console SAI.
|
||||
DATA_BRIDGE_PART1 = 27, // Used by the console SAI.
|
||||
DATA_BRIDGE_PART2 = 28, // Used by the console SAI.
|
||||
DATA_BRIDGE_PART3 = 29 // Used by the console SAI.
|
||||
};
|
||||
|
||||
enum SSNPCs
|
||||
@@ -91,8 +93,8 @@ enum SSSpells
|
||||
|
||||
enum KeeperCount
|
||||
{
|
||||
MIN_KEEPER_COUNT = 0,
|
||||
MAX_KEEPER_COUNT = 24
|
||||
MIN_KEEPER_COUNT = 0,
|
||||
MAX_KEEPER_COUNT = 24
|
||||
};
|
||||
|
||||
template <class AI, class T>
|
||||
|
||||
@@ -416,7 +416,7 @@ public:
|
||||
|
||||
bool OnGossipHello(Player* player, GameObject* /*go*/) override
|
||||
{
|
||||
if (player->HasAura(SPELL_MIND_EXHAUSTION) || player->HasAura(SPELL_SHADOW_GRASP))
|
||||
if (player->HasAnyAuras(SPELL_MIND_EXHAUSTION, SPELL_SHADOW_GRASP))
|
||||
return true;
|
||||
|
||||
if (Creature* trigger = player->FindNearestCreature(NPC_HELLFIRE_RAID_TRIGGER, 10.0f))
|
||||
|
||||
@@ -303,10 +303,6 @@ public:
|
||||
{
|
||||
CombatAI::InitializeAI();
|
||||
((Minion*)me)->SetFollowAngle(rand_norm() * 2 * M_PI);
|
||||
|
||||
// Heroism / Bloodlust immunity
|
||||
me->ApplySpellImmune(0, IMMUNITY_ID, 32182, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_ID, 2825, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -751,8 +751,8 @@ class spell_dk_pet_scaling : public AuraScript
|
||||
// Check just if owner has Ravenous Dead since it's effect is not an aura
|
||||
if (AuraEffect const* rdEff = owner->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DEATHKNIGHT, 3010, 0))
|
||||
{
|
||||
SpellInfo const* spellInfo = rdEff->GetSpellInfo(); // Then get the SpellProto and add the dummy effect value
|
||||
AddPct(modifier, spellInfo->Effects[EFFECT_1].CalcValue()); // Ravenous Dead edits the original scale
|
||||
SpellInfo const* spellInfo = rdEff->GetSpellInfo(); // Then get the SpellProto and add the dummy effect value
|
||||
AddPct(modifier, spellInfo->Effects[EFFECT_1].CalcValue()); // Ravenous Dead edits the original scale
|
||||
}
|
||||
|
||||
// xinef: Glyph of the Ghoul
|
||||
@@ -1618,7 +1618,7 @@ class spell_dk_improved_blood_presence : public AuraScript
|
||||
void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if ((target->HasAura(SPELL_DK_FROST_PRESENCE) || target->HasAura(SPELL_DK_UNHOLY_PRESENCE)) && !target->HasAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED))
|
||||
if (target->HasAnyAuras(SPELL_DK_FROST_PRESENCE, SPELL_DK_UNHOLY_PRESENCE) && !target->HasAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED))
|
||||
target->CastCustomSpell(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED, SPELLVALUE_BASE_POINT1, aurEff->GetAmount(), target, true, nullptr, aurEff);
|
||||
}
|
||||
|
||||
@@ -1655,7 +1655,7 @@ class spell_dk_improved_frost_presence : public AuraScript
|
||||
void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if ((target->HasAura(SPELL_DK_BLOOD_PRESENCE) || target->HasAura(SPELL_DK_UNHOLY_PRESENCE)) && !target->HasAura(SPELL_DK_FROST_PRESENCE_TRIGGERED))
|
||||
if (target->HasAnyAuras(SPELL_DK_BLOOD_PRESENCE, SPELL_DK_UNHOLY_PRESENCE) && !target->HasAura(SPELL_DK_FROST_PRESENCE_TRIGGERED))
|
||||
target->CastCustomSpell(SPELL_DK_FROST_PRESENCE_TRIGGERED, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), target, true, nullptr, aurEff);
|
||||
}
|
||||
|
||||
@@ -1700,7 +1700,7 @@ class spell_dk_improved_unholy_presence : public AuraScript
|
||||
target->CastCustomSpell(target, SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED, &basePoints, &basePoints, &basePoints, true, nullptr, aurEff);
|
||||
}
|
||||
|
||||
if ((target->HasAura(SPELL_DK_BLOOD_PRESENCE) || target->HasAura(SPELL_DK_FROST_PRESENCE)) && !target->HasAura(SPELL_DK_UNHOLY_PRESENCE_TRIGGERED))
|
||||
if (target->HasAnyAuras(SPELL_DK_BLOOD_PRESENCE, SPELL_DK_FROST_PRESENCE) && !target->HasAura(SPELL_DK_UNHOLY_PRESENCE_TRIGGERED))
|
||||
target->CastCustomSpell(SPELL_DK_UNHOLY_PRESENCE_TRIGGERED, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), target, true, nullptr, aurEff);
|
||||
}
|
||||
|
||||
@@ -2203,6 +2203,72 @@ class spell_dk_will_of_the_necropolis : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 49040 - Army of the Dead Passive
|
||||
class spell_dk_army_of_the_dead_passive : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_dk_army_of_the_dead_passive);
|
||||
|
||||
void CalculateAPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
// army ghoul inherits 6.5% of AP
|
||||
if (Unit* owner = GetUnitOwner()->GetOwner())
|
||||
amount = CalculatePct(std::max<int32>(0, owner->GetTotalAttackPowerValue(BASE_ATTACK)), 6.5f);
|
||||
}
|
||||
|
||||
void CalculateHealthAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
// army ghoul inherits 20% of health
|
||||
if (Unit* owner = GetUnitOwner()->GetOwner())
|
||||
amount = owner->CountPctFromMaxHealth(20);
|
||||
}
|
||||
|
||||
void CalculateSPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
// army ghoul inherits 6.5% of AP
|
||||
if (Unit* owner = GetUnitOwner()->GetOwner())
|
||||
amount = CalculatePct(std::max<int32>(0, owner->GetTotalAttackPowerValue(BASE_ATTACK)), 6.5f);
|
||||
}
|
||||
|
||||
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetUnitOwner()->IsPet())
|
||||
return;
|
||||
|
||||
GetUnitOwner()->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STAT, true, SPELL_BLOCK_TYPE_POSITIVE);
|
||||
GetUnitOwner()->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, SPELL_BLOCK_TYPE_POSITIVE);
|
||||
GetUnitOwner()->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_ATTACK_POWER, true, SPELL_BLOCK_TYPE_POSITIVE);
|
||||
GetUnitOwner()->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_ATTACK_POWER_PCT, true, SPELL_BLOCK_TYPE_POSITIVE);
|
||||
// Heroism / Bloodlust immunity
|
||||
GetUnitOwner()->ApplySpellImmune(0, IMMUNITY_ID, 32182, true);
|
||||
GetUnitOwner()->ApplySpellImmune(0, IMMUNITY_ID, 2825, true);
|
||||
}
|
||||
|
||||
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude)
|
||||
{
|
||||
if (!GetUnitOwner()->IsPet())
|
||||
return;
|
||||
|
||||
isPeriodic = true;
|
||||
amplitude = 2 * IN_MILLISECONDS;
|
||||
}
|
||||
|
||||
void HandlePeriodic(AuraEffect const* aurEff)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
GetEffect(aurEff->GetEffIndex())->RecalculateAmount();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_army_of_the_dead_passive::CalculateAPAmount, EFFECT_0, SPELL_AURA_MOD_ATTACK_POWER);
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_army_of_the_dead_passive::CalculateHealthAmount, EFFECT_1, SPELL_AURA_MOD_INCREASE_HEALTH);
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_army_of_the_dead_passive::CalculateSPAmount, EFFECT_2, SPELL_AURA_MOD_DAMAGE_DONE);
|
||||
OnEffectApply += AuraEffectApplyFn(spell_dk_army_of_the_dead_passive::HandleEffectApply, EFFECT_ALL, SPELL_AURA_ANY, AURA_EFFECT_HANDLE_REAL);
|
||||
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_dk_army_of_the_dead_passive::CalcPeriodic, EFFECT_ALL, SPELL_AURA_ANY);
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_dk_army_of_the_dead_passive::HandlePeriodic, EFFECT_ALL, SPELL_AURA_ANY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_deathknight_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_dk_wandering_plague);
|
||||
@@ -2250,4 +2316,5 @@ void AddSC_deathknight_spell_scripts()
|
||||
RegisterSpellScript(spell_dk_vampiric_blood);
|
||||
RegisterSpellScript(spell_dk_will_of_the_necropolis);
|
||||
RegisterSpellScript(spell_dk_ghoul_thrash);
|
||||
RegisterSpellScript(spell_dk_army_of_the_dead_passive);
|
||||
}
|
||||
|
||||
@@ -5320,6 +5320,65 @@ class spell_gen_set_health : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 67561 - Serverside - Pet Scaling - Master Spell 06 - Spell Hit, Expertise, Spell Penetration
|
||||
class spell_pet_spellhit_expertise_spellpen_scaling : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_pet_spellhit_expertise_spellpen_scaling)
|
||||
|
||||
int32 CalculatePercent(float hitChance, float cap, float maxChance)
|
||||
{
|
||||
return (hitChance / cap) * maxChance;
|
||||
}
|
||||
|
||||
void CalculateSpellHitAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
|
||||
amount = CalculatePercent(modOwner->m_modMeleeHitChance, 8.0f, 17.0f);
|
||||
}
|
||||
|
||||
void CalculateExpertiseAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
|
||||
amount = CalculatePercent(modOwner->m_modMeleeHitChance, 8.0f, 26.0f);
|
||||
}
|
||||
|
||||
void CalculateSpellPenAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
if (Player* modOwner = GetUnitOwner()->GetSpellModOwner())
|
||||
amount = modOwner->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_SPELL);
|
||||
}
|
||||
|
||||
void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
GetUnitOwner()->ApplySpellImmune(GetId(), IMMUNITY_STATE, aurEff->GetAuraType(), true, SPELL_BLOCK_TYPE_POSITIVE);
|
||||
}
|
||||
|
||||
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude)
|
||||
{
|
||||
if (!GetUnitOwner()->IsPet())
|
||||
return;
|
||||
|
||||
isPeriodic = true;
|
||||
amplitude = 3 * IN_MILLISECONDS;
|
||||
}
|
||||
|
||||
void HandlePeriodic(AuraEffect const* aurEff)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
GetEffect(aurEff->GetEffIndex())->RecalculateAmount();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pet_spellhit_expertise_spellpen_scaling::CalculateSpellHitAmount, EFFECT_0, SPELL_AURA_MOD_SPELL_HIT_CHANCE);
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pet_spellhit_expertise_spellpen_scaling::CalculateExpertiseAmount, EFFECT_1, SPELL_AURA_MOD_EXPERTISE);
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pet_spellhit_expertise_spellpen_scaling::CalculateSpellPenAmount, EFFECT_2, SPELL_AURA_MOD_TARGET_RESISTANCE);
|
||||
OnEffectApply += AuraEffectApplyFn(spell_pet_spellhit_expertise_spellpen_scaling::HandleEffectApply, EFFECT_ALL, SPELL_AURA_ANY, AURA_EFFECT_HANDLE_REAL);
|
||||
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_pet_spellhit_expertise_spellpen_scaling::CalcPeriodic, EFFECT_ALL, SPELL_AURA_ANY);
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_pet_spellhit_expertise_spellpen_scaling::HandlePeriodic, EFFECT_ALL, SPELL_AURA_ANY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_generic_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_silithyst);
|
||||
@@ -5478,4 +5537,5 @@ void AddSC_generic_spell_scripts()
|
||||
RegisterSpellScript(spell_gen_sober_up);
|
||||
RegisterSpellScript(spell_gen_steal_weapon);
|
||||
RegisterSpellScript(spell_gen_set_health);
|
||||
RegisterSpellScript(spell_pet_spellhit_expertise_spellpen_scaling);
|
||||
}
|
||||
|
||||
@@ -969,7 +969,7 @@ class spell_pal_lay_on_hands : public SpellScript
|
||||
Unit* caster = GetCaster();
|
||||
if (Unit* target = GetExplTargetUnit())
|
||||
if (caster == target)
|
||||
if (target->HasAura(SPELL_PALADIN_FORBEARANCE) || target->HasAura(SPELL_PALADIN_AVENGING_WRATH_MARKER) || target->HasAura(SPELL_PALADIN_IMMUNE_SHIELD_MARKER))
|
||||
if (target->HasAnyAuras(SPELL_PALADIN_FORBEARANCE, SPELL_PALADIN_AVENGING_WRATH_MARKER, SPELL_PALADIN_IMMUNE_SHIELD_MARKER))
|
||||
return SPELL_FAILED_TARGET_AURASTATE;
|
||||
|
||||
// Xinef: Glyph of Divinity
|
||||
|
||||
@@ -267,7 +267,7 @@ class achievement_flirt_with_disaster_perf_check : public AchievementCriteriaScr
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
if (player->HasAura(AURA_PERFUME_FOREVER) || player->HasAura(AURA_PERFUME_ENCHANTRESS) || player->HasAura(AURA_PERFUME_VICTORY))
|
||||
if (player->HasAnyAuras(AURA_PERFUME_FOREVER, AURA_PERFUME_ENCHANTRESS, AURA_PERFUME_VICTORY))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -774,7 +774,7 @@ public:
|
||||
{
|
||||
// return those not tagged or already under the influence of Aura of Nature
|
||||
if (Unit* unit = object->ToUnit())
|
||||
return !(unit->HasAura(SPELL_MARK_OF_NATURE) && !unit->HasAura(SPELL_AURA_OF_NATURE));
|
||||
return !unit->HasAllAuras(SPELL_MARK_OF_NATURE, SPELL_AURA_OF_NATURE);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -999,14 +999,10 @@ public:
|
||||
void SpellHit(Unit* /*Caster*/, SpellInfo const* Spell) override
|
||||
{
|
||||
if (InNormalForm())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (me->HasAura(NELSON_SPELL_SOUL_FLAME) && me->HasAura(NELSON_WEAKNESS_FROST_TRAP))
|
||||
{
|
||||
if (me->HasAllAuras(NELSON_SPELL_SOUL_FLAME, NELSON_WEAKNESS_FROST_TRAP))
|
||||
me->RemoveAura(NELSON_SPELL_SOUL_FLAME);
|
||||
}
|
||||
|
||||
if (!me->HasAura(NELSON_SPELL_CRIPPLING_CLIP) && Spell->Id == NELSON_WEAKNESS_WING_CLIP)
|
||||
{
|
||||
|
||||
@@ -179,7 +179,7 @@ protected:
|
||||
{
|
||||
LOG_DEBUG("misc", "Network Thread Starting");
|
||||
|
||||
_updateTimer.expires_at(std::chrono::steady_clock::now());
|
||||
_updateTimer.expires_at(std::chrono::steady_clock::now() + std::chrono::milliseconds(1));
|
||||
_updateTimer.async_wait([this](boost::system::error_code const&) { Update(); });
|
||||
_ioContext.run();
|
||||
|
||||
@@ -193,7 +193,7 @@ protected:
|
||||
if (_stopped)
|
||||
return;
|
||||
|
||||
_updateTimer.expires_at(std::chrono::steady_clock::now());
|
||||
_updateTimer.expires_at(std::chrono::steady_clock::now() + std::chrono::milliseconds(1));
|
||||
_updateTimer.async_wait([this](boost::system::error_code const&) { Update(); });
|
||||
|
||||
AddNewSockets();
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
#include "RealmList.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "Resolver.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Resolver.h"
|
||||
#include "SteadyTimer.h"
|
||||
#include "Util.h"
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <memory>
|
||||
@@ -227,9 +228,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
|
||||
|
||||
if (_updateInterval)
|
||||
{
|
||||
// Calculate the expiration time _updateInterval from now
|
||||
auto expiration_time = std::chrono::steady_clock::now() + std::chrono::seconds(_updateInterval);
|
||||
_updateTimer->expires_at(expiration_time);
|
||||
_updateTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(_updateInterval));
|
||||
_updateTimer->async_wait([this](boost::system::error_code const& errorCode){ UpdateRealms(errorCode); });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user