Merge branch 'master' into test-staging
This commit is contained in:
@@ -621,6 +621,15 @@ Allow.IP.Based.Action.Logging = 0
|
||||
|
||||
LogSpamReports = 1
|
||||
|
||||
#
|
||||
# ChatLog.Enable
|
||||
# Description: Enable or disable chat logging (chat_log.cpp).
|
||||
# Default: 0 - (Disabled)
|
||||
# 1 - (Enabled)
|
||||
#
|
||||
|
||||
ChatLog.Enable = 0
|
||||
|
||||
#
|
||||
# Appender config values: Given an appender "name"
|
||||
# Appender.name
|
||||
@@ -2608,6 +2617,14 @@ DurabilityLoss.InPvP = 0
|
||||
|
||||
DurabilityLoss.OnDeath = 10
|
||||
|
||||
#
|
||||
# DurabilityLoss.OnSpiritResurrect
|
||||
# Description: Durability loss percentage on spirit healer resurrection. Does not effect PvP
|
||||
# spirit healers.
|
||||
# Default: 25
|
||||
|
||||
DurabilityLoss.OnSpiritResurrect = 25
|
||||
|
||||
#
|
||||
# DurabilityLossChance.Damage
|
||||
# Description: Chance to lose durability on one equipped item from damage.
|
||||
|
||||
@@ -403,10 +403,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_UPD_CHARACTER_POSITION, "UPDATE characters SET position_x = ?, position_y = ?, position_z = ?, orientation = ?, map = ?, zone = ?, trans_x = 0, trans_y = 0, trans_z = 0, transguid = 0, taxi_path = '', cinematic = 1 WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_ONLINE, "SELECT name, account, map, zone FROM characters WHERE online > 0", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID, "SELECT guid, class, race FROM characters WHERE account = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate, level FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate, level FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%') ORDER BY deleteDate DESC", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME_LIMIT, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate, level FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%') ORDER BY deleteDate DESC LIMIT 51", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate, level FROM characters WHERE deleteDate IS NOT NULL ORDER BY deleteDate DESC LIMIT 51", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID, "SELECT guid FROM characters WHERE account = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_PINFO, "SELECT totaltime, level, money, account, race, class, map, zone, gender, health, playerFlags FROM characters WHERE guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM character_banned WHERE guid = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_PINFO_MAILS, "SELECT SUM(CASE WHEN (checked & 1) THEN 1 ELSE 0 END) AS 'readmail', COUNT(*) AS 'totalmail' FROM mail WHERE `receiver` = ?", CONNECTION_SYNCH);
|
||||
|
||||
@@ -333,6 +333,7 @@ enum CharacterDatabaseStatements : uint32
|
||||
|
||||
CHAR_SEL_CHAR_DEL_INFO_BY_GUID,
|
||||
CHAR_SEL_CHAR_DEL_INFO_BY_NAME,
|
||||
CHAR_SEL_CHAR_DEL_INFO_BY_NAME_LIMIT,
|
||||
CHAR_SEL_CHAR_DEL_INFO,
|
||||
|
||||
CHAR_SEL_CHARS_BY_ACCOUNT_ID,
|
||||
|
||||
@@ -300,7 +300,6 @@ enum RBACPermissions
|
||||
RBAC_PERM_COMMAND_GMNOTIFY = 468,
|
||||
RBAC_PERM_COMMAND_NAMEANNOUNCE = 469,
|
||||
RBAC_PERM_COMMAND_NOTIFY = 470,
|
||||
RBAC_PERM_COMMAND_WHISPERS = 471,
|
||||
RBAC_PERM_COMMAND_GROUP = 472,
|
||||
RBAC_PERM_COMMAND_GROUP_LEADER = 473,
|
||||
RBAC_PERM_COMMAND_GROUP_DISBAND = 474,
|
||||
@@ -678,6 +677,10 @@ enum RBACPermissions
|
||||
RBAC_PERM_COMMAND_BF_QUEUE = 913,
|
||||
RBAC_PERM_COMMAND_PET_LIST = 914,
|
||||
RBAC_PERM_COMMAND_PET_DELETE = 915,
|
||||
RBAC_PERM_COMMAND_RESPAWN_CREATURE_GUID = 916,
|
||||
RBAC_PERM_COMMAND_RESPAWN_GAMEOBJECT_GUID = 917,
|
||||
RBAC_PERM_COMMAND_RESPAWN_CREATURE_ENTRY = 918,
|
||||
RBAC_PERM_COMMAND_RESPAWN_GAMEOBJECT_ENTRY = 919,
|
||||
// custom permissions 1000+
|
||||
RBAC_PERM_MAX
|
||||
};
|
||||
|
||||
@@ -262,7 +262,9 @@ void WorldSession::SendSpiritResurrect()
|
||||
{
|
||||
_player->ResurrectPlayer(0.5f, true);
|
||||
|
||||
_player->DurabilityLossAll(0.25f, true);
|
||||
float durabilityLossOnSpiritResurrect = sWorld->getRate(RATE_DURABILITY_LOSS_ON_SPIRIT_RESURRECT) / 100.0f;
|
||||
if (durabilityLossOnSpiritResurrect)
|
||||
_player->DurabilityLossAll(durabilityLossOnSpiritResurrect, true);
|
||||
|
||||
// get corpse nearest graveyard
|
||||
GraveyardStruct const* corpseGrave = nullptr;
|
||||
|
||||
@@ -2724,12 +2724,18 @@ void Map::ProcessRespawns()
|
||||
|
||||
void Map::ProcessCreatureRespawn(ObjectGuid::LowType spawnId)
|
||||
{
|
||||
// Pool members are handled entirely by PoolMgr
|
||||
if (uint32 poolId = sPoolMgr->IsPartOfAPool<Creature>(spawnId))
|
||||
// Pool members in non-instanced maps are handled entirely by PoolMgr.
|
||||
// In instanced maps the pool system operates globally and Spawn1Object is
|
||||
// a no-op for instanceable maps, so fall through to the normal per-instance
|
||||
// respawn logic instead.
|
||||
if (!Instanceable())
|
||||
{
|
||||
sPoolMgr->UpdatePool<Creature>(poolId, spawnId);
|
||||
RemoveCreatureRespawnTime(spawnId);
|
||||
return;
|
||||
if (uint32 poolId = sPoolMgr->IsPartOfAPool<Creature>(spawnId))
|
||||
{
|
||||
sPoolMgr->UpdatePool<Creature>(poolId, spawnId);
|
||||
RemoveCreatureRespawnTime(spawnId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(spawnId);
|
||||
@@ -2785,12 +2791,16 @@ void Map::ProcessCreatureRespawn(ObjectGuid::LowType spawnId)
|
||||
|
||||
void Map::ProcessGameObjectRespawn(ObjectGuid::LowType spawnId)
|
||||
{
|
||||
// Pool members are handled entirely by PoolMgr
|
||||
if (uint32 poolId = sPoolMgr->IsPartOfAPool<GameObject>(spawnId))
|
||||
// Same rationale as ProcessCreatureRespawn: pool management via PoolMgr is
|
||||
// only meaningful for non-instanced maps where Spawn1Object actually spawns.
|
||||
if (!Instanceable())
|
||||
{
|
||||
sPoolMgr->UpdatePool<GameObject>(poolId, spawnId);
|
||||
RemoveGORespawnTime(spawnId);
|
||||
return;
|
||||
if (uint32 poolId = sPoolMgr->IsPartOfAPool<GameObject>(spawnId))
|
||||
{
|
||||
sPoolMgr->UpdatePool<GameObject>(poolId, spawnId);
|
||||
RemoveGORespawnTime(spawnId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GameObjectData const* data = sObjectMgr->GetGameObjectData(spawnId);
|
||||
|
||||
@@ -1487,6 +1487,27 @@ enum AcoreStrings
|
||||
|
||||
// Pet delete command
|
||||
LANG_PET_DELETE_NOT_FOUND = 35438,
|
||||
LANG_PET_DELETE_SUCCESS = 35439
|
||||
LANG_PET_DELETE_SUCCESS = 35439,
|
||||
|
||||
LANG_CHARACTER_DELETED_LIST_LIMIT = 35440,
|
||||
|
||||
// Respawn creature/gameobject by spawn GUID commands
|
||||
LANG_RESPAWN_GUID_CREATURE_NOT_FOUND = 35441,
|
||||
LANG_RESPAWN_GUID_MAP_NOT_LOADED = 35442,
|
||||
LANG_RESPAWN_GUID_CREATURE_ALIVE = 35443,
|
||||
LANG_RESPAWN_GUID_CREATURE_QUEUED = 35444,
|
||||
LANG_RESPAWN_GUID_GAMEOBJECT_ACTIVE = 35445,
|
||||
LANG_RESPAWN_GUID_GAMEOBJECT_QUEUED = 35446,
|
||||
// 35447 is reserved for LANG_LIST_RESPAWNS_NO_MAP (list respawns command, defined at the end of this enum)
|
||||
LANG_RESPAWN_GUID_GAMEOBJECT_NOT_FOUND = 35448,
|
||||
|
||||
// Respawn creature/gameobject by entry commands
|
||||
LANG_RESPAWN_ENTRY_CREATURE_NOT_FOUND = 35449,
|
||||
LANG_RESPAWN_ENTRY_GAMEOBJECT_NOT_FOUND = 35450,
|
||||
LANG_RESPAWN_ENTRY_CREATURE_QUEUED = 35451,
|
||||
LANG_RESPAWN_ENTRY_GAMEOBJECT_QUEUED = 35452,
|
||||
|
||||
// List respawns console support
|
||||
LANG_LIST_RESPAWNS_NO_MAP = 35447
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -138,6 +138,8 @@ void WorldConfig::BuildConfigCache()
|
||||
|
||||
SetConfigValue<float>(RATE_DURABILITY_LOSS_ON_DEATH, "DurabilityLoss.OnDeath", 10.0f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f && value <= 100.0f; }, ">= 0 && <= 100");
|
||||
|
||||
SetConfigValue<float>(RATE_DURABILITY_LOSS_ON_SPIRIT_RESURRECT, "DurabilityLoss.OnSpiritResurrect", 25.0f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f && value <= 100.0f; }, ">= 0 && <= 100");
|
||||
|
||||
SetConfigValue<float>(RATE_DURABILITY_LOSS_DAMAGE, "DurabilityLossChance.Damage", 0.5f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f; }, ">= 0");
|
||||
SetConfigValue<float>(RATE_DURABILITY_LOSS_ABSORB, "DurabilityLossChance.Absorb", 0.5f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f; }, ">= 0");
|
||||
SetConfigValue<float>(RATE_DURABILITY_LOSS_PARRY, "DurabilityLossChance.Parry", 0.05f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f; }, ">= 0");
|
||||
@@ -602,6 +604,8 @@ void WorldConfig::BuildConfigCache()
|
||||
|
||||
SetConfigValue<bool>(CONFIG_LOGSPAMREPORTS, "LogSpamReports", true);
|
||||
|
||||
SetConfigValue<bool>(CONFIG_CHATLOG_ENABLED, "ChatLog.Enable", false);
|
||||
|
||||
// Whether to use LoS from game objects
|
||||
SetConfigValue<bool>(CONFIG_CHECK_GOBJECT_LOS, "CheckGameObjectLoS", true);
|
||||
|
||||
|
||||
@@ -480,6 +480,7 @@ enum ServerConfigs
|
||||
RATE_CORPSE_DECAY_LOOTED,
|
||||
RATE_INSTANCE_RESET_TIME,
|
||||
RATE_DURABILITY_LOSS_ON_DEATH,
|
||||
RATE_DURABILITY_LOSS_ON_SPIRIT_RESURRECT,
|
||||
RATE_DURABILITY_LOSS_DAMAGE,
|
||||
RATE_DURABILITY_LOSS_PARRY,
|
||||
RATE_DURABILITY_LOSS_ABSORB,
|
||||
@@ -491,6 +492,7 @@ enum ServerConfigs
|
||||
CONFIG_NEW_CHAR_STRING,
|
||||
CONFIG_VALIDATE_SKILL_LEARNED_BY_SPELLS,
|
||||
CONFIG_ACHIEVEMENT_REALM_FIRST_KILL_WINDOW,
|
||||
CONFIG_CHATLOG_ENABLED,
|
||||
|
||||
MAX_NUM_SERVER_CONFIGS
|
||||
};
|
||||
|
||||
@@ -95,18 +95,22 @@ public:
|
||||
uint32 accountId; ///< the account id
|
||||
std::string accountName; ///< the account name
|
||||
time_t deleteDate; ///< the date at which the character has been deleted
|
||||
uint8 level; ///< the character level at the time of deletion
|
||||
};
|
||||
|
||||
typedef std::list<DeletedInfo> DeletedInfoList;
|
||||
|
||||
static constexpr std::size_t MAX_DELETED_CHAR_RESULTS = 50;
|
||||
|
||||
/**
|
||||
* Collects all GUIDs (and related info) from deleted characters which are still in the database.
|
||||
*
|
||||
* @param foundList a reference to an std::list which will be filled with info data
|
||||
* @param searchString the search string which either contains a player GUID or a part fo the character-name
|
||||
* @param searchString the search string which either contains a player GUID or a part of the character-name
|
||||
* @param limitResults if true, caps results at MAX_DELETED_CHAR_RESULTS + 1 using a DB-level LIMIT
|
||||
* @return returns false if there was a problem while selecting the characters (e.g. player name not normalizeable)
|
||||
*/
|
||||
static bool GetDeletedCharacterInfoList(DeletedInfoList& foundList, std::string searchString)
|
||||
static bool GetDeletedCharacterInfoList(DeletedInfoList& foundList, std::string searchString, bool limitResults = false)
|
||||
{
|
||||
PreparedQueryResult result;
|
||||
CharacterDatabasePreparedStatement* stmt = nullptr;
|
||||
@@ -125,7 +129,8 @@ public:
|
||||
if (!normalizePlayerName(searchString))
|
||||
return false;
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME);
|
||||
CharacterDatabaseStatements nameStmt = limitResults ? CHAR_SEL_CHAR_DEL_INFO_BY_NAME_LIMIT : CHAR_SEL_CHAR_DEL_INFO_BY_NAME;
|
||||
stmt = CharacterDatabase.GetPreparedStatement(nameStmt);
|
||||
stmt->SetData(0, searchString);
|
||||
result = CharacterDatabase.Query(stmt);
|
||||
}
|
||||
@@ -151,6 +156,7 @@ public:
|
||||
// account name will be empty for nonexisting account
|
||||
AccountMgr::GetName(info.accountId, info.accountName);
|
||||
info.deleteDate = time_t(fields[3].Get<uint32>());
|
||||
info.level = fields[4].Get<uint8>();
|
||||
foundList.push_back(info);
|
||||
} while (result->NextRow());
|
||||
}
|
||||
@@ -183,11 +189,13 @@ public:
|
||||
|
||||
if (!handler->GetSession())
|
||||
handler->PSendSysMessage(LANG_CHARACTER_DELETED_LIST_LINE_CONSOLE,
|
||||
itr->lowGuid, itr->name, itr->accountName.empty() ? "<Not existing>" : itr->accountName,
|
||||
itr->lowGuid, itr->name, uint32(itr->level),
|
||||
itr->accountName.empty() ? "<Not existing>" : itr->accountName,
|
||||
itr->accountId, dateStr);
|
||||
else
|
||||
handler->PSendSysMessage(LANG_CHARACTER_DELETED_LIST_LINE_CHAT,
|
||||
itr->lowGuid, itr->name, itr->accountName.empty() ? "<Not existing>" : itr->accountName,
|
||||
itr->lowGuid, itr->name, uint32(itr->level),
|
||||
itr->accountName.empty() ? "<Not existing>" : itr->accountName,
|
||||
itr->accountId, dateStr);
|
||||
}
|
||||
|
||||
@@ -590,7 +598,7 @@ public:
|
||||
if (needleStr)
|
||||
needle.assign(*needleStr);
|
||||
DeletedInfoList foundList;
|
||||
if (!GetDeletedCharacterInfoList(foundList, needle))
|
||||
if (!GetDeletedCharacterInfoList(foundList, needle, true))
|
||||
return false;
|
||||
|
||||
// if no characters have been found, output a warning
|
||||
@@ -600,8 +608,15 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool truncated = foundList.size() > MAX_DELETED_CHAR_RESULTS;
|
||||
if (truncated)
|
||||
foundList.resize(MAX_DELETED_CHAR_RESULTS);
|
||||
|
||||
HandleCharacterDeletedListHelper(foundList, handler);
|
||||
|
||||
if (truncated)
|
||||
handler->SendSysMessage(LANG_CHARACTER_DELETED_LIST_LIMIT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
{ "item", HandleListItemCommand, rbac::RBAC_PERM_COMMAND_LIST_ITEM, Console::Yes },
|
||||
{ "object", HandleListObjectCommand, rbac::RBAC_PERM_COMMAND_LIST_OBJECT, Console::Yes },
|
||||
{ "auras", listAurasCommandTable },
|
||||
{ "respawns", HandleListRespawnsCommand, rbac::RBAC_PERM_COMMAND_LIST_CREATURE, Console::No },
|
||||
{ "respawns", HandleListRespawnsCommand, rbac::RBAC_PERM_COMMAND_LIST_RESPAWNS, Console::Yes },
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
@@ -521,13 +521,35 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleListRespawnsCommand(ChatHandler* handler)
|
||||
static bool HandleListRespawnsCommand(ChatHandler* handler, Optional<uint32> firstArg, Optional<uint32> secondArg, Optional<uint32> thirdArg)
|
||||
{
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
if (!player)
|
||||
return false;
|
||||
Map* map = nullptr;
|
||||
Optional<uint32> entryFilter;
|
||||
|
||||
if (handler->GetSession())
|
||||
{
|
||||
// In-game: first arg = entryId (optional), use player's current map
|
||||
map = handler->GetSession()->GetPlayer()->GetMap();
|
||||
entryFilter = firstArg;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Console: first arg = mapId (required), second = instanceId, third = entryId
|
||||
if (!firstArg)
|
||||
{
|
||||
handler->SendSysMessage(LANG_LIST_RESPAWNS_NO_MAP);
|
||||
return false;
|
||||
}
|
||||
map = sMapMgr->FindMap(*firstArg, secondArg.value_or(0));
|
||||
entryFilter = thirdArg;
|
||||
}
|
||||
|
||||
if (!map)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_MAP_NOT_LOADED, firstArg.value_or(0));
|
||||
return false;
|
||||
}
|
||||
|
||||
Map* map = player->GetMap();
|
||||
uint32 count = 0;
|
||||
time_t now = GameTime::GetGameTime().count();
|
||||
|
||||
@@ -535,7 +557,7 @@ public:
|
||||
for (auto const& pair : map->GetCreatureRespawnTimes())
|
||||
{
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(pair.first);
|
||||
if (!data)
|
||||
if (!data || (entryFilter && data->id1 != *entryFilter))
|
||||
continue;
|
||||
|
||||
CreatureTemplate const* cTemplate = sObjectMgr->GetCreatureTemplate(data->id1);
|
||||
@@ -555,7 +577,7 @@ public:
|
||||
for (auto const& pair : map->GetGORespawnTimes())
|
||||
{
|
||||
GameObjectData const* data = sObjectMgr->GetGameObjectData(pair.first);
|
||||
if (!data)
|
||||
if (!data || (entryFilter && data->id != *entryFilter))
|
||||
continue;
|
||||
|
||||
GameObjectTemplate const* goTemplate = sObjectMgr->GetGameObjectTemplate(data->id);
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
{ "gmannounce", HandleGMAnnounceCommand, rbac::RBAC_PERM_COMMAND_GMANNOUNCE, Console::Yes },
|
||||
{ "notify", HandleNotifyCommand, rbac::RBAC_PERM_COMMAND_NOTIFY, Console::Yes },
|
||||
{ "gmnotify", HandleGMNotifyCommand, rbac::RBAC_PERM_COMMAND_GMNOTIFY, Console::Yes },
|
||||
{ "whispers", HandleWhispersCommand, rbac::RBAC_PERM_COMMAND_WHISPERS, Console::No },
|
||||
{ "whispers", HandleWhispersCommand, rbac::RBAC_PERM_CAN_FILTER_WHISPERS, Console::No },
|
||||
};
|
||||
return commandTable;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "CommandScript.h"
|
||||
#include "Common.h"
|
||||
#include "GameGraveyard.h"
|
||||
#include "GameObject.h"
|
||||
#include "GameTime.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridTerrainLoader.h"
|
||||
@@ -177,6 +178,10 @@ public:
|
||||
{ "pinfo", HandlePInfoCommand, rbac::RBAC_PERM_COMMAND_PINFO, Console::Yes },
|
||||
{ "respawn", HandleRespawnCommand, rbac::RBAC_PERM_COMMAND_RESPAWN, Console::No },
|
||||
{ "respawn all", HandleRespawnAllCommand, rbac::RBAC_PERM_COMMAND_RESPAWN_ALL, Console::No },
|
||||
{ "respawn creature guid", HandleRespawnCreatureByGuidCommand, rbac::RBAC_PERM_COMMAND_RESPAWN_CREATURE_GUID, Console::Yes },
|
||||
{ "respawn gameobject guid", HandleRespawnGameObjectByGuidCommand, rbac::RBAC_PERM_COMMAND_RESPAWN_GAMEOBJECT_GUID, Console::Yes },
|
||||
{ "respawn creature entry", HandleRespawnCreatureByEntryCommand, rbac::RBAC_PERM_COMMAND_RESPAWN_CREATURE_ENTRY, Console::Yes },
|
||||
{ "respawn gameobject entry", HandleRespawnGameObjectByEntryCommand, rbac::RBAC_PERM_COMMAND_RESPAWN_GAMEOBJECT_ENTRY, Console::Yes },
|
||||
{ "mute", HandleMuteCommand, rbac::RBAC_PERM_COMMAND_MUTE, Console::Yes },
|
||||
{ "mutehistory", HandleMuteInfoCommand, rbac::RBAC_PERM_COMMAND_MUTEHISTORY, Console::Yes },
|
||||
{ "unmute", HandleUnmuteCommand, rbac::RBAC_PERM_COMMAND_UNMUTE, Console::Yes },
|
||||
@@ -2448,6 +2453,265 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleRespawnCreatureByGuidCommand(ChatHandler* handler, ObjectGuid::LowType spawnId)
|
||||
{
|
||||
CreatureData const* creData = sObjectMgr->GetCreatureData(spawnId);
|
||||
if (!creData)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_RESPAWN_GUID_CREATURE_NOT_FOUND, spawnId);
|
||||
return false;
|
||||
}
|
||||
|
||||
Map* map = nullptr;
|
||||
if (handler->GetSession())
|
||||
{
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
if (player->GetMapId() == creData->mapid)
|
||||
map = player->GetMap();
|
||||
}
|
||||
if (!map)
|
||||
map = sMapMgr->FindMap(creData->mapid, 0);
|
||||
|
||||
if (!map)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_MAP_NOT_LOADED, creData->mapid);
|
||||
return true;
|
||||
}
|
||||
|
||||
// First pass: check if any instance is alive
|
||||
bool isAlive = false;
|
||||
auto const creBounds = map->GetCreatureBySpawnIdStore().equal_range(spawnId);
|
||||
for (auto itr = creBounds.first; itr != creBounds.second; ++itr)
|
||||
{
|
||||
if (itr->second->IsAlive())
|
||||
{
|
||||
isAlive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAlive)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_CREATURE_ALIVE, spawnId, creData->id1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Second pass: respawn any dead corpses in the world
|
||||
for (auto itr = creBounds.first; itr != creBounds.second; ++itr)
|
||||
{
|
||||
if (itr->second->isDead())
|
||||
itr->second->Respawn(true);
|
||||
}
|
||||
// Also trigger via respawn time queue for fully-removed spawns
|
||||
if (map->GetCreatureRespawnTime(spawnId) > 0)
|
||||
{
|
||||
time_t now = GameTime::GetGameTime().count();
|
||||
map->SaveCreatureRespawnTime(spawnId, now);
|
||||
}
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_CREATURE_QUEUED, spawnId, creData->id1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleRespawnGameObjectByGuidCommand(ChatHandler* handler, ObjectGuid::LowType spawnId)
|
||||
{
|
||||
GameObjectData const* goData = sObjectMgr->GetGameObjectData(spawnId);
|
||||
if (!goData)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_RESPAWN_GUID_GAMEOBJECT_NOT_FOUND, spawnId);
|
||||
return false;
|
||||
}
|
||||
|
||||
Map* map = nullptr;
|
||||
if (handler->GetSession())
|
||||
{
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
if (player->GetMapId() == goData->mapid)
|
||||
map = player->GetMap();
|
||||
}
|
||||
if (!map)
|
||||
map = sMapMgr->FindMap(goData->mapid, 0);
|
||||
|
||||
if (!map)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_MAP_NOT_LOADED, goData->mapid);
|
||||
return true;
|
||||
}
|
||||
|
||||
// First pass: check if any instance is already active
|
||||
bool isActive = false;
|
||||
auto const goBounds = map->GetGameObjectBySpawnIdStore().equal_range(spawnId);
|
||||
for (auto itr = goBounds.first; itr != goBounds.second; ++itr)
|
||||
{
|
||||
if (itr->second->isSpawned())
|
||||
{
|
||||
isActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isActive)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_GAMEOBJECT_ACTIVE, spawnId, goData->id);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Second pass: respawn inactive objects in the world
|
||||
for (auto itr = goBounds.first; itr != goBounds.second; ++itr)
|
||||
itr->second->Respawn();
|
||||
// Also trigger via respawn time queue for fully-removed spawns
|
||||
if (map->GetGORespawnTime(spawnId) > 0)
|
||||
{
|
||||
time_t now = GameTime::GetGameTime().count();
|
||||
map->SaveGORespawnTime(spawnId, now);
|
||||
}
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_GAMEOBJECT_QUEUED, spawnId, goData->id);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleRespawnCreatureByEntryCommand(ChatHandler* handler, uint32 entry, Optional<uint32> mapIdArg, Optional<uint32> instanceIdArg)
|
||||
{
|
||||
if (!sObjectMgr->GetCreatureTemplate(entry))
|
||||
{
|
||||
handler->SendErrorMessage(LANG_RESPAWN_ENTRY_CREATURE_NOT_FOUND, entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
Map* map = nullptr;
|
||||
if (handler->GetSession())
|
||||
{
|
||||
// In-game: always use the player's current map
|
||||
map = handler->GetSession()->GetPlayer()->GetMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Console: mapId required, instanceId optional
|
||||
if (!mapIdArg)
|
||||
{
|
||||
handler->SendSysMessage(LANG_LIST_RESPAWNS_NO_MAP);
|
||||
return false;
|
||||
}
|
||||
map = sMapMgr->FindMap(*mapIdArg, instanceIdArg.value_or(0));
|
||||
}
|
||||
|
||||
if (!map)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_MAP_NOT_LOADED, mapIdArg.value_or(0));
|
||||
return false;
|
||||
}
|
||||
|
||||
time_t now = GameTime::GetGameTime().count();
|
||||
uint32 count = 0;
|
||||
|
||||
// Phase 1: respawn dead corpses that are still tracked in the spawn-id store.
|
||||
// Collect first to avoid iterator invalidation caused by Respawn().
|
||||
std::vector<Creature*> deadCreatures;
|
||||
for (auto const& [spawnId, creature] : map->GetCreatureBySpawnIdStore())
|
||||
{
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(spawnId);
|
||||
if (!data || data->id1 != entry)
|
||||
continue;
|
||||
if (creature->isDead())
|
||||
deadCreatures.push_back(creature);
|
||||
}
|
||||
for (Creature* creature : deadCreatures)
|
||||
{
|
||||
creature->Respawn(true);
|
||||
++count;
|
||||
}
|
||||
|
||||
// Phase 2: set respawn time to now for fully-removed spawns, skipping pools
|
||||
std::vector<ObjectGuid::LowType> toRespawn;
|
||||
for (auto const& [spawnId, respawnTime] : map->GetCreatureRespawnTimes())
|
||||
{
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(spawnId);
|
||||
if (!data || data->id1 != entry)
|
||||
continue;
|
||||
if (sPoolMgr->IsPartOfAPool<Creature>(spawnId))
|
||||
continue;
|
||||
toRespawn.push_back(spawnId);
|
||||
}
|
||||
for (ObjectGuid::LowType spawnId : toRespawn)
|
||||
{
|
||||
map->SaveCreatureRespawnTime(spawnId, now);
|
||||
++count;
|
||||
}
|
||||
|
||||
handler->PSendSysMessage(LANG_RESPAWN_ENTRY_CREATURE_QUEUED, count, entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleRespawnGameObjectByEntryCommand(ChatHandler* handler, uint32 entry, Optional<uint32> mapIdArg, Optional<uint32> instanceIdArg)
|
||||
{
|
||||
if (!sObjectMgr->GetGameObjectTemplate(entry))
|
||||
{
|
||||
handler->SendErrorMessage(LANG_RESPAWN_ENTRY_GAMEOBJECT_NOT_FOUND, entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
Map* map = nullptr;
|
||||
if (handler->GetSession())
|
||||
{
|
||||
// In-game: always use the player's current map
|
||||
map = handler->GetSession()->GetPlayer()->GetMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Console: mapId required, instanceId optional
|
||||
if (!mapIdArg)
|
||||
{
|
||||
handler->SendSysMessage(LANG_LIST_RESPAWNS_NO_MAP);
|
||||
return false;
|
||||
}
|
||||
map = sMapMgr->FindMap(*mapIdArg, instanceIdArg.value_or(0));
|
||||
}
|
||||
|
||||
if (!map)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_RESPAWN_GUID_MAP_NOT_LOADED, mapIdArg.value_or(0));
|
||||
return false;
|
||||
}
|
||||
|
||||
time_t now = GameTime::GetGameTime().count();
|
||||
uint32 count = 0;
|
||||
|
||||
// Phase 1: respawn inactive objects that are still tracked in the spawn-id store.
|
||||
// Collect first to avoid iterator invalidation caused by Respawn().
|
||||
std::vector<GameObject*> inactiveGOs;
|
||||
for (auto const& [spawnId, go] : map->GetGameObjectBySpawnIdStore())
|
||||
{
|
||||
GameObjectData const* data = sObjectMgr->GetGameObjectData(spawnId);
|
||||
if (!data || data->id != entry)
|
||||
continue;
|
||||
if (!go->isSpawned())
|
||||
inactiveGOs.push_back(go);
|
||||
}
|
||||
for (GameObject* go : inactiveGOs)
|
||||
{
|
||||
go->Respawn();
|
||||
++count;
|
||||
}
|
||||
|
||||
// Phase 2: set respawn time to now for fully-removed spawns, skipping pools
|
||||
std::vector<ObjectGuid::LowType> toRespawn;
|
||||
for (auto const& [spawnId, respawnTime] : map->GetGORespawnTimes())
|
||||
{
|
||||
GameObjectData const* data = sObjectMgr->GetGameObjectData(spawnId);
|
||||
if (!data || data->id != entry)
|
||||
continue;
|
||||
if (sPoolMgr->IsPartOfAPool<GameObject>(spawnId))
|
||||
continue;
|
||||
toRespawn.push_back(spawnId);
|
||||
}
|
||||
for (ObjectGuid::LowType spawnId : toRespawn)
|
||||
{
|
||||
map->SaveGORespawnTime(spawnId, now);
|
||||
++count;
|
||||
}
|
||||
|
||||
handler->PSendSysMessage(LANG_RESPAWN_ENTRY_GAMEOBJECT_QUEUED, count, entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleRespawnCommand(ChatHandler* handler)
|
||||
{
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
|
||||
@@ -77,18 +77,6 @@ struct boss_moroes : public BossAI
|
||||
_activeGuests = 0;
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
BossAI::InitializeAI();
|
||||
InitializeGuests();
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
{
|
||||
BossAI::JustReachedHome();
|
||||
InitializeGuests();
|
||||
}
|
||||
|
||||
void InitializeGuests()
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
@@ -96,16 +84,18 @@ struct boss_moroes : public BossAI
|
||||
|
||||
if (_activeGuests == 0)
|
||||
{
|
||||
_activeGuests |= 0x3F;
|
||||
_activeGuests = 0x3F;
|
||||
uint8 rand1 = RAND(0x01, 0x02, 0x04);
|
||||
uint8 rand2 = RAND(0x08, 0x10, 0x20);
|
||||
_activeGuests &= ~(rand1 | rand2);
|
||||
}
|
||||
for (uint8 i = 0; i < MAX_GUEST_COUNT; ++i)
|
||||
|
||||
uint8 positionIndex = 0;
|
||||
for (uint8 i = 0; i < MAX_GUEST_COUNT && positionIndex < ACTIVE_GUEST_COUNT; ++i)
|
||||
{
|
||||
if ((1 << i) & _activeGuests)
|
||||
{
|
||||
me->SummonCreature(GuestEntries[i], GuestsPosition[summons.size()], TEMPSUMMON_MANUAL_DESPAWN);
|
||||
me->SummonCreature(GuestEntries[i], GuestsPosition[positionIndex++], TEMPSUMMON_MANUAL_DESPAWN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +120,8 @@ struct boss_moroes : public BossAI
|
||||
_recentlySpoken = false;
|
||||
_vanished = false;
|
||||
|
||||
InitializeGuests();
|
||||
|
||||
ScheduleHealthCheckEvent(30, [&] {
|
||||
DoCastSelf(SPELL_FRENZY, true);
|
||||
});
|
||||
@@ -203,6 +195,9 @@ struct boss_moroes : public BossAI
|
||||
}
|
||||
}
|
||||
|
||||
if (guestList.empty())
|
||||
return nullptr;
|
||||
|
||||
return Acore::Containers::SelectRandomContainerElement(guestList);
|
||||
}
|
||||
|
||||
@@ -211,12 +206,12 @@ struct boss_moroes : public BossAI
|
||||
bool guestsInRoom = true;
|
||||
summons.DoForAllSummons([&guestsInRoom](WorldObject* summon)
|
||||
{
|
||||
if ((summon->ToCreature()->GetPositionX()) < -11028.f || (summon->ToCreature()->GetPositionY()) < -1955.f) //boundaries of the two doors
|
||||
Creature* creature = summon->ToCreature();
|
||||
if (creature->IsAlive() &&
|
||||
((creature->GetPositionX() < -11028.f) || (creature->GetPositionY() < -1955.f))) // boundaries of the two doors
|
||||
{
|
||||
guestsInRoom = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return guestsInRoom;
|
||||
@@ -229,10 +224,6 @@ struct boss_moroes : public BossAI
|
||||
if (!CheckGuestsInRoom())
|
||||
{
|
||||
EnterEvadeMode();
|
||||
summons.DoForAllSummons([](WorldObject* summon)
|
||||
{
|
||||
summon->ToCreature()->DespawnOnEvade(5s);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -204,7 +204,9 @@ public:
|
||||
case EVENT_COMPLETE:
|
||||
{
|
||||
DoCast(me, SPELL_IDOM_ROOM_CAMERA_SHAKE);
|
||||
me->SummonGameObject(GO_BELNISTRASZS_BRAZIER, 2577.196f, 947.0781f, 53.16757f, 2.356195f, 0, 0, 0.9238796f, 0.3826832f, 3600);
|
||||
// Summon via the map so the brazier is not tied to Belnistrasz's
|
||||
// m_gameObj list and survives his despawn below.
|
||||
me->GetMap()->SummonGameObject(GO_BELNISTRASZS_BRAZIER, 2577.196f, 947.0781f, 53.16757f, 2.356195f, 0, 0, 0.9238796f, 0.3826832f, 3600);
|
||||
std::list<WorldObject*> ClusterList;
|
||||
Acore::AllWorldObjectsInRange objects(me, 50.0f);
|
||||
Acore::WorldObjectListSearcher<Acore::AllWorldObjectsInRange> searcher(me, ClusterList, objects);
|
||||
@@ -223,7 +225,7 @@ public:
|
||||
}
|
||||
}
|
||||
instance->SetData(GO_BELNISTRASZS_BRAZIER, DONE);
|
||||
me->DespawnOrUnsummon();
|
||||
me->DespawnOrUnsummon(5s);
|
||||
break;
|
||||
}
|
||||
case EVENT_FIREBALL:
|
||||
|
||||
@@ -36,8 +36,8 @@ enum Data
|
||||
// Non-boss data (SetData/GetData only)
|
||||
DATA_INTRO,
|
||||
DATA_FROSTSWORN_GENERAL,
|
||||
DATA_BATTERED_HILT = 6, //For SAI DB
|
||||
DATA_LK_INTRO,
|
||||
DATA_BATTERED_HILT,
|
||||
DATA_WAVE_NUMBER,
|
||||
DATA_LK_BATTLE,
|
||||
DATA_SHIP_CAPTAIN,
|
||||
|
||||
-1
@@ -60,7 +60,6 @@ public:
|
||||
case 5:
|
||||
_owner.SetFacingTo(2.82f);
|
||||
_owner.SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
_owner.m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(_owner, 6), 3s);
|
||||
break;
|
||||
case 6:
|
||||
if (InstanceScript* inst = _owner.GetInstanceScript())
|
||||
|
||||
@@ -155,6 +155,7 @@ struct boss_gal_darah : public BossAI
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PUNCTURE);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit*) override
|
||||
|
||||
@@ -133,6 +133,7 @@ enum Events
|
||||
EVENT_UNBOUND_PLAGUE,
|
||||
EVENT_MALLEABLE_GOO,
|
||||
EVENT_CHOKING_GAS_BOMB,
|
||||
EVENT_MUTATED_PLAGUE,
|
||||
};
|
||||
|
||||
#define EVENT_GROUP_ABILITIES 1
|
||||
@@ -653,6 +654,11 @@ public:
|
||||
me->CastSpell(me, SPELL_CHOKING_GAS_BOMB, false);
|
||||
events.ScheduleEvent(EVENT_CHOKING_GAS_BOMB, 35s, 40s, EVENT_GROUP_ABILITIES);
|
||||
break;
|
||||
case EVENT_MUTATED_PLAGUE:
|
||||
if (Unit* target = me->GetVictim())
|
||||
me->CastSpell(target, SPELL_MUTATED_PLAGUE, false);
|
||||
events.ScheduleEvent(EVENT_MUTATED_PLAGUE, 10s, EVENT_GROUP_ABILITIES);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -721,6 +727,7 @@ public:
|
||||
case 2:
|
||||
_phase = 3;
|
||||
events.CancelEvent(EVENT_UNSTABLE_EXPERIMENT);
|
||||
events.ScheduleEvent(EVENT_MUTATED_PLAGUE, 10s, EVENT_GROUP_ABILITIES);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -441,7 +441,6 @@ struct boss_kologarn : public BossAI
|
||||
{
|
||||
events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 20s);
|
||||
me->CastSpell(me, SPELL_FOCUSED_EYEBEAM_SUMMON, false);
|
||||
Talk(EMOTE_EYES);
|
||||
return;
|
||||
}
|
||||
case EVENT_RESTORE_ARM_LEFT:
|
||||
@@ -605,6 +604,7 @@ struct boss_kologarn_eyebeam : public ScriptedAI
|
||||
if (Creature* cr = _instance->GetCreature(BOSS_KOLOGARN))
|
||||
{
|
||||
me->CastSpell(cr, me->GetEntry() == NPC_EYE_LEFT ? SPELL_FOCUSED_EYEBEAM_LEFT : SPELL_FOCUSED_EYEBEAM_RIGHT, true);
|
||||
cr->AI()->Talk(EMOTE_EYES, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ enum Actions
|
||||
ACTION_START_ENCOUNTER = 1,
|
||||
ACTION_DRAKE_BREATH = 2,
|
||||
ACTION_PHASE2 = 3,
|
||||
ACTION_HARPOON_HIT = 4,
|
||||
};
|
||||
|
||||
enum CombatPhase
|
||||
@@ -171,8 +170,6 @@ public:
|
||||
_events.Reset();
|
||||
_summons.DespawnAll();
|
||||
_phase = PHASE_GROUND;
|
||||
_harpoonHit = 0;
|
||||
_loveSkadi = 0;
|
||||
_firstWaveSummoned = false;
|
||||
_encounterStarted = false;
|
||||
|
||||
@@ -266,8 +263,6 @@ public:
|
||||
_events.ScheduleEvent(EVENT_SKADI_RESET_CHECK, 6s);
|
||||
break;
|
||||
case ACTION_DRAKE_BREATH:
|
||||
if (_loveSkadi == 1)
|
||||
++_loveSkadi;
|
||||
Talk(SAY_DRAKE_BREATH);
|
||||
break;
|
||||
case ACTION_PHASE2:
|
||||
@@ -283,21 +278,9 @@ public:
|
||||
_events.ScheduleEvent(EVENT_SKADI_SPEAR, 11s);
|
||||
_events.ScheduleEvent(EVENT_SKADI_WHIRLWIND, 23s);
|
||||
break;
|
||||
case ACTION_HARPOON_HIT:
|
||||
++_harpoonHit;
|
||||
if (_harpoonHit == 1)
|
||||
_loveSkadi = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 id) const override
|
||||
{
|
||||
if (id == DATA_LOVE_TO_SKADI)
|
||||
return _loveSkadi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_events.Update(diff);
|
||||
@@ -384,8 +367,6 @@ public:
|
||||
EventMap _events;
|
||||
SummonList _summons;
|
||||
CombatPhase _phase;
|
||||
uint8 _harpoonHit;
|
||||
uint8 _loveSkadi;
|
||||
bool _firstWaveSummoned;
|
||||
bool _encounterStarted;
|
||||
};
|
||||
@@ -415,6 +396,7 @@ public:
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetSpeedRate(MOVE_RUN, 2.5f);
|
||||
_flyingToSide = false;
|
||||
_passFreshStart = false;
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
@@ -430,13 +412,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_LAUNCH_HARPOON)
|
||||
if (Creature* skadi = _instance->GetCreature(DATA_SKADI_THE_RUTHLESS))
|
||||
skadi->AI()->DoAction(ACTION_HARPOON_HIT);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 /*id*/) override
|
||||
{
|
||||
if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized())
|
||||
@@ -470,6 +445,7 @@ public:
|
||||
FORCED_MOVEMENT_RUN);
|
||||
break;
|
||||
case EVENT_GRAUF_BREATH_START:
|
||||
_passFreshStart = me->IsFullHealth();
|
||||
me->GetMotionMaster()->MovePath(
|
||||
_lastSide == POINT_LEFT ? PATH_LEFT : PATH_RIGHT,
|
||||
FORCED_MOVEMENT_RUN);
|
||||
@@ -493,10 +469,11 @@ public:
|
||||
{
|
||||
skadi->ExitVehicle();
|
||||
skadi->AI()->DoAction(ACTION_PHASE2);
|
||||
|
||||
if (skadi->AI()->GetData(DATA_LOVE_TO_SKADI) == 1)
|
||||
_instance->SetData(DATA_SKADI_ACHIEVEMENT, true);
|
||||
}
|
||||
|
||||
if (_passFreshStart)
|
||||
_instance->SetData(DATA_SKADI_ACHIEVEMENT, true);
|
||||
|
||||
me->DespawnOrUnsummon(6s);
|
||||
}
|
||||
|
||||
@@ -506,6 +483,7 @@ public:
|
||||
SummonList _summons;
|
||||
uint8 _lastSide = POINT_LEFT;
|
||||
bool _flyingToSide = false;
|
||||
bool _passFreshStart = false;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -313,6 +313,7 @@ class spell_hun_taming_the_beast : public AuraScript
|
||||
if (Creature* creature = target->ToCreature())
|
||||
{
|
||||
creature->GetThreatMgr().ClearAllThreat();
|
||||
creature->GetCombatManager().EndAllCombat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Guild.h"
|
||||
#include "Log.h"
|
||||
#include "PlayerScript.h"
|
||||
#include "World.h"
|
||||
|
||||
class ChatLogScript : public PlayerScript
|
||||
{
|
||||
@@ -38,6 +39,9 @@ public:
|
||||
|
||||
bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 lang, std::string& msg) override
|
||||
{
|
||||
if (!sWorld->getBoolConfig(CONFIG_CHATLOG_ENABLED))
|
||||
return true;
|
||||
|
||||
std::string logType = "";
|
||||
std::string chatType = "";
|
||||
|
||||
@@ -67,6 +71,9 @@ public:
|
||||
|
||||
bool OnPlayerCanUseChat(Player* player, uint32 /*type*/, uint32 lang, std::string& msg, Player* receiver) override
|
||||
{
|
||||
if (!sWorld->getBoolConfig(CONFIG_CHATLOG_ENABLED))
|
||||
return true;
|
||||
|
||||
//! NOTE:
|
||||
//! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER"
|
||||
std::string logType = (lang != LANG_ADDON) ? "chat." : "chat.addon.";
|
||||
@@ -80,6 +87,9 @@ public:
|
||||
|
||||
bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) override
|
||||
{
|
||||
if (!sWorld->getBoolConfig(CONFIG_CHATLOG_ENABLED))
|
||||
return true;
|
||||
|
||||
//! NOTE:
|
||||
//! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER"
|
||||
std::string logType = (lang != LANG_ADDON) ? "chat." : "chat.addon.";
|
||||
@@ -116,6 +126,9 @@ public:
|
||||
|
||||
bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) override
|
||||
{
|
||||
if (!sWorld->getBoolConfig(CONFIG_CHATLOG_ENABLED))
|
||||
return true;
|
||||
|
||||
//! NOTE:
|
||||
//! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER"
|
||||
std::string logType = (lang != LANG_ADDON) ? "chat." : "chat.addon.";
|
||||
@@ -141,6 +154,9 @@ public:
|
||||
|
||||
bool OnPlayerCanUseChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Channel* channel) override
|
||||
{
|
||||
if (!sWorld->getBoolConfig(CONFIG_CHATLOG_ENABLED))
|
||||
return true;
|
||||
|
||||
bool isSystem = channel &&
|
||||
(channel->HasFlag(CHANNEL_FLAG_TRADE) ||
|
||||
channel->HasFlag(CHANNEL_FLAG_GENERAL) ||
|
||||
|
||||
Reference in New Issue
Block a user