Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-02-04 23:40:06 +08:00
81 changed files with 3144 additions and 611 deletions
+39 -5
View File
@@ -15,8 +15,9 @@ results = {
"Multiple blank lines check": "Passed", "Multiple blank lines check": "Passed",
"Trailing whitespace check": "Passed", "Trailing whitespace check": "Passed",
"SQL codestyle check": "Passed", "SQL codestyle check": "Passed",
"INSERT safety usage check": "Passed", "INSERT & DELETE safety usage check": "Passed",
"Missing semicolon check": "Passed" "Missing semicolon check": "Passed",
"Backtick check": "Passed"
} }
# Collect all files in all directories # Collect all files in all directories
@@ -44,8 +45,9 @@ def parsing_file(files: list) -> None:
multiple_blank_lines_check(file, file_path) multiple_blank_lines_check(file, file_path)
trailing_whitespace_check(file, file_path) trailing_whitespace_check(file, file_path)
sql_check(file, file_path) sql_check(file, file_path)
insert_safety_check(file, file_path) insert_delete_safety_check(file, file_path)
semicolon_check(file, file_path) semicolon_check(file, file_path)
backtick_check(file, file_path)
except UnicodeDecodeError: except UnicodeDecodeError:
print(f"\nCould not decode file {file_path}") print(f"\nCould not decode file {file_path}")
sys.exit(1) sys.exit(1)
@@ -134,9 +136,10 @@ def sql_check(file: io, file_path: str) -> None:
error_handler = True error_handler = True
results["SQL codestyle check"] = "Failed" results["SQL codestyle check"] = "Failed"
def insert_safety_check(file: io, file_path: str) -> None: def insert_delete_safety_check(file: io, file_path: str) -> None:
global error_handler, results global error_handler, results
file.seek(0) # Reset file pointer to the beginning file.seek(0) # Reset file pointer to the beginning
not_delete = ["creature_template", "gameobject_template", "item_template", "quest_template"]
check_failed = False check_failed = False
previous_line = "" previous_line = ""
@@ -148,11 +151,18 @@ def insert_safety_check(file: io, file_path: str) -> None:
print(f"No DELETE keyword found after the INSERT in {file_path} at line {line_number}\nIf this error is intended, please advert a maintainer") print(f"No DELETE keyword found after the INSERT in {file_path} at line {line_number}\nIf this error is intended, please advert a maintainer")
check_failed = True check_failed = True
previous_line = line previous_line = line
match = re.match(r"DELETE FROM\s+`([^`]+)`", line, re.IGNORECASE)
if match:
table_name = match.group(1)
if table_name in not_delete:
print(
f"Entries from {table} should not be deleted! {file_path} at line {line_number}")
check_failed = True
# Handle the script error and update the result output # Handle the script error and update the result output
if check_failed: if check_failed:
error_handler = True error_handler = True
results["INSERT safety usage check"] = "Failed" results["INSERT & DELETE safety usage check"] = "Failed"
def semicolon_check(file: io, file_path: str) -> None: def semicolon_check(file: io, file_path: str) -> None:
global error_handler, results global error_handler, results
@@ -192,6 +202,30 @@ def semicolon_check(file: io, file_path: str) -> None:
error_handler = True error_handler = True
results["Missing semicolon check"] = "Failed" results["Missing semicolon check"] = "Failed"
def backtick_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0)
check_failed = False
pattern = re.compile(
r'\b(SELECT|FROM|JOIN|WHERE|GROUP BY|ORDER BY|DELETE FROM|UPDATE|INSERT INTO|SET)\s+([^;]+)',
re.IGNORECASE)
for line_number, line in enumerate(file, start=1):
matches = pattern.findall(line)
for clause, content in matches:
words = re.findall(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b', content)
for word in words:
if word.upper() in {"SELECT", "FROM", "JOIN", "WHERE", "GROUP", "BY", "ORDER",
"DELETE", "UPDATE", "INSERT", "INTO", "SET", "VALUES"}:
continue
if not re.search(rf'`{re.escape(word)}`', content):
print(f"Missing backticks around ({word}). {file_path} at line {line_number}")
check_failed = True
if check_failed:
error_handler = True
results["Backtick check"] = "Failed"
# Collect all files from matching directories # Collect all files from matching directories
all_files = collect_files_from_directories(src_directory) all_files = collect_files_from_directories(src_directory)
@@ -1,6 +1,6 @@
# install chocolatey before # install chocolatey before
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" # powershell.exe -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
# install automatically following packages: # install automatically following packages:
# cmake # cmake
@@ -24,7 +24,7 @@ fi
choco install -y --skip-checksums $INSTALL_ARGS cmake.install -y --installargs 'ADD_CMAKE_TO_PATH=System' choco install -y --skip-checksums $INSTALL_ARGS cmake.install -y --installargs 'ADD_CMAKE_TO_PATH=System'
choco install -y --skip-checksums $INSTALL_ARGS visualstudio2022-workload-nativedesktop choco install -y --skip-checksums $INSTALL_ARGS visualstudio2022-workload-nativedesktop
choco install -y --skip-checksums $INSTALL_ARGS openssl --version=3.1.1 choco install -y --skip-checksums $INSTALL_ARGS openssl --force --version=3.3.2
choco install -y --skip-checksums $INSTALL_ARGS boost-msvc-14.3 --version=1.82.0 choco install -y --skip-checksums $INSTALL_ARGS boost-msvc-14.3 --force --version=1.87.0
choco install -y --skip-checksums $INSTALL_ARGS mysql --version=8.0.31 choco install -y --skip-checksums $INSTALL_ARGS mysql --force --version=8.4.4
@@ -0,0 +1,13 @@
-- DB update 2024_11_15_00 -> 2025_01_31_00
--
DROP TABLE IF EXISTS `world_state`;
CREATE TABLE IF NOT EXISTS `world_state` (
`Id` INT UNSIGNED NOT NULL COMMENT 'Internal save ID',
`Data` longtext,
PRIMARY KEY(`Id`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COMMENT='WorldState save system';
-- Isle of Quel'danas is in its final stage with all subphases completed
-- open all Sunwell Plateau gates
DELETE FROM `world_state` WHERE `Id` = 20;
INSERT INTO `world_state` (`Id`, `Data`) VALUES(20, '3 15 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 3 80 80 80');
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
-- DB update 2025_01_31_00 -> 2025_01_31_01
-- Add pure energy immune script for Vex
UPDATE `creature_template` SET `ScriptName` = 'npc_pure_energy' WHERE (`entry` = 24745);
-- AOE_IMMUNE Flag for pure energy
UPDATE `creature_template` SET `flags_extra` = (`flags_extra` | 4194304) WHERE (`entry` = 24745);
-- Vexallus (Entry: 24744) Overload Emote with broadcasttextid 77866
DELETE FROM `creature_text` WHERE `CreatureID` = 24744 AND `GroupID` = 5 AND `ID` = 0;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(24744, 5, 0, 'Vexallus overloads!', 41, 0, 100, 0, 0, 0, 23781, 0, 'Vexallus - EMOTE_OVERLOAD');
@@ -0,0 +1,8 @@
-- DB update 2025_01_31_01 -> 2025_02_01_00
--
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24761);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(24761, 0, 0, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 44406, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Brightscale Wyrm - On Just Died - Cast \'Energy Infusion\'');
DELETE FROM `spell_custom_attr` WHERE `spell_id`= 44406;
INSERT INTO `spell_custom_attr` (`spell_id`, `attributes`) VALUES (44406, 4194304);
@@ -0,0 +1,3 @@
-- DB update 2025_02_01_00 -> 2025_02_01_01
--
UPDATE `creature_template` SET `ScriptName` = '' WHERE (`entry` = 24745);
@@ -0,0 +1,3 @@
-- DB update 2025_02_01_01 -> 2025_02_01_02
--
DELETE FROM `acore_string` WHERE `entry` = 6617;
@@ -0,0 +1,16 @@
-- DB update 2025_02_01_02 -> 2025_02_03_00
-- Add Russian locale for QuestID: 4641
DELETE FROM `quest_offer_reward_locale` WHERE `ID` = 4641 AND `locale` = 'ruRU';
INSERT INTO `quest_offer_reward_locale` (`ID`, `locale`, `RewardText`, `VerifiedBuild`) VALUES (4641,'ruRU','Очередной рекрут Калтунка?$B$BВидно, плохи наши дела, если у нас нет никого получше. Ну, ничего. К тому времени, как мы решим, что тебе пора покинуть долину, из тебя $c получится бравый воитель Орды!',0);
-- Add Russian locale for QuestID: 788
DELETE FROM `quest_offer_reward_locale` WHERE `ID` = 788 AND `locale` = 'ruRU';
INSERT INTO `quest_offer_reward_locale` (`ID`, `locale`, `RewardText`, `VerifiedBuild`) VALUES (788,'ruRU','Ну что ж, $N, неплохо. Но не задирай носа: грядут бои с куда более серьезными врагами.$b$bОднако ты показал себя достойным бойцом. В следующем испытании тебе придется встретиться с более опасным противником, так что дополнительная защита не помешает.',0);
-- Fix Russian locale for QuestID: 783
DELETE FROM `quest_template_locale` WHERE `ID` = 783 AND `locale` = 'ruRU';
INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `VerifiedBuild`) VALUES (783, 'ruRU', 'Внутренняя угроза', 'Надеюсь, ты $gготов:готова; к подвигам, |3-6($c), поскольку для тебя есть дело здесь, в Североземье.$B$BИ я имею в виду не мирные сельские заботы.$B$BСтража Штормграда с трудом поддерживает здесь мир: слишком многие из нас находятся в дальних краях, а тревожных вестей меньше не становится. И потому мы надеемся на помощь всех, кто готов защитить свой дом и своих близких.$B$BЕсли ты $gготов:готова; откликнуться на призыв, то поговори с моим командиром, маршалом Макбрайдом. Он здесь, в аббатстве у меня за спиной.', 'Поговорите с маршалом Макбрайдом.', 0);
-- Fix Russian locale for QuestID: 792
DELETE FROM `quest_template_locale` WHERE `ID` = 792 AND `locale` = 'ruRU';
INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `VerifiedBuild`) VALUES (792, 'ruRU', 'Злобные фамильяры', 'Что ж, |3-6($c), надеюсь, у нас ты многому научишься.$b$bМеня послали сюда, чтобы я стала твоей наставницей, но оказывается, здесь не все ладно!$b$bВ долине Испытаний обосновался клан Пылающего Клинка. Эти твари скрываются в пещере на северо-востоке, и их злобные фамильяры выбираются оттуда и сеют хаос.$b$bИтак, вот твое первое задание в борьбе с Пылающим Клинком: перебей их столько, сколько сумеешь, и, если выживешь, возвращайся ко мне.', 'Убейте 8 злобных фамильяров и вернитесь к Зурите Востроглазой, которая ждет вас у Логова.', 0);
@@ -0,0 +1,3 @@
-- DB update 2025_02_03_00 -> 2025_02_03_01
--
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 25485) AND (`source_type` = 0) AND (`id` IN (0));
@@ -0,0 +1,7 @@
-- DB update 2025_02_03_01 -> 2025_02_04_00
--
-- Set questId on WP start
UPDATE `smart_scripts` SET `action_param4` = 5203 WHERE (`entryorguid` = 1101600) AND (`source_type` = 9) AND (`id` = 9);
-- Delete area explored action
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 11016) AND (`source_type` = 0) AND (`id` = 38);
UPDATE `smart_scripts` SET `link`=39 WHERE (`entryorguid` = 11016) AND (`source_type` = 0) AND (`id` = 37);
@@ -4304,6 +4304,19 @@ Event.Announce = 0
# #
################################################################################################### ###################################################################################################
###################################################################################################
# WORLD STATE
#
# Sunsreach.CounterMax
# Description: Counter value to be reached to transition phases
# during the Sun's Reach Reclamation event.
# Default: 10000
Sunsreach.CounterMax = 10000
#
###################################################################################################
################################################################################################### ###################################################################################################
# AUCTION HOUSE # AUCTION HOUSE
# #
@@ -2696,7 +2696,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
} }
case SMART_ACTION_PLAYER_TALK: case SMART_ACTION_PLAYER_TALK:
{ {
char const* text = sObjectMgr->GetAcoreString(e.action.playerTalk.textId, DEFAULT_LOCALE); std::string text = sObjectMgr->GetAcoreString(e.action.playerTalk.textId, DEFAULT_LOCALE);
if (!targets.empty()) if (!targets.empty())
for (WorldObject* target : targets) for (WorldObject* target : targets)
@@ -3282,6 +3282,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
sWorldState->HandleExternalEvent(static_cast<WorldStateEvent>(e.action.worldStateScript.eventId), e.action.worldStateScript.param); sWorldState->HandleExternalEvent(static_cast<WorldStateEvent>(e.action.worldStateScript.eventId), e.action.worldStateScript.param);
break; break;
} }
case SMART_ACTION_DISABLE_REWARD:
{
for (WorldObject* target : targets)
if (IsCreature(target))
{
target->ToCreature()->SetReputationRewardDisabled(static_cast<bool>(e.action.reward.reputation));
target->ToCreature()->SetLootRewardDisabled(static_cast<bool>(e.action.reward.loot));
}
break;
}
default: default:
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break; break;
@@ -860,6 +860,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_MOVEMENT_PAUSE: return sizeof(SmartAction::move); case SMART_ACTION_MOVEMENT_PAUSE: return sizeof(SmartAction::move);
case SMART_ACTION_MOVEMENT_RESUME: return sizeof(SmartAction::move); case SMART_ACTION_MOVEMENT_RESUME: return sizeof(SmartAction::move);
case SMART_ACTION_WORLD_SCRIPT: return sizeof(SmartAction::worldStateScript); case SMART_ACTION_WORLD_SCRIPT: return sizeof(SmartAction::worldStateScript);
case SMART_ACTION_DISABLE_REWARD: return sizeof(SmartAction::reward);
default: default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.", LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -1894,6 +1895,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return IsSAIBoolValid(e, e.action.setHealthRegen.regenHealth); return IsSAIBoolValid(e, e.action.setHealthRegen.regenHealth);
case SMART_ACTION_CALL_TIMED_ACTIONLIST: case SMART_ACTION_CALL_TIMED_ACTIONLIST:
return IsSAIBoolValid(e, e.action.timedActionList.allowOverride); return IsSAIBoolValid(e, e.action.timedActionList.allowOverride);
case SMART_ACTION_DISABLE_REWARD:
return IsSAIBoolValid(e, e.action.reward.reputation) &&
IsSAIBoolValid(e, e.action.reward.loot);
case SMART_ACTION_FLEE_FOR_ASSIST: case SMART_ACTION_FLEE_FOR_ASSIST:
case SMART_ACTION_MOVE_TO_POS: case SMART_ACTION_MOVE_TO_POS:
case SMART_ACTION_EVADE: case SMART_ACTION_EVADE:
@@ -738,8 +738,9 @@ enum SMART_ACTION
SMART_ACTION_MOVEMENT_PAUSE = 235, // timer SMART_ACTION_MOVEMENT_PAUSE = 235, // timer
SMART_ACTION_MOVEMENT_RESUME = 236, // timerOverride SMART_ACTION_MOVEMENT_RESUME = 236, // timerOverride
SMART_ACTION_WORLD_SCRIPT = 237, // eventId, param SMART_ACTION_WORLD_SCRIPT = 237, // eventId, param
SMART_ACTION_DISABLE_REWARD = 238, // reputation 0/1, loot 0/1
SMART_ACTION_AC_END = 238, // placeholder SMART_ACTION_AC_END = 239, // placeholder
}; };
enum class SmartActionSummonCreatureFlags enum class SmartActionSummonCreatureFlags
@@ -1501,6 +1502,12 @@ struct SmartAction
uint32 param5; uint32 param5;
uint32 param6; uint32 param6;
} raw; } raw;
struct
{
SAIBool reputation;
SAIBool loot;
} reward;
}; };
}; };
@@ -2438,7 +2438,7 @@ bool AchievementMgr::HasAchieved(uint32 achievementId) const
bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement) bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement)
{ {
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, nullptr)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, nullptr))
return false; return false;
if (achievement->mapID != -1 && GetPlayer()->GetMapId() != uint32(achievement->mapID)) if (achievement->mapID != -1 && GetPlayer()->GetMapId() != uint32(achievement->mapID))
@@ -2917,7 +2917,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
continue; continue;
} }
if (!GetCriteriaDataSet(criteria) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, entryId, nullptr)) if (!GetCriteriaDataSet(criteria) && !sDisableMgr->IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, entryId, nullptr))
LOG_ERROR("sql.sql", "Table `achievement_criteria_data` does not have expected data for criteria (Entry: {} Type: {}) for achievement {}.", criteria->ID, criteria->requiredType, criteria->referredAchievement); LOG_ERROR("sql.sql", "Table `achievement_criteria_data` does not have expected data for criteria (Entry: {} Type: {}) for achievement {}.", criteria->ID, criteria->requiredType, criteria->referredAchievement);
} }
+8 -11
View File
@@ -58,7 +58,8 @@ namespace Acore
void operator()(WorldPacket& data, LocaleConstant loc_idx) void operator()(WorldPacket& data, LocaleConstant loc_idx)
{ {
char const* text = sObjectMgr->GetAcoreString(_textId, loc_idx); std::string strtext = sObjectMgr->GetAcoreString(_textId, loc_idx);
char const* text = strtext.c_str();
if (_args) if (_args)
{ {
// we need copy va_list before use or original va_list will corrupted // we need copy va_list before use or original va_list will corrupted
@@ -95,9 +96,12 @@ namespace Acore
void operator()(WorldPacket& data, LocaleConstant loc_idx) void operator()(WorldPacket& data, LocaleConstant loc_idx)
{ {
char const* text = sObjectMgr->GetAcoreString(_textId, loc_idx); std::string strtext = sObjectMgr->GetAcoreString(_textId, loc_idx);
char const* arg1str = _arg1 ? sObjectMgr->GetAcoreString(_arg1, loc_idx) : ""; char const* text = strtext.c_str();
char const* arg2str = _arg2 ? sObjectMgr->GetAcoreString(_arg2, loc_idx) : ""; std::string stragr1str = sObjectMgr->GetAcoreString(_arg1, loc_idx);
char const* arg1str = _arg1 ? stragr1str.c_str() : "";
std::string strarg2str = sObjectMgr->GetAcoreString(_arg2, loc_idx);
char const* arg2str = _arg2 ? strarg2str.c_str() : "";
char str[2048]; char str[2048];
snprintf(str, 2048, text, arg1str, arg2str); snprintf(str, 2048, text, arg1str, arg2str);
@@ -1659,13 +1663,6 @@ void Battleground::EndNow()
SetEndTime(0); SetEndTime(0);
} }
// To be removed
char const* Battleground::GetAcoreString(int32 entry)
{
// FIXME: now we have different DBC locales and need localized message for each target client
return sObjectMgr->GetAcoreStringForDBCLocale(entry);
}
void Battleground::HandleTriggerBuff(GameObject* gameObject) void Battleground::HandleTriggerBuff(GameObject* gameObject)
{ {
// Xinef: crash fix? // Xinef: crash fix?
@@ -559,8 +559,6 @@ public:
void DoorOpen(uint32 type); void DoorOpen(uint32 type);
void DoorClose(uint32 type); void DoorClose(uint32 type);
//to be removed
const char* GetAcoreString(int32 entry);
virtual bool HandlePlayerUnderMap(Player* /*player*/) { return false; } virtual bool HandlePlayerUnderMap(Player* /*player*/) { return false; }
@@ -467,7 +467,7 @@ void BattlegroundMgr::LoadBattlegroundTemplates()
BattlegroundTypeId bgTypeId = static_cast<BattlegroundTypeId>(fields[0].Get<uint32>()); BattlegroundTypeId bgTypeId = static_cast<BattlegroundTypeId>(fields[0].Get<uint32>());
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId, nullptr)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId, nullptr))
continue; continue;
// can be overwrite by values from DB // can be overwrite by values from DB
+2 -2
View File
@@ -37,7 +37,7 @@ Player* ChatHandler::GetPlayer() const
return m_session ? m_session->GetPlayer() : nullptr; return m_session ? m_session->GetPlayer() : nullptr;
} }
char const* ChatHandler::GetAcoreString(uint32 entry) const std::string ChatHandler::GetAcoreString(uint32 entry) const
{ {
return m_session->GetAcoreString(entry); return m_session->GetAcoreString(entry);
} }
@@ -953,7 +953,7 @@ std::string ChatHandler::GetNameLink(Player* chr) const
return playerLink(chr->GetName()); return playerLink(chr->GetName());
} }
char const* CliHandler::GetAcoreString(uint32 entry) const std::string CliHandler::GetAcoreString(uint32 entry) const
{ {
return sObjectMgr->GetAcoreStringForDBCLocale(entry); return sObjectMgr->GetAcoreStringForDBCLocale(entry);
} }
+2 -2
View File
@@ -148,7 +148,7 @@ public:
} }
// function with different implementation for chat/console // function with different implementation for chat/console
virtual char const* GetAcoreString(uint32 entry) const; virtual std::string GetAcoreString(uint32 entry) const;
virtual void SendSysMessage(std::string_view str, bool escapeCharacters = false); virtual void SendSysMessage(std::string_view str, bool escapeCharacters = false);
void SendSysMessage(uint32 entry); void SendSysMessage(uint32 entry);
@@ -276,7 +276,7 @@ public:
explicit CliHandler(void* callbackArg, Print* zprint) : m_callbackArg(callbackArg), m_print(zprint) { } explicit CliHandler(void* callbackArg, Print* zprint) : m_callbackArg(callbackArg), m_print(zprint) { }
// overwrite functions // overwrite functions
char const* GetAcoreString(uint32 entry) const override; std::string GetAcoreString(uint32 entry) const override;
void SendSysMessage(std::string_view, bool escapeCharacters) override; void SendSysMessage(std::string_view, bool escapeCharacters) override;
bool ParseCommands(std::string_view str) override; bool ParseCommands(std::string_view str) override;
std::string GetNameLink() const override; std::string GetNameLink() const override;
@@ -24,7 +24,7 @@ void Acore::Impl::ChatCommands::SendErrorMessageToHandler(ChatHandler* handler,
handler->SetSentErrorMessage(true); handler->SetSentErrorMessage(true);
} }
char const* Acore::Impl::ChatCommands::GetAcoreString(ChatHandler const* handler, AcoreStrings which) std::string Acore::Impl::ChatCommands::GetAcoreString(ChatHandler const* handler, AcoreStrings which)
{ {
return handler->GetAcoreString(which); return handler->GetAcoreString(which);
} }
@@ -120,7 +120,7 @@ namespace Acore::Impl::ChatCommands
}; };
AC_GAME_API void SendErrorMessageToHandler(ChatHandler* handler, std::string_view str); AC_GAME_API void SendErrorMessageToHandler(ChatHandler* handler, std::string_view str);
AC_GAME_API char const* GetAcoreString(ChatHandler const* handler, AcoreStrings which); AC_GAME_API std::string GetAcoreString(ChatHandler const* handler, AcoreStrings which);
template <typename... Ts> template <typename... Ts>
std::string FormatAcoreString(ChatHandler const* handler, AcoreStrings which, Ts&&... args) std::string FormatAcoreString(ChatHandler const* handler, AcoreStrings which, Ts&&... args)
{ {
+385 -360
View File
@@ -28,393 +28,418 @@
#include "VMapMgr2.h" #include "VMapMgr2.h"
#include "World.h" #include "World.h"
namespace DisableMgr std::map<DisableType, std::map<uint32, DisableData>> DisableMgr::m_DisableMap;
DisableMgr::DisableMgr() {}
DisableMgr::~DisableMgr() {}
DisableMgr* DisableMgr::instance()
{ {
namespace static DisableMgr instance;
return &instance;
}
void DisableMgr::LoadDisables()
{
uint32 oldMSTime = getMSTime();
// reload case
for (DisableMap::iterator itr = m_DisableMap.begin(); itr != m_DisableMap.end(); ++itr)
itr->second.clear();
m_DisableMap.clear();
QueryResult result = WorldDatabase.Query("SELECT sourceType, entry, flags, params_0, params_1 FROM disables");
uint32 total_count = 0;
if (!result)
{ {
struct DisableData LOG_WARN("server.loading", ">> Loaded 0 disables. DB table `disables` is empty!");
{
uint8 flags;
std::set<uint32> params[2]; // params0, params1
};
// single disables here with optional data
typedef std::map<uint32, DisableData> DisableTypeMap;
// global disable map by source
typedef std::map<DisableType, DisableTypeMap> DisableMap;
DisableMap m_DisableMap;
uint8 MAX_DISABLE_TYPES = 11;
}
void LoadDisables()
{
uint32 oldMSTime = getMSTime();
// reload case
for (DisableMap::iterator itr = m_DisableMap.begin(); itr != m_DisableMap.end(); ++itr)
itr->second.clear();
m_DisableMap.clear();
QueryResult result = WorldDatabase.Query("SELECT sourceType, entry, flags, params_0, params_1 FROM disables");
uint32 total_count = 0;
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 disables. DB table `disables` is empty!");
LOG_INFO("server.loading", " ");
return;
}
Field* fields;
do
{
fields = result->Fetch();
DisableType type = DisableType(fields[0].Get<uint32>());
if (type >= MAX_DISABLE_TYPES)
{
LOG_ERROR("sql.sql", "Invalid type {} specified in `disables` table, skipped.", type);
continue;
}
uint32 entry = fields[1].Get<uint32>();
uint8 flags = fields[2].Get<uint8>();
std::string params_0 = fields[3].Get<std::string>();
std::string params_1 = fields[4].Get<std::string>();
DisableData data;
data.flags = flags;
switch (type)
{
case DISABLE_TYPE_GO_LOS:
if (!sObjectMgr->GetGameObjectTemplate(entry))
{
LOG_ERROR("sql.sql", "Gameobject entry {} from `disables` doesn't exist in dbc, skipped.", entry);
continue;
}
if (flags)
LOG_ERROR("sql.sql", "Disable flags specified for gameobject {}, useless data.", entry);
break;
case DISABLE_TYPE_SPELL:
if (!(sSpellMgr->GetSpellInfo(entry) || flags & SPELL_DISABLE_DEPRECATED_SPELL))
{
LOG_ERROR("sql.sql", "Spell entry {} from `disables` doesn't exist in dbc, skipped.", entry);
continue;
}
if (!flags || flags > MAX_SPELL_DISABLE_TYPE)
{
LOG_ERROR("sql.sql", "Disable flags for spell {} are invalid, skipped.", entry);
continue;
}
if (flags & SPELL_DISABLE_MAP)
{
for (std::string_view mapStr : Acore::Tokenize(params_0, ',', true))
{
if (Optional<uint32> mapId = Acore::StringTo<uint32>(mapStr))
data.params[0].insert(*mapId);
else
LOG_ERROR("sql.sql", "Disable map '{}' for spell {} is invalid, skipped.", mapStr, entry);
}
}
if (flags & SPELL_DISABLE_AREA)
{
for (std::string_view areaStr : Acore::Tokenize(params_1, ',', true))
{
if (Optional<uint32> areaId = Acore::StringTo<uint32>(areaStr))
data.params[1].insert(*areaId);
else
LOG_ERROR("sql.sql", "Disable area '{}' for spell {} is invalid, skipped.", areaStr, entry);
}
}
// xinef: if spell has disabled los, add flag
if (flags & SPELL_DISABLE_LOS)
{
SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->GetSpellInfo(entry));
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
}
break;
// checked later
case DISABLE_TYPE_QUEST:
break;
case DISABLE_TYPE_MAP:
case DISABLE_TYPE_LFG_MAP:
{
MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
if (!mapEntry)
{
LOG_ERROR("sql.sql", "Map entry {} from `disables` doesn't exist in dbc, skipped.", entry);
continue;
}
bool isFlagInvalid = false;
switch (mapEntry->map_type)
{
case MAP_COMMON:
if (flags)
isFlagInvalid = true;
break;
case MAP_INSTANCE:
case MAP_RAID:
if (flags & DUNGEON_STATUSFLAG_HEROIC && !GetMapDifficultyData(entry, DUNGEON_DIFFICULTY_HEROIC))
isFlagInvalid = true;
else if (flags & RAID_STATUSFLAG_10MAN_HEROIC && !GetMapDifficultyData(entry, RAID_DIFFICULTY_10MAN_HEROIC))
isFlagInvalid = true;
else if (flags & RAID_STATUSFLAG_25MAN_HEROIC && !GetMapDifficultyData(entry, RAID_DIFFICULTY_25MAN_HEROIC))
isFlagInvalid = true;
break;
case MAP_BATTLEGROUND:
case MAP_ARENA:
LOG_ERROR("sql.sql", "Battleground map {} specified to be disabled in map case, skipped.", entry);
continue;
}
if (isFlagInvalid)
{
LOG_ERROR("sql.sql", "Disable flags for map {} are invalid, skipped.", entry);
continue;
}
break;
}
case DISABLE_TYPE_BATTLEGROUND:
if (!sBattlemasterListStore.LookupEntry(entry))
{
LOG_ERROR("sql.sql", "Battleground entry {} from `disables` doesn't exist in dbc, skipped.", entry);
continue;
}
if (flags)
LOG_ERROR("sql.sql", "Disable flags specified for battleground {}, useless data.", entry);
break;
case DISABLE_TYPE_OUTDOORPVP:
if (entry > MAX_OUTDOORPVP_TYPES)
{
LOG_ERROR("sql.sql", "OutdoorPvPTypes value {} from `disables` is invalid, skipped.", entry);
continue;
}
if (flags)
LOG_ERROR("sql.sql", "Disable flags specified for outdoor PvP {}, useless data.", entry);
break;
case DISABLE_TYPE_ACHIEVEMENT_CRITERIA:
if (!sAchievementCriteriaStore.LookupEntry(entry))
{
LOG_ERROR("sql.sql", "Achievement Criteria entry {} from `disables` doesn't exist in dbc, skipped.", entry);
continue;
}
if (flags)
LOG_ERROR("sql.sql", "Disable flags specified for Achievement Criteria {}, useless data.", entry);
break;
case DISABLE_TYPE_VMAP:
{
MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
if (!mapEntry)
{
LOG_ERROR("sql.sql", "Map entry {} from `disables` doesn't exist in dbc, skipped.", entry);
continue;
}
switch (mapEntry->map_type)
{
case MAP_COMMON:
if (flags & VMAP::VMAP_DISABLE_AREAFLAG)
LOG_INFO("disable", "Areaflag disabled for world map {}.", entry);
if (flags & VMAP::VMAP_DISABLE_LIQUIDSTATUS)
LOG_INFO("disable", "Liquid status disabled for world map {}.", entry);
break;
case MAP_INSTANCE:
case MAP_RAID:
if (flags & VMAP::VMAP_DISABLE_HEIGHT)
LOG_INFO("disable", "Height disabled for instance map {}.", entry);
if (flags & VMAP::VMAP_DISABLE_LOS)
LOG_INFO("disable", "LoS disabled for instance map {}.", entry);
break;
case MAP_BATTLEGROUND:
if (flags & VMAP::VMAP_DISABLE_HEIGHT)
LOG_INFO("disable", "Height disabled for battleground map {}.", entry);
if (flags & VMAP::VMAP_DISABLE_LOS)
LOG_INFO("disable", "LoS disabled for battleground map {}.", entry);
break;
case MAP_ARENA:
if (flags & VMAP::VMAP_DISABLE_HEIGHT)
LOG_INFO("disable", "Height disabled for arena map {}.", entry);
if (flags & VMAP::VMAP_DISABLE_LOS)
LOG_INFO("disable", "LoS disabled for arena map {}.", entry);
break;
default:
break;
}
break;
}
case DISABLE_TYPE_GAME_EVENT:
{
GameEventMgr::ActiveEvents const& activeEvents = sGameEventMgr->GetActiveEventList();
if (activeEvents.find(entry) != activeEvents.end())
{
sGameEventMgr->StopEvent(entry);
LOG_INFO("disable", "Event entry {} was stopped because it has been disabled.", entry);
}
break;
}
case DISABLE_TYPE_LOOT:
break;
default:
break;
}
m_DisableMap[type].insert(DisableTypeMap::value_type(entry, data));
++total_count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Disables in {} ms", total_count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " "); LOG_INFO("server.loading", " ");
return;
} }
void CheckQuestDisables() Field* fields;
do
{ {
uint32 oldMSTime = getMSTime(); fields = result->Fetch();
DisableType type = DisableType(fields[0].Get<uint32>());
uint32 count = m_DisableMap[DISABLE_TYPE_QUEST].size(); if (type >= MAX_DISABLE_TYPES)
if (!count)
{ {
LOG_INFO("server.loading", ">> Checked 0 quest disables."); LOG_ERROR("sql.sql", "Invalid type {} specified in `disables` table, skipped.", type);
LOG_INFO("server.loading", " "); continue;
return;
} }
// check only quests, rest already done at startup uint32 entry = fields[1].Get<uint32>();
for (DisableTypeMap::iterator itr = m_DisableMap[DISABLE_TYPE_QUEST].begin(); itr != m_DisableMap[DISABLE_TYPE_QUEST].end();) uint8 flags = fields[2].Get<uint8>();
std::string params_0 = fields[3].Get<std::string>();
std::string params_1 = fields[4].Get<std::string>();
DisableData data;
data.flags = flags;
if (!HandleDisableType(type, entry, flags, params_0, params_1, data))
continue;
m_DisableMap[type].insert(DisableTypeMap::value_type(entry, data));
++total_count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Disables in {} ms", total_count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
/**
* @brief Allow to add disables without adding it to the database. Useful for modules.
*
* @param type Disable type
* @param entry Entry of Spell/Quest/Map/BG/Achievement/Map/GameEvent/Item
* @param flags Flag depending on Type
* @param param0 MapId if DISABLE_TYPE_SPELL used, 0 for all maps.
* @param param1 AreaId if DISABLE_TYPE_SPELL used, 0 for all areas.
*/
void DisableMgr::AddDisable(DisableType type, uint32 entry, uint8 flags, std::string param0, std::string param1)
{
if (type >= MAX_DISABLE_TYPES)
{
LOG_ERROR("disables", "AddDisable: Invalid type {} specified for entry {}, skipped.", type);
return;
}
DisableData data;
data.flags = flags;
if (!HandleDisableType(type, entry, flags, param0, param1, data))
return;
m_DisableMap[type].insert(DisableTypeMap::value_type(entry, data));
}
bool DisableMgr::HandleDisableType(DisableType type, uint32 entry, uint8 flags, std::string const& params_0, std::string const& params_1, DisableData& data)
{
switch (type)
{
case DISABLE_TYPE_GO_LOS:
if (!sObjectMgr->GetGameObjectTemplate(entry))
{ {
const uint32 entry = itr->first; LOG_ERROR("sql.sql", "Gameobject entry {} from `disables` doesn't exist in dbc, skipped.", entry);
if (!sObjectMgr->GetQuestTemplate(entry)) return false;
}
if (flags)
LOG_ERROR("sql.sql", "Disable flags specified for gameobject {}, useless data.", entry);
break;
case DISABLE_TYPE_SPELL:
if (!(sSpellMgr->GetSpellInfo(entry) || flags & SPELL_DISABLE_DEPRECATED_SPELL))
{
LOG_ERROR("sql.sql", "Spell entry {} from `disables` doesn't exist in dbc, skipped.", entry);
return false;
}
if (!flags || flags > MAX_SPELL_DISABLE_TYPE)
{
LOG_ERROR("sql.sql", "Disable flags for spell {} are invalid, skipped.", entry);
return false;
}
if (flags & SPELL_DISABLE_MAP)
{
for (std::string_view mapStr : Acore::Tokenize(params_0, ',', true))
{ {
LOG_ERROR("sql.sql", "Quest entry {} from `disables` doesn't exist, skipped.", entry); if (Optional<uint32> mapId = Acore::StringTo<uint32>(mapStr))
m_DisableMap[DISABLE_TYPE_QUEST].erase(itr++); data.params[0].insert(*mapId);
continue; else
LOG_ERROR("sql.sql", "Disable map '{}' for spell {} is invalid, skipped.", mapStr, entry);
} }
if (itr->second.flags)
LOG_ERROR("sql.sql", "Disable flags specified for quest {}, useless data.", entry);
++itr;
} }
LOG_INFO("server.loading", ">> Checked {} Quest Disables in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); if (flags & SPELL_DISABLE_AREA)
{
for (std::string_view areaStr : Acore::Tokenize(params_1, ',', true))
{
if (Optional<uint32> areaId = Acore::StringTo<uint32>(areaStr))
data.params[1].insert(*areaId);
else
LOG_ERROR("sql.sql", "Disable area '{}' for spell {} is invalid, skipped.", areaStr, entry);
}
}
// xinef: if spell has disabled los, add flag
if (flags & SPELL_DISABLE_LOS)
{
SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->GetSpellInfo(entry));
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
}
break;
// checked later
case DISABLE_TYPE_QUEST:
break;
case DISABLE_TYPE_MAP:
case DISABLE_TYPE_LFG_MAP:
{
MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
if (!mapEntry)
{
LOG_ERROR("sql.sql", "Map entry {} from `disables` doesn't exist in dbc, skipped.", entry);
return false;
}
bool isFlagInvalid = false;
switch (mapEntry->map_type)
{
case MAP_COMMON:
if (flags)
isFlagInvalid = true;
break;
case MAP_INSTANCE:
case MAP_RAID:
if (flags & DUNGEON_STATUSFLAG_HEROIC && !GetMapDifficultyData(entry, DUNGEON_DIFFICULTY_HEROIC))
isFlagInvalid = true;
else if (flags & RAID_STATUSFLAG_10MAN_HEROIC && !GetMapDifficultyData(entry, RAID_DIFFICULTY_10MAN_HEROIC))
isFlagInvalid = true;
else if (flags & RAID_STATUSFLAG_25MAN_HEROIC && !GetMapDifficultyData(entry, RAID_DIFFICULTY_25MAN_HEROIC))
isFlagInvalid = true;
break;
case MAP_BATTLEGROUND:
case MAP_ARENA:
LOG_ERROR("sql.sql", "Battleground map {} specified to be disabled in map case, skipped.", entry);
return false;
}
if (isFlagInvalid)
{
LOG_ERROR("sql.sql", "Disable flags for map {} are invalid, skipped.", entry);
return false;
}
break;
}
case DISABLE_TYPE_BATTLEGROUND:
if (!sBattlemasterListStore.LookupEntry(entry))
{
LOG_ERROR("sql.sql", "Battleground entry {} from `disables` doesn't exist in dbc, skipped.", entry);
return false;
}
if (flags)
LOG_ERROR("sql.sql", "Disable flags specified for battleground {}, useless data.", entry);
break;
case DISABLE_TYPE_OUTDOORPVP:
if (entry > MAX_OUTDOORPVP_TYPES)
{
LOG_ERROR("sql.sql", "OutdoorPvPTypes value {} from `disables` is invalid, skipped.", entry);
return false;
}
if (flags)
LOG_ERROR("sql.sql", "Disable flags specified for outdoor PvP {}, useless data.", entry);
break;
case DISABLE_TYPE_ACHIEVEMENT_CRITERIA:
if (!sAchievementCriteriaStore.LookupEntry(entry))
{
LOG_ERROR("sql.sql", "Achievement Criteria entry {} from `disables` doesn't exist in dbc, skipped.", entry);
return false;
}
if (flags)
LOG_ERROR("sql.sql", "Disable flags specified for Achievement Criteria {}, useless data.", entry);
break;
case DISABLE_TYPE_VMAP:
{
MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
if (!mapEntry)
{
LOG_ERROR("sql.sql", "Map entry {} from `disables` doesn't exist in dbc, skipped.", entry);
return false;
}
switch (mapEntry->map_type)
{
case MAP_COMMON:
if (flags & VMAP::VMAP_DISABLE_AREAFLAG)
LOG_INFO("disable", "Areaflag disabled for world map {}.", entry);
if (flags & VMAP::VMAP_DISABLE_LIQUIDSTATUS)
LOG_INFO("disable", "Liquid status disabled for world map {}.", entry);
break;
case MAP_INSTANCE:
case MAP_RAID:
if (flags & VMAP::VMAP_DISABLE_HEIGHT)
LOG_INFO("disable", "Height disabled for instance map {}.", entry);
if (flags & VMAP::VMAP_DISABLE_LOS)
LOG_INFO("disable", "LoS disabled for instance map {}.", entry);
break;
case MAP_BATTLEGROUND:
if (flags & VMAP::VMAP_DISABLE_HEIGHT)
LOG_INFO("disable", "Height disabled for battleground map {}.", entry);
if (flags & VMAP::VMAP_DISABLE_LOS)
LOG_INFO("disable", "LoS disabled for battleground map {}.", entry);
break;
case MAP_ARENA:
if (flags & VMAP::VMAP_DISABLE_HEIGHT)
LOG_INFO("disable", "Height disabled for arena map {}.", entry);
if (flags & VMAP::VMAP_DISABLE_LOS)
LOG_INFO("disable", "LoS disabled for arena map {}.", entry);
break;
default:
break;
}
break;
}
case DISABLE_TYPE_GAME_EVENT:
{
GameEventMgr::ActiveEvents const& activeEvents = sGameEventMgr->GetActiveEventList();
if (activeEvents.find(entry) != activeEvents.end())
{
sGameEventMgr->StopEvent(entry);
LOG_INFO("disable", "Event entry {} was stopped because it has been disabled.", entry);
}
break;
}
case DISABLE_TYPE_LOOT:
break;
case MAX_DISABLE_TYPES:
{
LOG_ERROR("disable", "SourceType out of range for entry {}, skipped", entry);
return false;
}
default:
return false;
}
return true;
}
void DisableMgr::CheckQuestDisables()
{
uint32 oldMSTime = getMSTime();
uint32 count = m_DisableMap[DISABLE_TYPE_QUEST].size();
if (!count)
{
LOG_INFO("server.loading", ">> Checked 0 quest disables.");
LOG_INFO("server.loading", " "); LOG_INFO("server.loading", " ");
return;
} }
bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags) // check only quests, rest already done at startup
for (DisableTypeMap::iterator itr = m_DisableMap[DISABLE_TYPE_QUEST].begin(); itr != m_DisableMap[DISABLE_TYPE_QUEST].end();)
{ {
if (type > MAX_DISABLE_TYPES) const uint32 entry = itr->first;
if (!sObjectMgr->GetQuestTemplate(entry))
{ {
LOG_ERROR("server", "Disables::IsDisabledFor() called with unknown disable type {}! (entry {}, flags {}).", type, entry, flags); LOG_ERROR("sql.sql", "Quest entry {} from `disables` doesn't exist, skipped.", entry);
return false; m_DisableMap[DISABLE_TYPE_QUEST].erase(itr++);
continue;
} }
if (itr->second.flags)
LOG_ERROR("sql.sql", "Disable flags specified for quest {}, useless data.", entry);
++itr;
}
if (m_DisableMap[type].empty()) LOG_INFO("server.loading", ">> Checked {} Quest Disables in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
return false; LOG_INFO("server.loading", " ");
}
DisableTypeMap::iterator itr = m_DisableMap[type].find(entry);
if (itr == m_DisableMap[type].end()) // not disabled
return false;
switch (type)
{
case DISABLE_TYPE_SPELL:
{
uint8 spellFlags = itr->second.flags;
if (unit)
{
if ((spellFlags & SPELL_DISABLE_PLAYER && unit->IsPlayer()) ||
(unit->IsCreature() && ((unit->IsPet() && spellFlags & SPELL_DISABLE_PET) || spellFlags & SPELL_DISABLE_CREATURE)))
{
if (spellFlags & SPELL_DISABLE_MAP)
{
std::set<uint32> const& mapIds = itr->second.params[0];
if (mapIds.find(unit->GetMapId()) != mapIds.end())
return true; // Spell is disabled on current map
if (!(spellFlags & SPELL_DISABLE_AREA))
return false; // Spell is disabled on another map, but not this one, return false
// Spell is disabled in an area, but not explicitly our current mapId. Continue processing.
}
if (spellFlags & SPELL_DISABLE_AREA)
{
std::set<uint32> const& areaIds = itr->second.params[1];
if (areaIds.find(unit->GetAreaId()) != areaIds.end())
return true; // Spell is disabled in this area
return false; // Spell is disabled in another area, but not this one, return false
}
else
return true; // Spell disabled for all maps
}
return false;
}
else if (spellFlags & SPELL_DISABLE_DEPRECATED_SPELL) // call not from spellcast
return true;
break;
}
case DISABLE_TYPE_MAP:
case DISABLE_TYPE_LFG_MAP:
if (Player const* player = unit->ToPlayer())
{
MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
if (mapEntry->IsDungeon())
{
uint8 disabledModes = itr->second.flags;
Difficulty targetDifficulty = player->GetDifficulty(mapEntry->IsRaid());
GetDownscaledMapDifficultyData(entry, targetDifficulty);
switch (targetDifficulty)
{
case DUNGEON_DIFFICULTY_NORMAL:
return disabledModes & DUNGEON_STATUSFLAG_NORMAL;
case DUNGEON_DIFFICULTY_HEROIC:
return disabledModes & DUNGEON_STATUSFLAG_HEROIC;
case RAID_DIFFICULTY_10MAN_HEROIC:
return disabledModes & RAID_STATUSFLAG_10MAN_HEROIC;
case RAID_DIFFICULTY_25MAN_HEROIC:
return disabledModes & RAID_STATUSFLAG_25MAN_HEROIC;
}
}
else if (mapEntry->map_type == MAP_COMMON)
return true;
}
return false;
case DISABLE_TYPE_QUEST:
return true;
case DISABLE_TYPE_BATTLEGROUND:
case DISABLE_TYPE_OUTDOORPVP:
case DISABLE_TYPE_ACHIEVEMENT_CRITERIA:
return true;
case DISABLE_TYPE_VMAP:
return flags & itr->second.flags;
case DISABLE_TYPE_GO_LOS:
return true;
case DISABLE_TYPE_GAME_EVENT:
return true;
case DISABLE_TYPE_LOOT:
return true;
}
bool DisableMgr::IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags)
{
if (type >= MAX_DISABLE_TYPES)
{
LOG_ERROR("server", "Disables::IsDisabledFor() called with unknown disable type {}! (entry {}, flags {}).", type, entry, flags);
return false; return false;
} }
bool IsVMAPDisabledFor(uint32 entry, uint8 flags) if (m_DisableMap[type].empty())
{ return false;
return IsDisabledFor(DISABLE_TYPE_VMAP, entry, nullptr, flags);
}
bool IsPathfindingEnabled(const Map* map) DisableTypeMap::iterator itr = m_DisableMap[type].find(entry);
if (itr == m_DisableMap[type].end()) // not disabled
return false;
switch (type)
{ {
if (!map) case DISABLE_TYPE_SPELL:
{
uint8 spellFlags = itr->second.flags;
if (unit)
{
if ((spellFlags & SPELL_DISABLE_PLAYER && unit->IsPlayer()) ||
(unit->IsCreature() && ((unit->IsPet() && spellFlags & SPELL_DISABLE_PET) || spellFlags & SPELL_DISABLE_CREATURE)))
{
if (spellFlags & SPELL_DISABLE_MAP)
{
std::set<uint32> const& mapIds = itr->second.params[0];
if (mapIds.find(unit->GetMapId()) != mapIds.end())
return true; // Spell is disabled on current map
if (!(spellFlags & SPELL_DISABLE_AREA))
return false; // Spell is disabled on another map, but not this one, return false
// Spell is disabled in an area, but not explicitly our current mapId. Continue processing.
}
if (spellFlags & SPELL_DISABLE_AREA)
{
std::set<uint32> const& areaIds = itr->second.params[1];
if (areaIds.find(unit->GetAreaId()) != areaIds.end())
return true; // Spell is disabled in this area
return false; // Spell is disabled in another area, but not this one, return false
}
else
return true; // Spell disabled for all maps
}
return false;
}
else if (spellFlags & SPELL_DISABLE_DEPRECATED_SPELL) // call not from spellcast
return true;
break;
}
case DISABLE_TYPE_MAP:
case DISABLE_TYPE_LFG_MAP:
if (Player const* player = unit->ToPlayer())
{
MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
if (mapEntry->IsDungeon())
{
uint8 disabledModes = itr->second.flags;
Difficulty targetDifficulty = player->GetDifficulty(mapEntry->IsRaid());
GetDownscaledMapDifficultyData(entry, targetDifficulty);
switch (targetDifficulty)
{
case DUNGEON_DIFFICULTY_NORMAL:
return disabledModes & DUNGEON_STATUSFLAG_NORMAL;
case DUNGEON_DIFFICULTY_HEROIC:
return disabledModes & DUNGEON_STATUSFLAG_HEROIC;
case RAID_DIFFICULTY_10MAN_HEROIC:
return disabledModes & RAID_STATUSFLAG_10MAN_HEROIC;
case RAID_DIFFICULTY_25MAN_HEROIC:
return disabledModes & RAID_STATUSFLAG_25MAN_HEROIC;
}
}
else if (mapEntry->map_type == MAP_COMMON)
return true;
}
return false; return false;
case DISABLE_TYPE_VMAP:
return !MMAP::MMapFactory::forbiddenMaps[map->GetId()] && (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena()); return flags & itr->second.flags;
case DISABLE_TYPE_QUEST:
case DISABLE_TYPE_BATTLEGROUND:
case DISABLE_TYPE_OUTDOORPVP:
case DISABLE_TYPE_ACHIEVEMENT_CRITERIA:
case DISABLE_TYPE_GO_LOS:
case DISABLE_TYPE_GAME_EVENT:
case DISABLE_TYPE_LOOT:
return true;
default:
break;
} }
} // Namespace return false;
}
bool DisableMgr::IsVMAPDisabledFor(uint32 entry, uint8 flags)
{
return IsDisabledFor(DISABLE_TYPE_VMAP, entry, nullptr, flags);
}
bool DisableMgr::IsPathfindingEnabled(Map const* map)
{
if (!map)
return false;
return !MMAP::MMapFactory::forbiddenMaps[map->GetId()] && (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena());
}
+40 -14
View File
@@ -15,8 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef ACORE_DISABLEMGR_H #ifndef _DISABLEMGR_H
#define ACORE_DISABLEMGR_H #define _DISABLEMGR_H
#include "Define.h" #include "Define.h"
#include "Map.h" #include "Map.h"
@@ -34,7 +34,8 @@ enum DisableType
DISABLE_TYPE_GO_LOS = 7, DISABLE_TYPE_GO_LOS = 7,
DISABLE_TYPE_LFG_MAP = 8, DISABLE_TYPE_LFG_MAP = 8,
DISABLE_TYPE_GAME_EVENT = 9, DISABLE_TYPE_GAME_EVENT = 9,
DISABLE_TYPE_LOOT = 10 DISABLE_TYPE_LOOT = 10,
MAX_DISABLE_TYPES
}; };
enum SpellDisableTypes enum SpellDisableTypes
@@ -46,18 +47,43 @@ enum SpellDisableTypes
SPELL_DISABLE_MAP = 0x10, SPELL_DISABLE_MAP = 0x10,
SPELL_DISABLE_AREA = 0x20, SPELL_DISABLE_AREA = 0x20,
SPELL_DISABLE_LOS = 0x40, SPELL_DISABLE_LOS = 0x40,
MAX_SPELL_DISABLE_TYPE = ( SPELL_DISABLE_PLAYER | SPELL_DISABLE_CREATURE | SPELL_DISABLE_PET | MAX_SPELL_DISABLE_TYPE = (SPELL_DISABLE_PLAYER | SPELL_DISABLE_CREATURE | SPELL_DISABLE_PET |
SPELL_DISABLE_DEPRECATED_SPELL | SPELL_DISABLE_MAP | SPELL_DISABLE_AREA | SPELL_DISABLE_DEPRECATED_SPELL | SPELL_DISABLE_MAP | SPELL_DISABLE_AREA |
SPELL_DISABLE_LOS) SPELL_DISABLE_LOS)
}; };
namespace DisableMgr struct DisableData
{ {
void LoadDisables(); uint8 flags;
bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags = 0); std::set<uint32> params[2]; // params0, params1
void CheckQuestDisables(); };
bool IsVMAPDisabledFor(uint32 entry, uint8 flags);
bool IsPathfindingEnabled(const Map* map);
}
#endif //ACORE_DISABLEMGR_H class DisableMgr
{
private:
DisableMgr();
~DisableMgr();
public:
static DisableMgr* instance();
void LoadDisables();
void AddDisable(DisableType type, uint32 entry, uint8 flags, std::string param0, std::string param1);
bool HandleDisableType(DisableType type, uint32 entry, uint8 flags, std::string const& params_0, std::string const& params_1, DisableData& data);
static bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags = 0);
void CheckQuestDisables();
static bool IsVMAPDisabledFor(uint32 entry, uint8 flags);
static bool IsPathfindingEnabled(Map const* map);
private:
// single disables here with optional data
typedef std::map<uint32, DisableData> DisableTypeMap;
// global disable map by source
typedef std::map<DisableType, DisableTypeMap> DisableMap;
static DisableMap m_DisableMap;
};
#define sDisableMgr DisableMgr::instance()
#endif //_DISABLEMGR_H
+2 -2
View File
@@ -410,9 +410,9 @@ namespace lfg
uint32 lockData = 0; uint32 lockData = 0;
if (dungeon->expansion > expansion || (onlySeasonalBosses && !dungeon->seasonal)) if (dungeon->expansion > expansion || (onlySeasonalBosses && !dungeon->seasonal))
lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION;
else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player)) else if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player))
lockData = LFG_LOCKSTATUS_RAID_LOCKED; lockData = LFG_LOCKSTATUS_RAID_LOCKED;
else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_LFG_MAP, dungeon->map, player)) else if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_LFG_MAP, dungeon->map, player))
lockData = LFG_LOCKSTATUS_RAID_LOCKED; lockData = LFG_LOCKSTATUS_RAID_LOCKED;
else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && (!mapEntry || !mapEntry->IsRaid()) && sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUID(), dungeon->map, Difficulty(dungeon->difficulty))) else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && (!mapEntry || !mapEntry->IsRaid()) && sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUID(), dungeon->map, Difficulty(dungeon->difficulty)))
lockData = LFG_LOCKSTATUS_RAID_LOCKED; lockData = LFG_LOCKSTATUS_RAID_LOCKED;
@@ -286,7 +286,9 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(),
m_ProhibitSchoolTime[i] = 0; m_ProhibitSchoolTime[i] = 0;
m_CreatureSpellCooldowns.clear(); m_CreatureSpellCooldowns.clear();
DisableReputationGain = false;
DisableReputationReward = false;
DisableLootReward = false;
m_SightDistance = sWorld->getFloatConfig(CONFIG_SIGHT_MONSTER); m_SightDistance = sWorld->getFloatConfig(CONFIG_SIGHT_MONSTER);
m_CombatDistance = 0.0f; m_CombatDistance = 0.0f;
+6 -3
View File
@@ -359,8 +359,10 @@ public:
Unit* SelectVictim(); Unit* SelectVictim();
void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; } void SetReputationRewardDisabled(bool disable) { DisableReputationReward = disable; }
[[nodiscard]] bool IsReputationGainDisabled() const { return DisableReputationGain; } [[nodiscard]] bool IsReputationRewardDisabled() const { return DisableReputationReward; }
void SetLootRewardDisabled(bool disable) { DisableLootReward = disable; }
[[nodiscard]] bool IsLootRewardDisabled() const { return DisableLootReward; }
[[nodiscard]] bool IsDamageEnoughForLootingAndReward() const; [[nodiscard]] bool IsDamageEnoughForLootingAndReward() const;
void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true); void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true);
void ResetPlayerDamageReq(); void ResetPlayerDamageReq();
@@ -478,7 +480,8 @@ protected:
Position m_homePosition; Position m_homePosition;
Position m_transportHomePosition; Position m_transportHomePosition;
bool DisableReputationGain; bool DisableReputationReward;
bool DisableLootReward;
CreatureTemplate const* m_creatureInfo; // in difficulty mode > 0 can different from sObjectMgr->GetCreatureTemplate(GetEntry()) CreatureTemplate const* m_creatureInfo; // in difficulty mode > 0 can different from sObjectMgr->GetCreatureTemplate(GetEntry())
CreatureData const* m_creatureData; CreatureData const* m_creatureData;
@@ -2594,7 +2594,7 @@ void GameObject::EnableCollision(bool enable)
GetMap()->InsertGameObjectModel(*m_model);*/ GetMap()->InsertGameObjectModel(*m_model);*/
uint32 phaseMask = 0; uint32 phaseMask = 0;
if (enable && !DisableMgr::IsDisabledFor(DISABLE_TYPE_GO_LOS, GetEntry(), nullptr)) if (enable && !sDisableMgr->IsDisabledFor(DISABLE_TYPE_GO_LOS, GetEntry(), nullptr))
phaseMask = GetPhaseMask(); phaseMask = GetPhaseMask();
m_model->enable(phaseMask); m_model->enable(phaseMask);
+7 -2
View File
@@ -1340,7 +1340,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
return false; return false;
} }
if (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, mapid, this)) if (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && sDisableMgr->IsDisabledFor(DISABLE_TYPE_MAP, mapid, this))
{ {
LOG_ERROR("entities.player", "Player ({}, name: {}) tried to enter a forbidden map {}", GetGUID().ToString(), GetName(), mapid); LOG_ERROR("entities.player", "Player ({}, name: {}) tried to enter a forbidden map {}", GetGUID().ToString(), GetName(), mapid);
SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED); SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED);
@@ -4493,6 +4493,9 @@ void Player::BuildPlayerRepop()
void Player::ResurrectPlayer(float restore_percent, bool applySickness) void Player::ResurrectPlayer(float restore_percent, bool applySickness)
{ {
if (!sScriptMgr->CanPlayerResurrect(this))
return;
WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4 * 4); // remove spirit healer position WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4 * 4); // remove spirit healer position
data << uint32(-1); data << uint32(-1);
data << float(0); data << float(0);
@@ -5993,7 +5996,7 @@ void Player::RewardReputation(Unit* victim)
if (!victim || victim->IsPlayer()) if (!victim || victim->IsPlayer())
return; return;
if (victim->ToCreature()->IsReputationGainDisabled()) if (victim->ToCreature()->IsReputationRewardDisabled())
return; return;
ReputationOnKillEntry const* Rep = sObjectMgr->GetReputationOnKilEntry(victim->ToCreature()->GetCreatureTemplate()->Entry); ReputationOnKillEntry const* Rep = sObjectMgr->GetReputationOnKilEntry(victim->ToCreature()->GetCreatureTemplate()->Entry);
@@ -8858,6 +8861,8 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
} }
} }
sWorldState->FillInitialWorldStates(data, zoneid, areaid);
uint16 length = (data.wpos() - countPos) / 8; uint16 length = (data.wpos() - countPos) / 8;
data.put<uint16>(countPos, length); data.put<uint16>(countPos, length);
+4
View File
@@ -1728,6 +1728,10 @@ public:
[[nodiscard]] bool HasTalent(uint32 spell_id, uint8 spec) const; [[nodiscard]] bool HasTalent(uint32 spell_id, uint8 spec) const;
[[nodiscard]] uint32 CalculateTalentsPoints() const; [[nodiscard]] uint32 CalculateTalentsPoints() const;
void SetBonusTalentCount(uint32 count) { m_extraBonusTalentCount = count; };
uint32 GetBonusTalentCount() { return m_extraBonusTalentCount; };
void AddBonusTalent(uint32 count) { m_extraBonusTalentCount += count; };
void RemoveBonusTalent(uint32 count) { m_extraBonusTalentCount -= count; };
// Dual Spec // Dual Spec
void UpdateSpecCount(uint8 count); void UpdateSpecCount(uint8 count);
@@ -236,7 +236,7 @@ Quest const* Player::GetNextQuest(ObjectGuid guid, Quest const* quest)
bool Player::CanSeeStartQuest(Quest const* quest) bool Player::CanSeeStartQuest(Quest const* quest)
{ {
if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) && if (!sDisableMgr->IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) &&
SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) && SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) &&
SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) && SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) &&
SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) && SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
@@ -250,7 +250,7 @@ bool Player::CanSeeStartQuest(Quest const* quest)
bool Player::CanTakeQuest(Quest const* quest, bool msg) bool Player::CanTakeQuest(Quest const* quest, bool msg)
{ {
return !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) return !sDisableMgr->IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this)
&& SatisfyQuestStatus(quest, msg) && SatisfyQuestExclusiveGroup(quest, msg) && SatisfyQuestStatus(quest, msg) && SatisfyQuestExclusiveGroup(quest, msg)
&& SatisfyQuestClass(quest, msg) && SatisfyQuestRace(quest, msg) && SatisfyQuestLevel(quest, msg) && SatisfyQuestClass(quest, msg) && SatisfyQuestRace(quest, msg) && SatisfyQuestLevel(quest, msg)
&& SatisfyQuestSkill(quest, msg) && SatisfyQuestReputation(quest, msg) && SatisfyQuestSkill(quest, msg) && SatisfyQuestReputation(quest, msg)
@@ -5619,7 +5619,7 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
bool Player::isAllowedToLoot(Creature const* creature) bool Player::isAllowedToLoot(Creature const* creature)
{ {
if (!creature->isDead() || !creature->IsDamageEnoughForLootingAndReward()) if (!creature->isDead() || !creature->IsDamageEnoughForLootingAndReward() || creature->IsLootRewardDisabled())
return false; return false;
if (HasPendingBind()) if (HasPendingBind())
@@ -6722,7 +6722,7 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map
LevelMax = ar->levelMax; LevelMax = ar->levelMax;
} }
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, target_map, this)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_MAP, target_map, this))
{ {
GetSession()->SendAreaTriggerMessage("{}", GetSession()->GetAcoreString(LANG_INSTANCE_CLOSED)); GetSession()->SendAreaTriggerMessage("{}", GetSession()->GetAcoreString(LANG_INSTANCE_CLOSED));
return false; return false;
@@ -555,7 +555,7 @@ void Player::UpdateLocalChannels(uint32 newZone)
if (channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY) if (channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY)
currentNameExt = sObjectMgr->GetAcoreStringForDBCLocale( currentNameExt = sObjectMgr->GetAcoreStringForDBCLocale(
LANG_CHANNEL_CITY); LANG_CHANNEL_CITY).c_str();
else else
currentNameExt = current_zone_name.c_str(); currentNameExt = current_zone_name.c_str();
+8 -2
View File
@@ -17798,7 +17798,7 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
bool isRewardAllowed = true; bool isRewardAllowed = true;
if (creature) if (creature)
{ {
isRewardAllowed = creature->IsDamageEnoughForLootingAndReward(); isRewardAllowed = (creature->IsDamageEnoughForLootingAndReward() && !creature->IsLootRewardDisabled());
if (!isRewardAllowed) if (!isRewardAllowed)
creature->SetLootRecipient(nullptr); creature->SetLootRecipient(nullptr);
} }
@@ -20444,7 +20444,7 @@ void Unit::PetSpellFail(SpellInfo const* spellInfo, Unit* target, uint32 result)
if (!charmInfo || !IsCreature()) if (!charmInfo || !IsCreature())
return; return;
if ((DisableMgr::IsPathfindingEnabled(GetMap()) || result != SPELL_FAILED_LINE_OF_SIGHT) && target) if ((sDisableMgr->IsPathfindingEnabled(GetMap()) || result != SPELL_FAILED_LINE_OF_SIGHT) && target)
{ {
if ((result == SPELL_FAILED_LINE_OF_SIGHT || result == SPELL_FAILED_OUT_OF_RANGE) || !ToCreature()->HasReactState(REACT_PASSIVE)) if ((result == SPELL_FAILED_LINE_OF_SIGHT || result == SPELL_FAILED_OUT_OF_RANGE) || !ToCreature()->HasReactState(REACT_PASSIVE))
if (Unit* owner = GetOwner()) if (Unit* owner = GetOwner())
@@ -21355,6 +21355,12 @@ bool Unit::CanRestoreMana(SpellInfo const* spellInfo) const
return false; return false;
} }
void Unit::SetShapeshiftForm(ShapeshiftForm form)
{
SetByteValue(UNIT_FIELD_BYTES_2, 3, form);
sScriptMgr->OnUnitSetShapeshiftForm((Unit*)this, form);
}
bool Unit::IsInDisallowedMountForm() const bool Unit::IsInDisallowedMountForm() const
{ {
if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(getTransForm())) if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(getTransForm()))
+1 -4
View File
@@ -1869,10 +1869,7 @@ public:
// ShapeShitForm (use by druid) // ShapeShitForm (use by druid)
[[nodiscard]] ShapeshiftForm GetShapeshiftForm() const { return ShapeshiftForm(GetByteValue(UNIT_FIELD_BYTES_2, 3)); } [[nodiscard]] ShapeshiftForm GetShapeshiftForm() const { return ShapeshiftForm(GetByteValue(UNIT_FIELD_BYTES_2, 3)); }
void SetShapeshiftForm(ShapeshiftForm form) void SetShapeshiftForm(ShapeshiftForm form);
{
SetByteValue(UNIT_FIELD_BYTES_2, 3, form);
}
bool IsAttackSpeedOverridenShapeShift() const; bool IsAttackSpeedOverridenShapeShift() const;
[[nodiscard]] bool IsInFeralForm() const [[nodiscard]] bool IsInFeralForm() const
{ {
+1 -1
View File
@@ -133,7 +133,7 @@ void GameEventMgr::StartInternalEvent(uint16 event_id)
bool GameEventMgr::StartEvent(uint16 event_id, bool overwrite) bool GameEventMgr::StartEvent(uint16 event_id, bool overwrite)
{ {
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_GAME_EVENT, event_id, nullptr) && !overwrite) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_GAME_EVENT, event_id, nullptr) && !overwrite)
{ {
return false; return false;
} }
+12 -11
View File
@@ -3072,7 +3072,7 @@ void ObjectMgr::LoadItemTemplates()
else if (itemTemplate.Spells[1].SpellId != -1) else if (itemTemplate.Spells[1].SpellId != -1)
{ {
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemTemplate.Spells[1].SpellId); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemTemplate.Spells[1].SpellId);
if (!spellInfo && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, itemTemplate.Spells[1].SpellId, nullptr)) if (!spellInfo && !sDisableMgr->IsDisabledFor(DISABLE_TYPE_SPELL, itemTemplate.Spells[1].SpellId, nullptr))
{ {
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong (not existing) spell in spellid_{} ({})", entry, 1 + 1, itemTemplate.Spells[1].SpellId); LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong (not existing) spell in spellid_{} ({})", entry, 1 + 1, itemTemplate.Spells[1].SpellId);
itemTemplate.Spells[0].SpellId = 0; itemTemplate.Spells[0].SpellId = 0;
@@ -3120,7 +3120,7 @@ void ObjectMgr::LoadItemTemplates()
if (itemTemplate.Spells[j].SpellId && itemTemplate.Spells[j].SpellId != -1) if (itemTemplate.Spells[j].SpellId && itemTemplate.Spells[j].SpellId != -1)
{ {
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemTemplate.Spells[j].SpellId); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemTemplate.Spells[j].SpellId);
if (!spellInfo && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, itemTemplate.Spells[j].SpellId, nullptr)) if (!spellInfo && !sDisableMgr->IsDisabledFor(DISABLE_TYPE_SPELL, itemTemplate.Spells[j].SpellId, nullptr))
{ {
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong (not existing) spell in spellid_{} ({})", entry, j + 1, itemTemplate.Spells[j].SpellId); LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong (not existing) spell in spellid_{} ({})", entry, j + 1, itemTemplate.Spells[j].SpellId);
itemTemplate.Spells[j].SpellId = 0; itemTemplate.Spells[j].SpellId = 0;
@@ -4616,7 +4616,7 @@ void ObjectMgr::LoadQuests()
for (QuestMap::iterator iter = _questTemplates.begin(); iter != _questTemplates.end(); ++iter) for (QuestMap::iterator iter = _questTemplates.begin(); iter != _questTemplates.end(); ++iter)
{ {
// skip post-loading checks for disabled quests // skip post-loading checks for disabled quests
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, iter->first, nullptr)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_QUEST, iter->first, nullptr))
continue; continue;
Quest* qinfo = iter->second; Quest* qinfo = iter->second;
@@ -8770,19 +8770,20 @@ bool ObjectMgr::LoadAcoreStrings()
return true; return true;
} }
char const* ObjectMgr::GetAcoreString(uint32 entry, LocaleConstant locale) const std::string ObjectMgr::GetAcoreString(uint32 entry, LocaleConstant locale) const
{ {
if (AcoreString const* ts = GetAcoreString(entry)) AcoreString const* as = GetAcoreString(entry);
if (as && !as->Content.empty())
{ {
if (ts->Content.size() > std::size_t(locale) && !ts->Content[locale].empty()) if (as->Content.size() > std::size_t(locale) && !as->Content[locale].empty())
return ts->Content[locale].c_str(); return as->Content[locale];
return ts->Content[DEFAULT_LOCALE].c_str(); return as->Content[DEFAULT_LOCALE];
} }
LOG_ERROR("sql.sql", "Acore string entry {} not found in DB.", entry); std::string msg = Acore::StringFormat("No entry for acore_string ({}) in DB.", entry);
LOG_ERROR("sql.sql", msg);
return "<error>"; return msg;
} }
void ObjectMgr::LoadFishingBaseSkillLevel() void ObjectMgr::LoadFishingBaseSkillLevel()
+2 -2
View File
@@ -1315,8 +1315,8 @@ public:
return &itr->second; return &itr->second;
} }
[[nodiscard]] char const* GetAcoreString(uint32 entry, LocaleConstant locale) const; [[nodiscard]] std::string GetAcoreString(uint32 entry, LocaleConstant locale) const;
[[nodiscard]] char const* GetAcoreStringForDBCLocale(uint32 entry) const { return GetAcoreString(entry, DBCLocaleIndex); } [[nodiscard]] std::string GetAcoreStringForDBCLocale(uint32 entry) const { return GetAcoreString(entry, DBCLocaleIndex); }
[[nodiscard]] LocaleConstant GetDBCLocaleIndex() const { return DBCLocaleIndex; } [[nodiscard]] LocaleConstant GetDBCLocaleIndex() const { return DBCLocaleIndex; }
void SetDBCLocaleIndex(LocaleConstant locale) { DBCLocaleIndex = locale; } void SetDBCLocaleIndex(LocaleConstant locale) { DBCLocaleIndex = locale; }
@@ -90,7 +90,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
} }
// chosen battleground type is disabled // chosen battleground type is disabled
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, nullptr)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, nullptr))
{ {
ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED);
return; return;
@@ -721,7 +721,7 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData)
} }
// arenas disabled // arenas disabled
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, BATTLEGROUND_AA, nullptr)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, BATTLEGROUND_AA, nullptr))
{ {
ChatHandler(this).PSendSysMessage(LANG_ARENA_DISABLED); ChatHandler(this).PSendSysMessage(LANG_ARENA_DISABLED);
return; return;
+1 -1
View File
@@ -158,7 +158,7 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/)
{ {
HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(entry); HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(entry);
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_GAME_EVENT, sGameEventMgr->GetHolidayEventId(holiday->Id), nullptr)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_GAME_EVENT, sGameEventMgr->GetHolidayEventId(holiday->Id), nullptr))
{ {
continue; continue;
} }
+1 -1
View File
@@ -232,7 +232,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
return; return;
// Not let attack through obstructions // Not let attack through obstructions
bool checkLos = !DisableMgr::IsPathfindingEnabled(pet->GetMap()) || bool checkLos = !sDisableMgr->IsPathfindingEnabled(pet->GetMap()) ||
(TargetUnit->IsCreature() && (TargetUnit->ToCreature()->isWorldBoss() || TargetUnit->ToCreature()->IsDungeonBoss())); (TargetUnit->IsCreature() && (TargetUnit->ToCreature()->isWorldBoss() || TargetUnit->ToCreature()->IsDungeonBoss()));
if (checkLos && !pet->IsWithinLOSInMap(TargetUnit)) if (checkLos && !pet->IsWithinLOSInMap(TargetUnit))
+1 -1
View File
@@ -421,7 +421,7 @@ bool LootItem::AllowedForPlayer(Player const* player, ObjectGuid source) const
return false; return false;
} }
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_LOOT, itemid, nullptr)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_LOOT, itemid, nullptr))
{ {
return false; return false;
} }
+1 -1
View File
@@ -145,7 +145,7 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy)
void Map::LoadMMap(int gx, int gy) void Map::LoadMMap(int gx, int gy)
{ {
if (!DisableMgr::IsPathfindingEnabled(this)) // pussywizard if (!sDisableMgr->IsPathfindingEnabled(this)) // pussywizard
return; return;
int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(GetId(), gx, gy); int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(GetId(), gx, gy);
+1 -2
View File
@@ -1169,8 +1169,7 @@ enum AcoreStrings
LANG_GM_SILENCE = 6616, // "Silence is ON for %s" - Spell 1852 LANG_GM_SILENCE = 6616, // "Silence is ON for %s" - Spell 1852
// Used for .string command // Free strings 6617-7522
LANG_NO_ACORE_STRING_FOUND = 6617,
LANG_WORLD_CLOSED = 7523, LANG_WORLD_CLOSED = 7523,
LANG_WORLD_OPENED = 7524, LANG_WORLD_OPENED = 7524,
@@ -63,7 +63,7 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner)
} }
owner->UpdateAllowedPositionZ(x, y, z); owner->UpdateAllowedPositionZ(x, y, z);
init.MoveTo(x, y, z, DisableMgr::IsPathfindingEnabled(owner->FindMap()), true); init.MoveTo(x, y, z, sDisableMgr->IsPathfindingEnabled(owner->FindMap()), true);
init.SetWalk(_walk); init.SetWalk(_walk);
init.Launch(); init.Launch();
@@ -35,7 +35,7 @@ PathGenerator::PathGenerator(WorldObject const* owner) :
memset(_pathPolyRefs, 0, sizeof(_pathPolyRefs)); memset(_pathPolyRefs, 0, sizeof(_pathPolyRefs));
uint32 mapId = _source->GetMapId(); uint32 mapId = _source->GetMapId();
//if (DisableMgr::IsPathfindingEnabled(_sourceUnit->FindMap())) //if (sDisableMgr->IsPathfindingEnabled(_sourceUnit->FindMap()))
{ {
MMAP::MMapMgr* mmap = MMAP::MMapFactory::createOrGetMMapMgr(); MMAP::MMapMgr* mmap = MMAP::MMapFactory::createOrGetMMapMgr();
_navMesh = mmap->GetNavMesh(mapId); _navMesh = mmap->GetNavMesh(mapId);
+1 -1
View File
@@ -60,7 +60,7 @@ void OutdoorPvPMgr::InitOutdoorPvP()
{ {
typeId = fields[0].Get<uint8>(); typeId = fields[0].Get<uint8>();
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_OUTDOORPVP, typeId, nullptr)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_OUTDOORPVP, typeId, nullptr))
continue; continue;
if (typeId >= MAX_OUTDOORPVP_TYPES) if (typeId >= MAX_OUTDOORPVP_TYPES)
@@ -903,6 +903,11 @@ bool ScriptMgr::AnticheatCheckMovementInfo(Player* player, MovementInfo const& m
CALL_ENABLED_BOOLEAN_HOOKS(PlayerScript, PLAYERHOOK_ANTICHEAT_CHECK_MOVEMENT_INFO, !script->AnticheatCheckMovementInfo(player, movementInfo, mover, jump)); CALL_ENABLED_BOOLEAN_HOOKS(PlayerScript, PLAYERHOOK_ANTICHEAT_CHECK_MOVEMENT_INFO, !script->AnticheatCheckMovementInfo(player, movementInfo, mover, jump));
} }
bool ScriptMgr::CanPlayerResurrect(Player* player)
{
CALL_ENABLED_BOOLEAN_HOOKS(PlayerScript, PLAYERHOOK_CAN_RESURRECT, !script->CanPlayerResurrect(player));
}
PlayerScript::PlayerScript(const char* name, std::vector<uint16> enabledHooks) PlayerScript::PlayerScript(const char* name, std::vector<uint16> enabledHooks)
: ScriptObject(name, PLAYERHOOK_END) : ScriptObject(name, PLAYERHOOK_END)
{ {
@@ -204,6 +204,7 @@ enum PlayerHook
PLAYERHOOK_CAN_SEND_ERROR_ALREADY_LOOTED, PLAYERHOOK_CAN_SEND_ERROR_ALREADY_LOOTED,
PLAYERHOOK_ON_AFTER_CREATURE_LOOT, PLAYERHOOK_ON_AFTER_CREATURE_LOOT,
PLAYERHOOK_ON_AFTER_CREATURE_LOOT_MONEY, PLAYERHOOK_ON_AFTER_CREATURE_LOOT_MONEY,
PLAYERHOOK_CAN_RESURRECT,
PLAYERHOOK_END PLAYERHOOK_END
}; };
@@ -766,6 +767,15 @@ public:
* @param player Contains information about the Player * @param player Contains information about the Player
*/ */
virtual void OnAfterCreatureLootMoney(Player* /*player*/) { } virtual void OnAfterCreatureLootMoney(Player* /*player*/) { }
/**
* @brief This hook is called, to avoid player resurrect
*
* @param player Contains information about the Player
*
* @return true if player is authorized to resurect
*/
virtual bool CanPlayerResurrect(Player* /*player*/) { return true; }
}; };
#endif #endif
@@ -148,6 +148,11 @@ void ScriptMgr::OnUnitDeath(Unit* unit, Unit* killer)
CALL_ENABLED_HOOKS(UnitScript, UNITHOOK_ON_UNIT_DEATH, script->OnUnitDeath(unit, killer)); CALL_ENABLED_HOOKS(UnitScript, UNITHOOK_ON_UNIT_DEATH, script->OnUnitDeath(unit, killer));
} }
void ScriptMgr::OnUnitSetShapeshiftForm(Unit* unit, uint8 form)
{
CALL_ENABLED_HOOKS(UnitScript, UNITHOOK_ON_UNIT_SET_SHAPESHIFT_FORM, script->OnUnitSetShapeshiftForm(unit, form));
}
UnitScript::UnitScript(const char* name, bool addToScripts, std::vector<uint16> enabledHooks) UnitScript::UnitScript(const char* name, bool addToScripts, std::vector<uint16> enabledHooks)
: ScriptObject(name, UNITHOOK_END) : ScriptObject(name, UNITHOOK_END)
{ {
@@ -45,6 +45,7 @@ enum UnitHook
UNITHOOK_ON_UNIT_ENTER_EVADE_MODE, UNITHOOK_ON_UNIT_ENTER_EVADE_MODE,
UNITHOOK_ON_UNIT_ENTER_COMBAT, UNITHOOK_ON_UNIT_ENTER_COMBAT,
UNITHOOK_ON_UNIT_DEATH, UNITHOOK_ON_UNIT_DEATH,
UNITHOOK_ON_UNIT_SET_SHAPESHIFT_FORM,
UNITHOOK_END UNITHOOK_END
}; };
@@ -115,6 +116,7 @@ public:
virtual void OnUnitEnterEvadeMode(Unit* /*unit*/, uint8 /*evadeReason*/) { } virtual void OnUnitEnterEvadeMode(Unit* /*unit*/, uint8 /*evadeReason*/) { }
virtual void OnUnitEnterCombat(Unit* /*unit*/, Unit* /*victim*/) { } virtual void OnUnitEnterCombat(Unit* /*unit*/, Unit* /*victim*/) { }
virtual void OnUnitDeath(Unit* /*unit*/, Unit* /*killer*/) { } virtual void OnUnitDeath(Unit* /*unit*/, Unit* /*killer*/) { }
virtual void OnUnitSetShapeshiftForm(Unit* /*unit*/, uint8 /*form*/) { }
}; };
#endif #endif
+2
View File
@@ -492,6 +492,7 @@ public: /* PlayerScript */
void OnAfterCreatureLoot(Player* player); void OnAfterCreatureLoot(Player* player);
void OnAfterCreatureLootMoney(Player* player); void OnAfterCreatureLootMoney(Player* player);
bool OnCanPlayerFlyInZone(Player* player, uint32 mapId, uint32 zoneId, SpellInfo const* bySpell); bool OnCanPlayerFlyInZone(Player* player, uint32 mapId, uint32 zoneId, SpellInfo const* bySpell);
bool CanPlayerResurrect(Player* player);
// Anti cheat // Anti cheat
void AnticheatSetCanFlybyServer(Player* player, bool apply); void AnticheatSetCanFlybyServer(Player* player, bool apply);
@@ -589,6 +590,7 @@ public: /* UnitScript */
void OnUnitEnterEvadeMode(Unit* unit, uint8 why); void OnUnitEnterEvadeMode(Unit* unit, uint8 why);
void OnUnitEnterCombat(Unit* unit, Unit* victim); void OnUnitEnterCombat(Unit* unit, Unit* victim);
void OnUnitDeath(Unit* unit, Unit* killer); void OnUnitDeath(Unit* unit, Unit* killer);
void OnUnitSetShapeshiftForm(Unit* unit, uint8 form);
public: /* MovementHandlerScript */ public: /* MovementHandlerScript */
void OnPlayerMove(Player* player, MovementInfo movementInfo, uint32 opcode); void OnPlayerMove(Player* player, MovementInfo movementInfo, uint32 opcode);
+1 -1
View File
@@ -830,7 +830,7 @@ bool WorldSession::DisallowHyperlinksAndMaybeKick(std::string_view str)
return false; return false;
} }
char const* WorldSession::GetAcoreString(uint32 entry) const std::string WorldSession::GetAcoreString(uint32 entry) const
{ {
return sObjectMgr->GetAcoreString(entry, GetSessionDbLocaleIndex()); return sObjectMgr->GetAcoreString(entry, GetSessionDbLocaleIndex());
} }
+4 -4
View File
@@ -372,7 +372,7 @@ public:
void SendAreaTriggerMessage(std::string_view str); void SendAreaTriggerMessage(std::string_view str);
template<typename... Args> template<typename... Args>
void SendAreaTriggerMessage(char const* fmt, Args&&... args) void SendAreaTriggerMessage(std::string fmt, Args&&... args)
{ {
if (!m_playerLoading) if (!m_playerLoading)
SendAreaTriggerMessage(Acore::StringFormat(fmt, std::forward<Args>(args)...)); SendAreaTriggerMessage(Acore::StringFormat(fmt, std::forward<Args>(args)...));
@@ -528,9 +528,9 @@ public:
time_t m_muteTime; time_t m_muteTime;
// Locales // Locales
LocaleConstant GetSessionDbcLocale() const { return /*_isBot? LOCALE_enUS : */m_sessionDbcLocale; } LocaleConstant GetSessionDbcLocale() const { return m_sessionDbcLocale; }
LocaleConstant GetSessionDbLocaleIndex() const { return /*_isBot? LOCALE_enUS : */m_sessionDbLocaleIndex; } LocaleConstant GetSessionDbLocaleIndex() const { return m_sessionDbLocaleIndex; }
char const* GetAcoreString(uint32 entry) const; std::string GetAcoreString(uint32 entry) const;
std::string const* GetModuleString(std::string module, uint32 id) const; std::string const* GetModuleString(std::string module, uint32 id) const;
uint32 GetLatency() const { return m_latency; } uint32 GetLatency() const { return m_latency; }
+3 -3
View File
@@ -3530,7 +3530,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const
_spellEvent = new SpellEvent(this); _spellEvent = new SpellEvent(this);
m_caster->m_Events.AddEvent(_spellEvent, m_caster->m_Events.CalculateTime(1)); m_caster->m_Events.AddEvent(_spellEvent, m_caster->m_Events.CalculateTime(1));
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, m_caster)) if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, m_caster))
{ {
SendCastResult(SPELL_FAILED_SPELL_UNAVAILABLE); SendCastResult(SPELL_FAILED_SPELL_UNAVAILABLE);
finish(false); finish(false);
@@ -6247,7 +6247,7 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_BAD_TARGETS; return SPELL_FAILED_BAD_TARGETS;
// Xinef: Pass only explicit unit target spells // Xinef: Pass only explicit unit target spells
// pussywizard: // pussywizard:
if (DisableMgr::IsPathfindingEnabled(m_caster->FindMap()) && m_spellInfo->NeedsExplicitUnitTarget()) if (sDisableMgr->IsPathfindingEnabled(m_caster->FindMap()) && m_spellInfo->NeedsExplicitUnitTarget())
{ {
Unit* target = m_targets.GetUnitTarget(); Unit* target = m_targets.GetUnitTarget();
if (!target) if (!target)
@@ -7960,7 +7960,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
// if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell.spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) || if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell.spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) ||
DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell.spellInfo->Id, nullptr, SPELL_DISABLE_LOS))) sDisableMgr->IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell.spellInfo->Id, nullptr, SPELL_DISABLE_LOS)))
{ {
return true; return true;
} }
@@ -1602,6 +1602,7 @@ void SpellMgr::LoadSpellInfoCorrections()
ApplySpellFix({ 44335 }, [](SpellInfo* spellInfo) ApplySpellFix({ 44335 }, [](SpellInfo* spellInfo)
{ {
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP;
spellInfo->AttributesCu |= SPELL_ATTR0_CU_SINGLE_AURA_STACK;
}); });
ApplySpellFix({ ApplySpellFix({
+2 -1
View File
@@ -39,7 +39,8 @@ void Acore::CustomChatTextBuilder::operator()(WorldPacket& data, LocaleConstant
void Acore::AcoreStringChatBuilder::operator()(WorldPacket& data, LocaleConstant locale) const void Acore::AcoreStringChatBuilder::operator()(WorldPacket& data, LocaleConstant locale) const
{ {
char const* text = sObjectMgr->GetAcoreString(_textId, locale); std::string strtext = sObjectMgr->GetAcoreString(_textId, locale);
char const* text = strtext.c_str();
if (_args) if (_args)
{ {
+2 -1
View File
@@ -422,6 +422,7 @@ enum WorldIntConfigs
CONFIG_DAILY_RBG_MIN_LEVEL_AP_REWARD, CONFIG_DAILY_RBG_MIN_LEVEL_AP_REWARD,
CONFIG_AUCTIONHOUSE_WORKERTHREADS, CONFIG_AUCTIONHOUSE_WORKERTHREADS,
CONFIG_SPELL_QUEUE_WINDOW, CONFIG_SPELL_QUEUE_WINDOW,
CONFIG_SUNSREACH_COUNTER_MAX,
INT_CONFIG_VALUE_COUNT INT_CONFIG_VALUE_COUNT
}; };
@@ -572,7 +573,7 @@ public:
virtual void SendGlobalMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0; virtual void SendGlobalMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0;
virtual void SendGlobalGMMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0; virtual void SendGlobalGMMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0;
virtual bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0; virtual bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0;
virtual void SendZoneText(uint32 zone, const char* text, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0; virtual void SendZoneText(uint32 zone, std::string text, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0;
virtual void SendServerMessage(ServerMessageType messageID, std::string stringParam = "", Player* player = nullptr) = 0; virtual void SendServerMessage(ServerMessageType messageID, std::string stringParam = "", Player* player = nullptr) = 0;
[[nodiscard]] virtual bool IsShuttingDown() const = 0; [[nodiscard]] virtual bool IsShuttingDown() const = 0;
[[nodiscard]] virtual uint32 GetShutDownTimeLeft() const = 0; [[nodiscard]] virtual uint32 GetShutDownTimeLeft() const = 0;
+11 -5
View File
@@ -1499,6 +1499,8 @@ void World::LoadConfigSettings(bool reload)
_bool_configs[CONFIG_SPELL_QUEUE_ENABLED] = sConfigMgr->GetOption<bool>("SpellQueue.Enabled", true); _bool_configs[CONFIG_SPELL_QUEUE_ENABLED] = sConfigMgr->GetOption<bool>("SpellQueue.Enabled", true);
_int_configs[CONFIG_SPELL_QUEUE_WINDOW] = sConfigMgr->GetOption<uint32>("SpellQueue.Window", 400); _int_configs[CONFIG_SPELL_QUEUE_WINDOW] = sConfigMgr->GetOption<uint32>("SpellQueue.Window", 400);
_int_configs[CONFIG_SUNSREACH_COUNTER_MAX] = sConfigMgr->GetOption<uint32>("Sunsreach.CounterMax", 10000);
// call ScriptMgr if we're reloading the configuration // call ScriptMgr if we're reloading the configuration
sScriptMgr->OnAfterConfigLoad(reload); sScriptMgr->OnAfterConfigLoad(reload);
} }
@@ -1720,7 +1722,7 @@ void World::SetInitialWorldSettings()
LoadRandomEnchantmentsTable(); LoadRandomEnchantmentsTable();
LOG_INFO("server.loading", "Loading Disables"); LOG_INFO("server.loading", "Loading Disables");
DisableMgr::LoadDisables(); // must be before loading quests and items sDisableMgr->LoadDisables(); // must be before loading quests and items
LOG_INFO("server.loading", "Loading Items..."); // must be after LoadRandomEnchantmentsTable and LoadPageTexts LOG_INFO("server.loading", "Loading Items..."); // must be after LoadRandomEnchantmentsTable and LoadPageTexts
sObjectMgr->LoadItemTemplates(); sObjectMgr->LoadItemTemplates();
@@ -1801,7 +1803,7 @@ void World::SetInitialWorldSettings()
sObjectMgr->LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables sObjectMgr->LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables
LOG_INFO("server.loading", "Checking Quest Disables"); LOG_INFO("server.loading", "Checking Quest Disables");
DisableMgr::CheckQuestDisables(); // must be after loading quests sDisableMgr->CheckQuestDisables(); // must be after loading quests
LOG_INFO("server.loading", "Loading Quest POI"); LOG_INFO("server.loading", "Loading Quest POI");
sObjectMgr->LoadQuestPOI(); sObjectMgr->LoadQuestPOI();
@@ -2126,6 +2128,9 @@ void World::SetInitialWorldSettings()
LOG_INFO("server.loading", " "); LOG_INFO("server.loading", " ");
sGameEventMgr->StartArenaSeason(); sGameEventMgr->StartArenaSeason();
LOG_INFO("server.loading", "Loading WorldState...");
sWorldState->Load();
sTicketMgr->Initialize(); sTicketMgr->Initialize();
///- Initialize Battlegrounds ///- Initialize Battlegrounds
@@ -2571,7 +2576,8 @@ namespace Acore
explicit WorldWorldTextBuilder(uint32 textId, va_list* args = nullptr) : i_textId(textId), i_args(args) {} explicit WorldWorldTextBuilder(uint32 textId, va_list* args = nullptr) : i_textId(textId), i_args(args) {}
void operator()(WorldPacketList& data_list, LocaleConstant loc_idx) void operator()(WorldPacketList& data_list, LocaleConstant loc_idx)
{ {
char const* text = sObjectMgr->GetAcoreString(i_textId, loc_idx); std::string strtext = sObjectMgr->GetAcoreString(i_textId, loc_idx);
char const* text = strtext.c_str();
if (i_args) if (i_args)
{ {
@@ -2630,10 +2636,10 @@ bool World::SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession
} }
/// Send a System Message to all players in the zone (except self if mentioned) /// Send a System Message to all players in the zone (except self if mentioned)
void World::SendZoneText(uint32 zone, const char* text, WorldSession* self, TeamId teamId) void World::SendZoneText(uint32 zone, std::string text, WorldSession* self, TeamId teamId)
{ {
WorldPacket data; WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text); ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text.c_str());
SendZoneMessage(zone, &data, self, teamId); SendZoneMessage(zone, &data, self, teamId);
} }
+1 -1
View File
@@ -239,7 +239,7 @@ public:
void SendGlobalMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) override; void SendGlobalMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) override;
void SendGlobalGMMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) override; void SendGlobalGMMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) override;
bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) override; bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) override;
void SendZoneText(uint32 zone, const char* text, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) override; void SendZoneText(uint32 zone, std::string text, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) override;
void SendServerMessage(ServerMessageType messageID, std::string stringParam = "", Player* player = nullptr) override; void SendServerMessage(ServerMessageType messageID, std::string stringParam = "", Player* player = nullptr) override;
/// Are we in the middle of a shutdown? /// Are we in the middle of a shutdown?
+795
View File
@@ -15,9 +15,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "GameEventMgr.h"
#include "MapMgr.h" #include "MapMgr.h"
#include "Player.h" #include "Player.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "Weather.h"
#include "WorldState.h" #include "WorldState.h"
WorldState* WorldState::instance() WorldState* WorldState::instance()
@@ -37,6 +39,82 @@ WorldState::~WorldState()
{ {
} }
void WorldState::Load()
{
QueryResult result = CharacterDatabase.Query("SELECT Id, Data FROM world_state");
if (result)
{
do
{
Field* fields = result->Fetch();
uint32 id = fields[0].Get<uint32>();
std::string data = fields[1].Get<std::string>();
std::istringstream loadStream(data);
switch (id)
{
case SAVE_ID_QUEL_DANAS:
{
if (data.size())
{
try
{
loadStream >> m_sunsReachData.m_phase >> m_sunsReachData.m_subphaseMask;
for (uint32 i = 0; i < COUNTERS_MAX; ++i)
loadStream >> m_sunsReachData.m_sunsReachReclamationCounters[i];
loadStream >> m_sunsReachData.m_gate;
for (uint32 i = 0; i < COUNTERS_MAX_GATES; ++i)
loadStream >> m_sunsReachData.m_gateCounters[i];
}
catch (std::exception& e)
{
LOG_ERROR("scripts", "WorldState::Load: Exception reading SunsReach data {}", e.what());
m_sunsReachData.m_phase = 0;
m_sunsReachData.m_subphaseMask = 0;
memset(m_sunsReachData.m_sunsReachReclamationCounters, 0, sizeof(m_sunsReachData.m_sunsReachReclamationCounters));
m_sunsReachData.m_gate = SUNWELL_ALL_GATES_CLOSED;
memset(m_sunsReachData.m_gateCounters, 0, sizeof(m_sunsReachData.m_gateCounters));
}
}
else
{
m_sunsReachData.m_phase = 0;
m_sunsReachData.m_subphaseMask = 0;
memset(m_sunsReachData.m_sunsReachReclamationCounters, 0, sizeof(m_sunsReachData.m_sunsReachReclamationCounters));
m_sunsReachData.m_gate = SUNWELL_ALL_GATES_CLOSED;
memset(m_sunsReachData.m_gateCounters, 0, sizeof(m_sunsReachData.m_gateCounters));
}
break;
}
}
} while (result->NextRow());
}
StartSunsReachPhase(true);
StartSunwellGatePhase();
HandleSunsReachSubPhaseTransition(m_sunsReachData.m_subphaseMask, true);
}
void WorldState::Save(WorldStateSaveIds saveId)
{
switch (saveId)
{
case SAVE_ID_QUEL_DANAS:
{
std::string expansionData = m_sunsReachData.GetData();
SaveHelper(expansionData, SAVE_ID_QUEL_DANAS);
break;
}
default:
break;
}
}
void WorldState::SaveHelper(std::string& stringToSave, WorldStateSaveIds saveId)
{
CharacterDatabase.Execute("DELETE FROM world_state WHERE Id='{}'", saveId);
CharacterDatabase.Execute("INSERT INTO world_state(Id,Data) VALUES('{}','{}')", saveId, stringToSave.data());
}
bool WorldState::IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state) const bool WorldState::IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state) const
{ {
switch (conditionId) switch (conditionId)
@@ -140,6 +218,16 @@ void WorldState::HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId)
else if (_isMagtheridonHeadSpawnedHorde && player->GetTeamId() == TEAM_HORDE) else if (_isMagtheridonHeadSpawnedHorde && player->GetTeamId() == TEAM_HORDE)
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true); player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
break; break;
case ZONEID_ISLE_OF_QUEL_DANAS:
case ZONEID_MAGISTERS_TERRACE:
case ZONEID_SUNWELL_PLATEAU:
{
std::lock_guard<std::mutex> guard(m_sunsReachData.m_sunsReachReclamationMutex);
m_sunsReachData.m_sunsReachReclamationPlayers.push_back(player->GetGUID());
if (m_sunsReachData.m_subphaseMask == SUBPHASE_ALL)
player->CastSpell(player, SPELL_KIRU_SONG_OF_VICTORY, true);
break;
}
default: default:
break; break;
} }
@@ -167,6 +255,17 @@ void WorldState::HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId)
else if (player->GetTeamId() == TEAM_HORDE) else if (player->GetTeamId() == TEAM_HORDE)
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR); player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
break; break;
case ZONEID_ISLE_OF_QUEL_DANAS:
case ZONEID_MAGISTERS_TERRACE:
case ZONEID_SUNWELL_PLATEAU:
{
std::lock_guard<std::mutex> guard(m_sunsReachData.m_sunsReachReclamationMutex);
player->RemoveAurasDueToSpell(SPELL_KIRU_SONG_OF_VICTORY);
auto position = std::find(m_sunsReachData.m_sunsReachReclamationPlayers.begin(), m_sunsReachData.m_sunsReachReclamationPlayers.end(), player->GetGUID());
if (position != m_sunsReachData.m_sunsReachReclamationPlayers.end())
m_sunsReachData.m_sunsReachReclamationPlayers.erase(position);
break;
}
default: default:
break; break;
} }
@@ -291,3 +390,699 @@ void WorldState::DispelAdalsSongOfBattle()
} }
}); });
} }
void WorldState::SendWorldstateUpdate(std::mutex& mutex, GuidVector const& guids, uint32 value, uint32 worldStateId)
{
std::lock_guard<std::mutex> guard(mutex);
for (ObjectGuid const& guid : guids)
if (Player* player = ObjectAccessor::FindPlayer(guid))
player->SendUpdateWorldState(worldStateId, value);
}
enum WorldStateSunsReachQuests
{
QUEST_ERRATIC_BEHAVIOR = 11524,
QUEST_SANCTUM_WARDS = 11496,
QUEST_BATTLE_FOR_THE_SUNS_REACH_ARMORY = 11538,
QUEST_DISTRACTION_AT_THE_DEAD_SCAR = 11532,
QUEST_INTERCEPTING_THE_MANA_CELLS = 11513,
QUEST_INTERCEPT_THE_REINFORCEMENTS = 11542,
QUEST_TAKING_THE_HARBOR = 11539,
QUEST_MAKING_READY = 11535,
QUEST_DISCOVERING_YOUR_ROOTS = 11520,
QUEST_A_CHARITABLE_DONATION = 11545,
QUEST_A_MAGNANIMOUS_BENEFACTOR = 11549,
COUNTER_MAX_VAL_REQ = 10000,
};
void WorldState::AddSunsReachProgress(uint32 questId)
{
uint32 counter = 0;
int32 otherCounter = -1;
int32 worldState = 0;
uint32 subPhaseMask = 0;
uint32 addedValue = 1;
switch (questId)
{
case QUEST_ERRATIC_BEHAVIOR:
counter = COUNTER_ERRATIC_BEHAVIOR;
otherCounter = COUNTER_SANCTUM_WARDS;
worldState = WORLD_STATE_QUEL_DANAS_SANCTUM;
break;
case QUEST_SANCTUM_WARDS:
counter = COUNTER_SANCTUM_WARDS;
otherCounter = COUNTER_SANCTUM_WARDS;
worldState = WORLD_STATE_QUEL_DANAS_SANCTUM;
break;
case QUEST_BATTLE_FOR_THE_SUNS_REACH_ARMORY:
counter = COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY;
otherCounter = COUNTER_DISTRACTION_AT_THE_DEAD_SCAR;
worldState = WORLD_STATE_QUEL_DANAS_ARMORY;
break;
case QUEST_DISTRACTION_AT_THE_DEAD_SCAR:
counter = COUNTER_DISTRACTION_AT_THE_DEAD_SCAR;
otherCounter = COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY;
worldState = WORLD_STATE_QUEL_DANAS_ARMORY;
break;
case QUEST_INTERCEPTING_THE_MANA_CELLS:
counter = COUNTER_INTERCEPTING_THE_MANA_CELLS;
subPhaseMask = SUBPHASE_PORTAL;
worldState = WORLD_STATE_QUEL_DANAS_PORTAL;
break;
case QUEST_INTERCEPT_THE_REINFORCEMENTS:
counter = COUNTER_INTERCEPT_THE_REINFORCEMENTS;
otherCounter = COUNTER_TAKING_THE_HARBOR;
worldState = WORLD_STATE_QUEL_DANAS_HARBOR;
break;
case QUEST_TAKING_THE_HARBOR:
counter = COUNTER_TAKING_THE_HARBOR;
otherCounter = COUNTER_INTERCEPT_THE_REINFORCEMENTS;
worldState = WORLD_STATE_QUEL_DANAS_HARBOR;
break;
case QUEST_MAKING_READY:
counter = COUNTER_MAKING_READY;
subPhaseMask = SUBPHASE_ANVIL;
worldState = WORLD_STATE_QUEL_DANAS_ANVIL;
break;
case QUEST_DISCOVERING_YOUR_ROOTS:
counter = COUNTER_DISCOVERING_YOUR_ROOTS;
subPhaseMask = SUBPHASE_ALCHEMY_LAB;
worldState = WORLD_STATE_QUEL_DANAS_ALCHEMY_LAB;
break;
case QUEST_A_CHARITABLE_DONATION:
counter = COUNTER_A_CHARITABLE_DONATION;
subPhaseMask = SUBPHASE_MONUMENT;
worldState = WORLD_STATE_QUEL_DANAS_MONUMENT;
break;
case QUEST_A_MAGNANIMOUS_BENEFACTOR:
counter = COUNTER_A_CHARITABLE_DONATION;
subPhaseMask = SUBPHASE_MONUMENT;
worldState = WORLD_STATE_QUEL_DANAS_MONUMENT;
addedValue = 150;
break;
default:
return;
}
uint32 previousValue = 0;
uint32 newValue = 0;
if (!subPhaseMask)
previousValue = m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase);
else
previousValue = m_sunsReachData.GetSubPhasePercentage(subPhaseMask);
m_sunsReachData.m_sunsReachReclamationCounters[counter] += addedValue;
if (!subPhaseMask)
newValue = m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase);
else
newValue = m_sunsReachData.GetSubPhasePercentage(subPhaseMask);
if (previousValue != newValue)
SendWorldstateUpdate(m_sunsReachData.m_sunsReachReclamationMutex, m_sunsReachData.m_sunsReachReclamationPlayers, newValue, worldState);
bool save = true;
uint32 counterValue = m_sunsReachData.m_sunsReachReclamationCounters[counter];
uint32 modifier = 1;
if (otherCounter != -1)
{
modifier = 2;
counterValue += m_sunsReachData.m_sunsReachReclamationCounters[otherCounter];
}
if (counterValue >= sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX) * modifier)
{
save = false;
switch (questId)
{
case QUEST_ERRATIC_BEHAVIOR:
case QUEST_SANCTUM_WARDS:
{
if (m_sunsReachData.m_phase == SUNS_REACH_PHASE_1_STAGING_AREA)
HandleSunsReachPhaseTransition(SUNS_REACH_PHASE_2_SANCTUM);
break;
}
case QUEST_BATTLE_FOR_THE_SUNS_REACH_ARMORY:
case QUEST_DISTRACTION_AT_THE_DEAD_SCAR:
{
if (m_sunsReachData.m_phase == SUNS_REACH_PHASE_2_SANCTUM)
HandleSunsReachPhaseTransition(SUNS_REACH_PHASE_3_ARMORY);
break;
}
case QUEST_INTERCEPTING_THE_MANA_CELLS:
{
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_PORTAL) == 0)
HandleSunsReachSubPhaseTransition(SUBPHASE_PORTAL);
break;
}
case QUEST_INTERCEPT_THE_REINFORCEMENTS:
case QUEST_TAKING_THE_HARBOR:
{
if (m_sunsReachData.m_phase == SUNS_REACH_PHASE_3_ARMORY)
HandleSunsReachPhaseTransition(SUNS_REACH_PHASE_4_HARBOR);
break;
}
case QUEST_MAKING_READY:
{
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ANVIL) == 0)
HandleSunsReachSubPhaseTransition(SUBPHASE_ANVIL);
break;
}
case QUEST_DISCOVERING_YOUR_ROOTS:
{
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALCHEMY_LAB) == 0)
HandleSunsReachSubPhaseTransition(SUBPHASE_ALCHEMY_LAB);
break;
}
case QUEST_A_CHARITABLE_DONATION:
case QUEST_A_MAGNANIMOUS_BENEFACTOR:
{
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_MONUMENT) == 0)
HandleSunsReachSubPhaseTransition(SUBPHASE_MONUMENT);
break;
}
}
}
if (save)
Save(SAVE_ID_QUEL_DANAS);
}
void WorldState::HandleSunsReachPhaseTransition(uint32 newPhase)
{
if (newPhase < m_sunsReachData.m_phase)
{
while (newPhase != m_sunsReachData.m_phase)
{
StopSunsReachPhase(newPhase > m_sunsReachData.m_phase);
--m_sunsReachData.m_phase;
}
StartSunsReachPhase();
}
else
{
StopSunsReachPhase(newPhase > m_sunsReachData.m_phase);
bool moreThanOne = newPhase > m_sunsReachData.m_phase + 1; // custom command case
m_sunsReachData.m_phase = newPhase;
StartSunsReachPhase(moreThanOne);
}
switch (m_sunsReachData.m_phase)
{
case SUNS_REACH_PHASE_2_SANCTUM: if ((m_sunsReachData.m_subphaseMask & SUBPHASE_PORTAL) == 0) sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_NO_PORTAL); break;
case SUNS_REACH_PHASE_3_ARMORY: if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ANVIL) == 0) sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_NO_ANVIL); break;
case SUNS_REACH_PHASE_4_HARBOR:
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALCHEMY_LAB) == 0) sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_NO_MONUMENT);
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_MONUMENT) == 0) sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_NO_ALCHEMY_LAB);
break;
default: break;
}
SendWorldstateUpdate(m_sunsReachData.m_sunsReachReclamationMutex, m_sunsReachData.m_sunsReachReclamationPlayers, m_sunsReachData.m_phase, WORLD_STATE_QUEL_DANAS_MUSIC);
Save(SAVE_ID_QUEL_DANAS);
}
void WorldState::HandleSunsReachSubPhaseTransition(int32 subPhaseMask, bool initial)
{
bool start = true;
if (subPhaseMask < 0)
{
start = false;
subPhaseMask = -subPhaseMask;
}
bool all = false;
if (start)
{
m_sunsReachData.m_subphaseMask |= subPhaseMask;
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALL) == SUBPHASE_ALL)
all = true;
}
else
{
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALL) == SUBPHASE_ALL)
all = true;
m_sunsReachData.m_subphaseMask &= ~subPhaseMask;
}
if (initial)
{
if (m_sunsReachData.m_phase >= SUNS_REACH_PHASE_2_SANCTUM)
if ((subPhaseMask & SUBPHASE_PORTAL) == 0)
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_NO_PORTAL);
if (m_sunsReachData.m_phase >= SUNS_REACH_PHASE_3_ARMORY)
if ((subPhaseMask & SUBPHASE_ANVIL) == 0)
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_NO_ANVIL);
if (m_sunsReachData.m_phase >= SUNS_REACH_PHASE_4_HARBOR)
{
if ((subPhaseMask & SUBPHASE_ALCHEMY_LAB) == 0)
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_NO_ALCHEMY_LAB);
if ((subPhaseMask & SUBPHASE_MONUMENT) == 0)
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_NO_MONUMENT);
}
}
if ((subPhaseMask & SUBPHASE_PORTAL))
{
uint32 first = GAME_EVENT_QUEL_DANAS_PHASE_2_NO_PORTAL;
uint32 second = GAME_EVENT_QUEL_DANAS_PHASE_2_PORTAL;
if (start)
{
sGameEventMgr->StopEvent(first);
sGameEventMgr->StartEvent(second);
}
else
{
sGameEventMgr->StopEvent(second);
sGameEventMgr->StartEvent(first);
}
}
if ((subPhaseMask & SUBPHASE_ANVIL))
{
uint32 first = GAME_EVENT_QUEL_DANAS_PHASE_3_NO_ANVIL;
uint32 second = GAME_EVENT_QUEL_DANAS_PHASE_3_ANVIL;
if (start)
{
sGameEventMgr->StopEvent(first);
sGameEventMgr->StartEvent(second);
}
else
{
sGameEventMgr->StopEvent(second);
sGameEventMgr->StartEvent(first);
}
}
if ((subPhaseMask & SUBPHASE_ALCHEMY_LAB))
{
uint32 first = GAME_EVENT_QUEL_DANAS_PHASE_4_NO_ALCHEMY_LAB;
uint32 second = GAME_EVENT_QUEL_DANAS_PHASE_4_ALCHEMY_LAB;
if (start)
{
sGameEventMgr->StopEvent(first);
sGameEventMgr->StartEvent(second);
}
else
{
sGameEventMgr->StopEvent(second);
sGameEventMgr->StartEvent(first);
}
}
if ((subPhaseMask & SUBPHASE_MONUMENT))
{
uint32 first = GAME_EVENT_QUEL_DANAS_PHASE_4_NO_MONUMENT;
uint32 second = GAME_EVENT_QUEL_DANAS_PHASE_4_MONUMENT;
if (start)
{
sGameEventMgr->StopEvent(first);
sGameEventMgr->StartEvent(second);
}
else
{
sGameEventMgr->StopEvent(second);
sGameEventMgr->StartEvent(first);
}
}
if (all)
{
if (start)
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_KIRU);
else
sGameEventMgr->StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_4_KIRU);
if (!initial)
{
std::lock_guard<std::mutex> guard(m_sunsReachData.m_sunsReachReclamationMutex);
for (ObjectGuid& guid : m_sunsReachData.m_sunsReachReclamationPlayers)
if (Player* player = ObjectAccessor::FindPlayer(guid))
{
if (start)
player->CastSpell(player, SPELL_KIRU_SONG_OF_VICTORY, true);
else
player->RemoveAurasDueToSpell(SPELL_KIRU_SONG_OF_VICTORY);
}
}
}
if (!initial)
Save(SAVE_ID_QUEL_DANAS);
}
void WorldState::HandleSunwellGateTransition(uint32 newGate)
{
if (newGate < m_sunsReachData.m_gate)
{
while (newGate != m_sunsReachData.m_gate)
{
StopSunwellGatePhase();
--m_sunsReachData.m_gate;
}
StartSunwellGatePhase();
}
else
{
StopSunwellGatePhase();
m_sunsReachData.m_gate = newGate;
StartSunwellGatePhase();
}
int32 worldState = 0;
switch (newGate)
{
case SUNWELL_AGAMATH_GATE1_OPEN: worldState = WORLD_STATE_AGAMATH_THE_FIRST_GATE_HEALTH; break;
case SUNWELL_ROHENDOR_GATE2_OPEN: worldState = WORLD_STATE_ROHENDOR_THE_SECOND_GATE_HEALTH; break;
case SUNWELL_ARCHONISUS_GATE3_OPEN: worldState = WORLD_STATE_ARCHONISUS_THE_FINAL_GATE_HEALTH; break;
}
if (worldState)
SendWorldstateUpdate(m_sunsReachData.m_sunsReachReclamationMutex, m_sunsReachData.m_sunsReachReclamationPlayers, m_sunsReachData.m_gate, worldState);
Save(SAVE_ID_QUEL_DANAS);
}
void WorldState::SetSunsReachCounter(SunsReachCounters index, uint32 value)
{
m_sunsReachData.m_sunsReachReclamationCounters[index] = value;
}
void WorldState::StopSunsReachPhase(bool forward)
{
switch (m_sunsReachData.m_phase)
{
case SUNS_REACH_PHASE_1_STAGING_AREA: sGameEventMgr->StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_1); break;
case SUNS_REACH_PHASE_2_SANCTUM: sGameEventMgr->StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_ONLY); if (!forward) sGameEventMgr->StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT); break;
case SUNS_REACH_PHASE_3_ARMORY: sGameEventMgr->StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_ONLY); if (!forward) sGameEventMgr->StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_PERMANENT); break;
case SUNS_REACH_PHASE_4_HARBOR: sGameEventMgr->StopEvent(GAME_EVENT_QUEL_DANAS_PHASE_4); break;
default: break;
}
}
void WorldState::StartSunsReachPhase(bool initial)
{
switch (m_sunsReachData.m_phase)
{
case SUNS_REACH_PHASE_1_STAGING_AREA:
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_1);
if (Map* map = sMapMgr->FindBaseNonInstanceMap(530))
map->SetZoneWeather(ZONEID_ISLE_OF_QUEL_DANAS, WEATHER_STATE_MEDIUM_RAIN, 0.75f);
break;
case SUNS_REACH_PHASE_2_SANCTUM:
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_ONLY);
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT);
if (Map* map = sMapMgr->FindBaseNonInstanceMap(530))
map->SetZoneWeather(ZONEID_ISLE_OF_QUEL_DANAS, WEATHER_STATE_LIGHT_RAIN, 0.5f);
break;
case SUNS_REACH_PHASE_3_ARMORY:
if (initial)
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT);
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_ONLY); sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_PERMANENT);
// TODO: Should be id 2 0.25f?
if (Map* map = sMapMgr->FindBaseNonInstanceMap(530))
map->SetZoneWeather(ZONEID_ISLE_OF_QUEL_DANAS, WEATHER_STATE_LIGHT_RAIN, 0.25f);
break;
case SUNS_REACH_PHASE_4_HARBOR:
if (initial)
{
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT);
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_3_PERMANENT);
}
sGameEventMgr->StartEvent(GAME_EVENT_QUEL_DANAS_PHASE_4);
if (Map* map = sMapMgr->FindBaseNonInstanceMap(530))
map->SetZoneWeather(ZONEID_ISLE_OF_QUEL_DANAS, WEATHER_STATE_FINE, 0.0f);
break;
default: break;
}
}
std::string WorldState::GetSunsReachPrintout()
{
auto formatPhase = [this]() -> std::string {
std::string name;
switch (m_sunsReachData.m_phase)
{
case SUNS_REACH_PHASE_1_STAGING_AREA: name = "Phase 1: Staging Area"; break;
case SUNS_REACH_PHASE_2_SANCTUM: name = "Phase 2: Sanctum"; break;
case SUNS_REACH_PHASE_3_ARMORY: name = "Phase 3: Armory"; break;
case SUNS_REACH_PHASE_4_HARBOR: name = "Phase 4: Harbor"; break;
default: name = "Unknown"; break;
}
return "Phase: " + std::to_string(m_sunsReachData.m_phase) + " (" + name + ") " + std::to_string(m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase)) + "%\n";
};
auto formatSubPhase = [this](uint32 subPhase) -> std::string {
std::string name;
switch (subPhase)
{
case SUBPHASE_PORTAL: name = "Portal"; break;
case SUBPHASE_ANVIL: name = "Anvil"; break;
case SUBPHASE_ALCHEMY_LAB: name = "Alchemy Lab"; break;
case SUBPHASE_MONUMENT: name = "Monument"; break;
default: name = "Unknown"; break;
}
return name + ": " + (m_sunsReachData.m_subphaseMask & subPhase ? "100%" : std::to_string(m_sunsReachData.GetSubPhasePercentage(subPhase)) + "%");
};
auto formatCounter = [](uint32 counter, uint32 value) -> std::string {
switch (counter)
{
case COUNTER_ERRATIC_BEHAVIOR:
return "Erratic Behavior: " + std::to_string(value) + " (counts towards Phase 2: Sanctum)";
case COUNTER_SANCTUM_WARDS:
return "Sanctum Wards: " + std::to_string(value) + " (counts towards Phase 2: Sanctum)";
case COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY:
return "Battle for the Sun's Reach Armory: " + std::to_string(value) + " (counts towards Phase 3: Armory)";
case COUNTER_DISTRACTION_AT_THE_DEAD_SCAR:
return "Distraction at the Dead Scar: " + std::to_string(value) + " (counts towards Phase 3: Armory)";
case COUNTER_INTERCEPTING_THE_MANA_CELLS:
return "Intercepting the Mana Cells: " + std::to_string(value) + " (counts towards Subphase: Portal)";
case COUNTER_INTERCEPT_THE_REINFORCEMENTS:
return "Intercept the Reinforcements: " + std::to_string(value) + " (counts towards Phase 4: Harbor)";
case COUNTER_TAKING_THE_HARBOR:
return "Taking the Harbor: " + std::to_string(value) + " (counts towards Phase 4: Harbor)";
case COUNTER_MAKING_READY:
return "Making Ready: " + std::to_string(value) + " (counts towards Subphase: Anvil)";
case COUNTER_DISCOVERING_YOUR_ROOTS:
return "Discovering Your Roots: " + std::to_string(value) + " (counts towards Subphase: Alchemy Lab)";
case COUNTER_A_CHARITABLE_DONATION:
return "A Charitable Donation: " + std::to_string(value) + " (counts towards Subphase: Monument)";
default:
return "Unknown: " + std::to_string(value) + " (Unknown goal)";
}
};
std::string output = formatPhase();
output += "Subphase mask: " + std::to_string(m_sunsReachData.m_subphaseMask) + "\n";
for (uint32 i = 0; i < 4; ++i)
{
uint32 subPhaseMask = 1 << i;
output += " " + formatSubPhase(subPhaseMask) + "\n";
}
output += "Counters:\n";
output += " Sunsreach.CounterMax = " + std::to_string(sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX)) + "\n";
for (uint32 i = 0; i < COUNTERS_MAX; ++i)
output += " " + std::to_string(i) + ". " + formatCounter(i, m_sunsReachData.m_sunsReachReclamationCounters[i]) + "\n";
// Sunwell Gates
auto formatGatePhase = [](uint32 gate) -> std::string {
switch (gate)
{
case SUNWELL_ALL_GATES_CLOSED: return "All Gates Closed"; break;
case SUNWELL_AGAMATH_GATE1_OPEN: return "Gate 1 Agamath Open"; break;
case SUNWELL_ROHENDOR_GATE2_OPEN: return "Gate 2 Rohendar Open"; break;
case SUNWELL_ARCHONISUS_GATE3_OPEN: return "Gate 3 Archonisus Open"; break;
default: return "Unknown"; break;
}
};
output += "Sunwell Plateau Gate Phase " + std::to_string(m_sunsReachData.m_gate) + " (" + formatGatePhase(m_sunsReachData.m_gate) + ")" + ":\n";
output += " 0. Gate 1 (Agamath): " + std::string(m_sunsReachData.m_gate >= SUNWELL_AGAMATH_GATE1_OPEN ? "Open " : "Closed ") + std::to_string(m_sunsReachData.m_sunsReachReclamationCounters[COUNTER_AGAMATH_THE_FIRST_GATE]) + " (" + std::to_string(m_sunsReachData.GetSunwellGatePercentage(SUNWELL_ALL_GATES_CLOSED)) + "%)\n";
output += " 1. Gate 2 (Rohendor): " + std::string(m_sunsReachData.m_gate >= SUNWELL_ROHENDOR_GATE2_OPEN ? "Open " : "Closed ") + std::to_string(m_sunsReachData.m_sunsReachReclamationCounters[COUNTER_ROHENDOR_THE_SECOND_GATE]) + " (" + std::to_string(m_sunsReachData.GetSunwellGatePercentage(SUNWELL_AGAMATH_GATE1_OPEN)) + "%)\n";
output += " 2. Gate 3 (Archonisus): " + std::string(m_sunsReachData.m_gate >= SUNWELL_ARCHONISUS_GATE3_OPEN ? "Open " : "Closed ") + std::to_string(m_sunsReachData.m_sunsReachReclamationCounters[COUNTER_ARCHONISUS_THE_FINAL_GATE]) + " (" + std::to_string(m_sunsReachData.GetSunwellGatePercentage(SUNWELL_ROHENDOR_GATE2_OPEN)) + "%)\n";
return output;
}
std::string SunsReachReclamationData::GetData()
{
std::string output = std::to_string(m_phase) + " " + std::to_string(m_subphaseMask);
for (uint32 value : m_sunsReachReclamationCounters)
output += " " + std::to_string(value);
output += " " + std::to_string(m_gate);
for (uint32 value : m_gateCounters)
output += " " + std::to_string(value);
return output;
}
uint32 SunsReachReclamationData::GetPhasePercentage(uint32 phase)
{
switch (phase)
{
case SUNS_REACH_PHASE_1_STAGING_AREA: return uint32((m_sunsReachReclamationCounters[COUNTER_ERRATIC_BEHAVIOR] + m_sunsReachReclamationCounters[COUNTER_SANCTUM_WARDS]) * 100 / (2 * sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX)));
case SUNS_REACH_PHASE_2_SANCTUM: return uint32((m_sunsReachReclamationCounters[COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY] + m_sunsReachReclamationCounters[COUNTER_DISTRACTION_AT_THE_DEAD_SCAR]) * 100 / (2 * sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX)));
case SUNS_REACH_PHASE_3_ARMORY: return uint32((m_sunsReachReclamationCounters[COUNTER_INTERCEPT_THE_REINFORCEMENTS] + m_sunsReachReclamationCounters[COUNTER_TAKING_THE_HARBOR]) * 100 / (2 * sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX)));
default: return 0;
}
}
uint32 SunsReachReclamationData::GetSubPhasePercentage(uint32 subPhase)
{
switch (subPhase)
{
case SUBPHASE_PORTAL: return uint32(m_sunsReachReclamationCounters[COUNTER_INTERCEPTING_THE_MANA_CELLS] * 100 / sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX));
case SUBPHASE_ANVIL: return uint32(m_sunsReachReclamationCounters[COUNTER_MAKING_READY] * 100 / sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX));
case SUBPHASE_ALCHEMY_LAB: return uint32(m_sunsReachReclamationCounters[COUNTER_DISCOVERING_YOUR_ROOTS] * 100 / sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX));
case SUBPHASE_MONUMENT: return uint32(m_sunsReachReclamationCounters[COUNTER_A_CHARITABLE_DONATION] * 100 / sWorld->getIntConfig(CONFIG_SUNSREACH_COUNTER_MAX));
default: return 0;
}
}
enum WorldStateSunwellGateQuests
{
// Sunwell Plateau PTR progressive release gates
QUEST_AGAMATH_THE_FIRST_GATE = 11551,
QUEST_ROHENDOR_THE_SECOND_GATE = 11552,
QUEST_ARCHONISUS_THE_FINAL_GATE = 11553,
COUNTER_MAX_VAL_REQ_SWP_GATES = 80,
};
void WorldState::AddSunwellGateProgress(uint32 questId)
{
uint32 counter = 0;
int32 worldState = 0;
uint32 addedValue = 1;
switch (questId)
{
case QUEST_AGAMATH_THE_FIRST_GATE:
case QUEST_ROHENDOR_THE_SECOND_GATE:
case QUEST_ARCHONISUS_THE_FINAL_GATE:
break;
default: return;
}
switch (m_sunsReachData.m_gate)
{
case SUNWELL_ALL_GATES_CLOSED: counter = COUNTER_AGAMATH_THE_FIRST_GATE; worldState = WORLD_STATE_AGAMATH_THE_FIRST_GATE_HEALTH; break;
case SUNWELL_AGAMATH_GATE1_OPEN: counter = COUNTER_ROHENDOR_THE_SECOND_GATE; worldState = WORLD_STATE_ROHENDOR_THE_SECOND_GATE_HEALTH; break;
case SUNWELL_ROHENDOR_GATE2_OPEN: counter = COUNTER_ARCHONISUS_THE_FINAL_GATE; worldState = WORLD_STATE_ARCHONISUS_THE_FINAL_GATE_HEALTH; break;
default: return;
}
uint32 previousValue = m_sunsReachData.GetSunwellGatePercentage(m_sunsReachData.m_gate);
uint32 newValue = 0;
m_sunsReachData.m_gateCounters[counter] += addedValue;
newValue = m_sunsReachData.GetSunwellGatePercentage(m_sunsReachData.m_gate);
if (previousValue != newValue)
SendWorldstateUpdate(m_sunsReachData.m_sunsReachReclamationMutex, m_sunsReachData.m_sunsReachReclamationPlayers, newValue, worldState);
bool save = true;
if (m_sunsReachData.m_gateCounters[counter] >= COUNTER_MAX_VAL_REQ_SWP_GATES)
{
save = false;
switch (questId)
{
case QUEST_AGAMATH_THE_FIRST_GATE:
{
if (m_sunsReachData.m_gate == SUNWELL_ALL_GATES_CLOSED)
HandleSunwellGateTransition(SUNWELL_AGAMATH_GATE1_OPEN);
break;
}
case QUEST_ROHENDOR_THE_SECOND_GATE:
{
if (m_sunsReachData.m_gate == SUNWELL_AGAMATH_GATE1_OPEN)
HandleSunwellGateTransition(SUNWELL_ROHENDOR_GATE2_OPEN);
break;
}
case QUEST_ARCHONISUS_THE_FINAL_GATE:
{
if (m_sunsReachData.m_gate == SUNWELL_ROHENDOR_GATE2_OPEN)
HandleSunwellGateTransition(SUNWELL_ARCHONISUS_GATE3_OPEN);
break;
}
}
}
if (save)
Save(SAVE_ID_QUEL_DANAS);
}
void WorldState::SetSunwellGateCounter(SunwellGateCounters index, uint32 value)
{
m_sunsReachData.m_gateCounters[index] = value;
}
void WorldState::StartSunwellGatePhase()
{
switch (m_sunsReachData.m_gate)
{
case SUNWELL_ALL_GATES_CLOSED: sGameEventMgr->StartEvent(GAME_EVENT_SWP_GATES_PHASE_0); break;
case SUNWELL_AGAMATH_GATE1_OPEN: sGameEventMgr->StartEvent(GAME_EVENT_SWP_GATES_PHASE_1); break;
case SUNWELL_ROHENDOR_GATE2_OPEN: sGameEventMgr->StartEvent(GAME_EVENT_SWP_GATES_PHASE_2); break;
case SUNWELL_ARCHONISUS_GATE3_OPEN: sGameEventMgr->StartEvent(GAME_EVENT_SWP_GATES_PHASE_3); break;
default: break;
}
}
void WorldState::StopSunwellGatePhase()
{
switch (m_sunsReachData.m_gate)
{
case SUNWELL_ALL_GATES_CLOSED: sGameEventMgr->StopEvent(GAME_EVENT_SWP_GATES_PHASE_0); break;
case SUNWELL_AGAMATH_GATE1_OPEN: sGameEventMgr->StopEvent(GAME_EVENT_SWP_GATES_PHASE_1); break;
case SUNWELL_ROHENDOR_GATE2_OPEN: sGameEventMgr->StopEvent(GAME_EVENT_SWP_GATES_PHASE_2); break;
case SUNWELL_ARCHONISUS_GATE3_OPEN: sGameEventMgr->StopEvent(GAME_EVENT_SWP_GATES_PHASE_3); break;
default: break;
}
}
uint32 SunsReachReclamationData::GetSunwellGatePercentage(uint32 gate)
{
int32 percentage = 0;
switch (gate)
{
case SUNWELL_ALL_GATES_CLOSED:
percentage = 100 - int32(m_gateCounters[COUNTER_AGAMATH_THE_FIRST_GATE] * 100 / COUNTER_MAX_VAL_REQ_SWP_GATES);
break;
case SUNWELL_AGAMATH_GATE1_OPEN:
percentage = 100 - int32(m_gateCounters[COUNTER_ROHENDOR_THE_SECOND_GATE] * 100 / COUNTER_MAX_VAL_REQ_SWP_GATES);
break;
case SUNWELL_ROHENDOR_GATE2_OPEN:
percentage = 100 - int32(m_gateCounters[COUNTER_ARCHONISUS_THE_FINAL_GATE] * 100 / COUNTER_MAX_VAL_REQ_SWP_GATES);
break;
default:
return 0;
}
return percentage < 0 ? 0 : uint32(percentage);
}
void WorldState::FillInitialWorldStates(ByteBuffer& data, uint32 zoneId, uint32 /*areaId*/)
{
switch (zoneId)
{
case ZONEID_ISLE_OF_QUEL_DANAS:
case ZONEID_MAGISTERS_TERRACE:
case ZONEID_SUNWELL_PLATEAU:
case ZONEID_SHATTRATH:
{
// Sunwell Reclamation
switch (m_sunsReachData.m_phase)
{
case SUNS_REACH_PHASE_1_STAGING_AREA:
data << WORLD_STATE_QUEL_DANAS_SANCTUM << m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase);
break;
case SUNS_REACH_PHASE_2_SANCTUM:
data << WORLD_STATE_QUEL_DANAS_ARMORY << m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase);
break;
case SUNS_REACH_PHASE_3_ARMORY:
data << WORLD_STATE_QUEL_DANAS_HARBOR << m_sunsReachData.GetPhasePercentage(m_sunsReachData.m_phase);
break;
case SUNS_REACH_PHASE_4_HARBOR:
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_ALCHEMY_LAB) == 0)
data << WORLD_STATE_QUEL_DANAS_ALCHEMY_LAB << m_sunsReachData.GetSubPhasePercentage(SUBPHASE_ALCHEMY_LAB);
if ((m_sunsReachData.m_subphaseMask & SUBPHASE_MONUMENT) == 0)
data << WORLD_STATE_QUEL_DANAS_MONUMENT << m_sunsReachData.GetSubPhasePercentage(SUBPHASE_MONUMENT);
break;
}
if (m_sunsReachData.m_phase >= SUNS_REACH_PHASE_2_SANCTUM && (m_sunsReachData.m_subphaseMask & SUBPHASE_PORTAL) == 0)
data << WORLD_STATE_QUEL_DANAS_PORTAL << m_sunsReachData.GetSubPhasePercentage(SUBPHASE_PORTAL);
if (m_sunsReachData.m_phase >= SUNS_REACH_PHASE_3_ARMORY && (m_sunsReachData.m_subphaseMask & SUBPHASE_ANVIL) == 0)
data << WORLD_STATE_QUEL_DANAS_ANVIL << m_sunsReachData.GetSubPhasePercentage(SUBPHASE_ANVIL);
data << WORLD_STATE_QUEL_DANAS_MUSIC << m_sunsReachData.m_phase;
// Sunwell Gates
switch (m_sunsReachData.m_gate)
{
case SUNWELL_ALL_GATES_CLOSED:
data << WORLD_STATE_AGAMATH_THE_FIRST_GATE_HEALTH << m_sunsReachData.GetSunwellGatePercentage(m_sunsReachData.m_gate);
break;
case SUNWELL_AGAMATH_GATE1_OPEN:
data << WORLD_STATE_ROHENDOR_THE_SECOND_GATE_HEALTH << m_sunsReachData.GetSunwellGatePercentage(m_sunsReachData.m_gate);
break;
case SUNWELL_ROHENDOR_GATE2_OPEN:
data << WORLD_STATE_ARCHONISUS_THE_FINAL_GATE_HEALTH << m_sunsReachData.GetSunwellGatePercentage(m_sunsReachData.m_gate);
break;
}
break;
}
}
}
+139
View File
@@ -21,6 +21,24 @@
#include "Player.h" #include "Player.h"
#include <atomic> #include <atomic>
// TODO: Move these to WorldStateDefines.h
enum WorldStateWorldStates
{
// Sun's Reach Reclamation
WORLD_STATE_QUEL_DANAS_MUSIC = 3426,
WORLD_STATE_QUEL_DANAS_HARBOR = 3238,
WORLD_STATE_QUEL_DANAS_ALCHEMY_LAB = 3223,
WORLD_STATE_QUEL_DANAS_ARMORY = 3233,
WORLD_STATE_QUEL_DANAS_SANCTUM = 3244,
WORLD_STATE_QUEL_DANAS_PORTAL = 3269,
WORLD_STATE_QUEL_DANAS_ANVIL = 3228,
WORLD_STATE_QUEL_DANAS_MONUMENT = 3275,
// Sunwell Gate
WORLD_STATE_AGAMATH_THE_FIRST_GATE_HEALTH = 3253, // guessed, potentially wrong
WORLD_STATE_ROHENDOR_THE_SECOND_GATE_HEALTH = 3255,
WORLD_STATE_ARCHONISUS_THE_FINAL_GATE_HEALTH = 3257,
};
enum WorldStateCondition enum WorldStateCondition
{ {
WORLD_STATE_CONDITION_TROLLBANES_COMMAND = 39911, WORLD_STATE_CONDITION_TROLLBANES_COMMAND = 39911,
@@ -56,6 +74,10 @@ enum WorldStateZoneId
ZONEID_BLOOD_FURNACE = 3713, ZONEID_BLOOD_FURNACE = 3713,
ZONEID_SHATTERED_HALLS = 3714, ZONEID_SHATTERED_HALLS = 3714,
ZONEID_MAGTHERIDON_LAIR = 3836, ZONEID_MAGTHERIDON_LAIR = 3836,
ZONEID_ISLE_OF_QUEL_DANAS = 4080,
ZONEID_MAGISTERS_TERRACE = 4131,
ZONEID_SUNWELL_PLATEAU = 4075,
}; };
enum WorldStateSpells enum WorldStateSpells
@@ -64,6 +86,105 @@ enum WorldStateSpells
SPELL_TROLLBANES_COMMAND = 39911, SPELL_TROLLBANES_COMMAND = 39911,
SPELL_NAZGRELS_FAVOR = 39913, SPELL_NAZGRELS_FAVOR = 39913,
SPELL_KIRU_SONG_OF_VICTORY = 46302,
};
enum WorldStateSaveIds
{
SAVE_ID_QUEL_DANAS = 20,
};
enum WorldStateGameEvents
{
// Isle phases
GAME_EVENT_QUEL_DANAS_PHASE_1 = 101,
GAME_EVENT_QUEL_DANAS_PHASE_2_ONLY = 102,
GAME_EVENT_QUEL_DANAS_PHASE_2_PERMANENT = 103,
GAME_EVENT_QUEL_DANAS_PHASE_2_NO_PORTAL = 104,
GAME_EVENT_QUEL_DANAS_PHASE_2_PORTAL = 105,
GAME_EVENT_QUEL_DANAS_PHASE_3_ONLY = 106,
GAME_EVENT_QUEL_DANAS_PHASE_3_PERMANENT = 107,
GAME_EVENT_QUEL_DANAS_PHASE_3_NO_ANVIL = 108,
GAME_EVENT_QUEL_DANAS_PHASE_3_ANVIL = 109,
GAME_EVENT_QUEL_DANAS_PHASE_4 = 110,
GAME_EVENT_QUEL_DANAS_PHASE_4_NO_MONUMENT = 111,
GAME_EVENT_QUEL_DANAS_PHASE_4_MONUMENT = 112,
GAME_EVENT_QUEL_DANAS_PHASE_4_NO_ALCHEMY_LAB= 113,
GAME_EVENT_QUEL_DANAS_PHASE_4_ALCHEMY_LAB = 114,
GAME_EVENT_QUEL_DANAS_PHASE_4_KIRU = 115,
// SWP Phases
GAME_EVENT_SWP_GATES_PHASE_0 = 116, // All Gates Closed
GAME_EVENT_SWP_GATES_PHASE_1 = 117, // First Gate Open
GAME_EVENT_SWP_GATES_PHASE_2 = 118, // Second Gate Open
GAME_EVENT_SWP_GATES_PHASE_3 = 119, // All Gates Open
};
enum SunsReachPhases
{
SUNS_REACH_PHASE_1_STAGING_AREA,
SUNS_REACH_PHASE_2_SANCTUM,
SUNS_REACH_PHASE_3_ARMORY,
SUNS_REACH_PHASE_4_HARBOR,
};
enum SunsReachSubPhases
{
SUBPHASE_PORTAL = 0x01,
SUBPHASE_ANVIL = 0x02,
SUBPHASE_ALCHEMY_LAB = 0x04,
SUBPHASE_MONUMENT = 0x08,
SUBPHASE_ALL = SUBPHASE_PORTAL | SUBPHASE_ANVIL | SUBPHASE_ALCHEMY_LAB | SUBPHASE_MONUMENT,
};
enum SunsReachCounters
{
COUNTER_ERRATIC_BEHAVIOR,
COUNTER_SANCTUM_WARDS,
COUNTER_BATTLE_FOR_THE_SUNS_REACH_ARMORY,
COUNTER_DISTRACTION_AT_THE_DEAD_SCAR,
COUNTER_INTERCEPTING_THE_MANA_CELLS,
COUNTER_INTERCEPT_THE_REINFORCEMENTS,
COUNTER_TAKING_THE_HARBOR,
COUNTER_MAKING_READY,
COUNTER_DISCOVERING_YOUR_ROOTS,
COUNTER_A_CHARITABLE_DONATION,
COUNTERS_MAX,
};
enum SunwellGates
{
SUNWELL_ALL_GATES_CLOSED,
SUNWELL_AGAMATH_GATE1_OPEN,
SUNWELL_ROHENDOR_GATE2_OPEN,
SUNWELL_ARCHONISUS_GATE3_OPEN,
};
enum SunwellGateCounters
{
COUNTER_AGAMATH_THE_FIRST_GATE,
COUNTER_ROHENDOR_THE_SECOND_GATE,
COUNTER_ARCHONISUS_THE_FINAL_GATE,
COUNTERS_MAX_GATES,
};
struct SunsReachReclamationData
{
uint32 m_phase;
uint32 m_subphaseMask;
uint32 m_sunsReachReclamationCounters[COUNTERS_MAX];
GuidVector m_sunsReachReclamationPlayers;
std::mutex m_sunsReachReclamationMutex;
uint32 m_gate;
uint32 m_gateCounters[COUNTERS_MAX_GATES];
SunsReachReclamationData() : m_phase(SUNS_REACH_PHASE_1_STAGING_AREA), m_subphaseMask(0), m_gate(SUNWELL_ALL_GATES_CLOSED)
{
memset(m_sunsReachReclamationCounters, 0, sizeof(m_sunsReachReclamationCounters));
memset(m_gateCounters, 0, sizeof(m_gateCounters));
}
std::string GetData();
uint32 GetPhasePercentage(uint32 phase);
uint32 GetSubPhasePercentage(uint32 subPhase);
uint32 GetSunwellGatePercentage(uint32 gate);
}; };
// Intended for implementing server wide scripts, note: all behaviour must be safeguarded towards multithreading // Intended for implementing server wide scripts, note: all behaviour must be safeguarded towards multithreading
@@ -73,13 +194,30 @@ class WorldState
WorldState(); WorldState();
virtual ~WorldState(); virtual ~WorldState();
static WorldState* instance(); static WorldState* instance();
void Load();
void Save(WorldStateSaveIds saveId);
void SaveHelper(std::string& stringToSave, WorldStateSaveIds saveId);
void HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId); void HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId);
void HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId); void HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId);
bool IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state = WORLD_STATE_CONDITION_STATE_NONE) const; bool IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state = WORLD_STATE_CONDITION_STATE_NONE) const;
void HandleConditionStateChange(WorldStateCondition conditionId, WorldStateConditionState state); void HandleConditionStateChange(WorldStateCondition conditionId, WorldStateConditionState state);
void HandleExternalEvent(WorldStateEvent eventId, uint32 param); void HandleExternalEvent(WorldStateEvent eventId, uint32 param);
void Update(uint32 diff); void Update(uint32 diff);
void AddSunwellGateProgress(uint32 questId);
void AddSunsReachProgress(uint32 questId);
std::string GetSunsReachPrintout();
void FillInitialWorldStates(ByteBuffer& data, uint32 zoneId, uint32 areaId);
void HandleSunsReachPhaseTransition(uint32 newPhase);
void HandleSunsReachSubPhaseTransition(int32 subPhaseMask, bool initial = false);
void SetSunsReachCounter(SunsReachCounters index, uint32 value);
void HandleSunwellGateTransition(uint32 newGate);
void SetSunwellGateCounter(SunwellGateCounters index, uint32 value);
private: private:
void SendWorldstateUpdate(std::mutex& mutex, GuidVector const& guids, uint32 value, uint32 worldStateId);
void StopSunsReachPhase(bool forward);
void StartSunsReachPhase(bool initial = false);
void StartSunwellGatePhase();
void StopSunwellGatePhase();
void BuffAdalsSongOfBattle(); void BuffAdalsSongOfBattle();
void DispelAdalsSongOfBattle(); void DispelAdalsSongOfBattle();
uint32 _adalSongOfBattleTimer; uint32 _adalSongOfBattleTimer;
@@ -87,6 +225,7 @@ class WorldState
void DispelMagtheridonTeam(TeamId team); void DispelMagtheridonTeam(TeamId team);
bool _isMagtheridonHeadSpawnedHorde; bool _isMagtheridonHeadSpawnedHorde;
bool _isMagtheridonHeadSpawnedAlliance; bool _isMagtheridonHeadSpawnedAlliance;
SunsReachReclamationData m_sunsReachData;
std::map<WorldStateCondition, std::atomic<WorldStateConditionState>> _transportStates; // atomic to avoid having to lock std::map<WorldStateCondition, std::atomic<WorldStateConditionState>> _transportStates; // atomic to avoid having to lock
std::mutex _mutex; // all World State operations are threat unsafe std::mutex _mutex; // all World State operations are threat unsafe
}; };
+2 -2
View File
@@ -292,7 +292,7 @@ public:
Player const* target = player->GetConnectedPlayer(); Player const* target = player->GetConnectedPlayer();
LocaleConstant loc = handler->GetSessionDbcLocale(); LocaleConstant loc = handler->GetSessionDbcLocale();
char const* knownStr = handler->GetAcoreString(LANG_KNOWN); std::string knownStr = handler->GetAcoreString(LANG_KNOWN);
// Search in CharTitles.dbc // Search in CharTitles.dbc
for (uint32 id = 0; id < sCharTitlesStore.GetNumRows(); id++) for (uint32 id = 0; id < sCharTitlesStore.GetNumRows(); id++)
@@ -308,7 +308,7 @@ public:
if (!*name) if (!*name)
continue; continue;
char const* activeStr = ""; std::string activeStr = "";
if (target->GetUInt32Value(PLAYER_CHOSEN_TITLE) == titleInfo->bit_index) if (target->GetUInt32Value(PLAYER_CHOSEN_TITLE) == titleInfo->bit_index)
activeStr = handler->GetAcoreString(LANG_ACTIVE); activeStr = handler->GetAcoreString(LANG_ACTIVE);
+2 -8
View File
@@ -61,28 +61,22 @@ public:
GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
GameEventMgr::ActiveEvents const& activeEvents = sGameEventMgr->GetActiveEventList(); GameEventMgr::ActiveEvents const& activeEvents = sGameEventMgr->GetActiveEventList();
char const* active = handler->GetAcoreString(LANG_ACTIVE); std::string active = handler->GetAcoreString(LANG_ACTIVE);
for (uint16 eventId : activeEvents) for (uint16 eventId : activeEvents)
{ {
GameEventData const& eventData = events[eventId]; GameEventData const& eventData = events[eventId];
if (handler->GetSession()) if (handler->GetSession())
{
handler->PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT, eventId, eventId, eventData.description, active); handler->PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT, eventId, eventId, eventData.description, active);
}
else else
{
handler->PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE, eventId, eventData.description, active); handler->PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE, eventId, eventData.description, active);
}
++counter; ++counter;
} }
if (counter == 0) if (counter == 0)
{
handler->SendSysMessage(LANG_NOEVENTFOUND); handler->SendSysMessage(LANG_NOEVENTFOUND);
}
handler->SetSentErrorMessage(true); handler->SetSentErrorMessage(true);
@@ -108,7 +102,7 @@ public:
GameEventMgr::ActiveEvents const& activeEvents = sGameEventMgr->GetActiveEventList(); GameEventMgr::ActiveEvents const& activeEvents = sGameEventMgr->GetActiveEventList();
bool active = activeEvents.find(eventId) != activeEvents.end(); bool active = activeEvents.find(eventId) != activeEvents.end();
char const* activeStr = active ? handler->GetAcoreString(LANG_ACTIVE) : ""; std::string activeStr = active ? handler->GetAcoreString(LANG_ACTIVE) : "";
std::string startTimeStr = Acore::Time::TimeToTimestampStr(Seconds(eventData.start)); std::string startTimeStr = Acore::Time::TimeToTimestampStr(Seconds(eventData.start));
std::string endTimeStr = Acore::Time::TimeToTimestampStr(Seconds(eventData.end)); std::string endTimeStr = Acore::Time::TimeToTimestampStr(Seconds(eventData.end));
+2 -2
View File
@@ -460,8 +460,8 @@ public:
wstrToLower(namePart); wstrToLower(namePart);
char const* talentStr = handler->GetAcoreString(LANG_TALENT); std::string talentStr = handler->GetAcoreString(LANG_TALENT);
char const* passiveStr = handler->GetAcoreString(LANG_PASSIVE); std::string passiveStr = handler->GetAcoreString(LANG_PASSIVE);
Unit::AuraApplicationMap const& auras = unit->GetAppliedAuras(); Unit::AuraApplicationMap const& auras = unit->GetAppliedAuras();
handler->PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, auras.size()); handler->PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, auras.size());
+5 -9
View File
@@ -308,7 +308,7 @@ public:
return true; return true;
} }
char const* active = activeEvents.find(id) != activeEvents.end() ? handler->GetAcoreString(LANG_ACTIVE) : ""; std::string active = activeEvents.find(id) != activeEvents.end() ? handler->GetAcoreString(LANG_ACTIVE) : "";
if (handler->GetSession()) if (handler->GetSession())
{ {
@@ -806,7 +806,7 @@ public:
return true; return true;
} }
char const* statusStr = ""; std::string statusStr = "";
if (target) if (target)
{ {
@@ -862,7 +862,7 @@ public:
return true; return true;
} }
char const* statusStr = ""; std::string statusStr = "";
if (target) if (target)
{ {
@@ -1498,20 +1498,16 @@ public:
return true; return true;
} }
char const* knownStr = target && target->HasTitle(titleInfo) ? handler->GetAcoreString(LANG_KNOWN) : ""; std::string knownStr = target && target->HasTitle(titleInfo) ? handler->GetAcoreString(LANG_KNOWN) : "";
char const* activeStr = target && target->GetUInt32Value(PLAYER_CHOSEN_TITLE) == titleInfo->bit_index ? handler->GetAcoreString(LANG_ACTIVE) : ""; std::string activeStr = target && target->GetUInt32Value(PLAYER_CHOSEN_TITLE) == titleInfo->bit_index ? handler->GetAcoreString(LANG_ACTIVE) : "";
std::string titleNameStr = Acore::StringFormat(name, targetName); std::string titleNameStr = Acore::StringFormat(name, targetName);
// send title in "id (idx:idx) - [namedlink locale]" format // send title in "id (idx:idx) - [namedlink locale]" format
if (handler->GetSession()) if (handler->GetSession())
{
handler->PSendSysMessage(LANG_TITLE_LIST_CHAT, titleInfo->ID, titleInfo->bit_index, titleInfo->ID, titleNameStr, localeNames[locale], knownStr, activeStr); handler->PSendSysMessage(LANG_TITLE_LIST_CHAT, titleInfo->ID, titleInfo->bit_index, titleInfo->ID, titleNameStr, localeNames[locale], knownStr, activeStr);
}
else else
{
handler->PSendSysMessage(LANG_TITLE_LIST_CONSOLE, titleInfo->ID, titleInfo->bit_index, titleNameStr, localeNames[locale], knownStr, activeStr); handler->PSendSysMessage(LANG_TITLE_LIST_CONSOLE, titleInfo->ID, titleInfo->bit_index, titleNameStr, localeNames[locale], knownStr, activeStr);
}
++counter; ++counter;
} }
+7 -22
View File
@@ -1992,8 +1992,8 @@ public:
uint32 mapId; uint32 mapId;
uint32 areaId; uint32 areaId;
uint32 phase = 0; uint32 phase = 0;
char const* areaName = nullptr; std::string areaName = "";
char const* zoneName = nullptr; std::string zoneName = "";
// Guild data print variables defined so that they exist, but are not necessarily used // Guild data print variables defined so that they exist, but are not necessarily used
uint32 guildId = 0; uint32 guildId = 0;
@@ -2325,19 +2325,13 @@ public:
} }
} }
if (!zoneName) if (zoneName.empty())
{
zoneName = handler->GetAcoreString(LANG_UNKNOWN); zoneName = handler->GetAcoreString(LANG_UNKNOWN);
}
if (areaName) if (!areaName.empty())
{
handler->PSendSysMessage(LANG_PINFO_CHR_MAP_WITH_AREA, map->name[locale], zoneName, areaName); handler->PSendSysMessage(LANG_PINFO_CHR_MAP_WITH_AREA, map->name[locale], zoneName, areaName);
}
else else
{
handler->PSendSysMessage(LANG_PINFO_CHR_MAP, map->name[locale], zoneName); handler->PSendSysMessage(LANG_PINFO_CHR_MAP, map->name[locale], zoneName);
}
// Output XVII. - XVIX. if they are not empty // Output XVII. - XVIX. if they are not empty
if (!guildName.empty()) if (!guildName.empty())
@@ -3022,18 +3016,9 @@ public:
return false; return false;
} }
const char* str = sObjectMgr->GetAcoreString(id, locale ? static_cast<LocaleConstant>(*locale) : DEFAULT_LOCALE); std::string str = sObjectMgr->GetAcoreString(id, locale ? static_cast<LocaleConstant>(*locale) : DEFAULT_LOCALE);
handler->SendSysMessage(str);
if (!strcmp(str, "<error>")) return true;
{
handler->PSendSysMessage(LANG_NO_ACORE_STRING_FOUND, id);
return true;
}
else
{
handler->SendSysMessage(str);
return true;
}
} }
static bool HandleOpenDoorCommand(ChatHandler* handler, Optional<float> range) static bool HandleOpenDoorCommand(ChatHandler* handler, Optional<float> range)
+1 -2
View File
@@ -217,8 +217,7 @@ public:
static bool HandleMmapStatsCommand(ChatHandler* handler) static bool HandleMmapStatsCommand(ChatHandler* handler)
{ {
handler->PSendSysMessage("mmap stats:"); handler->PSendSysMessage("mmap stats:");
//handler->PSendSysMessage(" global mmap pathfinding is {}abled", DisableMgr::IsPathfindingEnabled(mapId) ? "en" : "dis"); //handler->PSendSysMessage(" global mmap pathfinding is {}abled", sDisableMgr->IsPathfindingEnabled(mapId) ? "en" : "dis");
MMAP::MMapMgr* manager = MMAP::MMapFactory::createOrGetMMapMgr(); MMAP::MMapMgr* manager = MMAP::MMapFactory::createOrGetMMapMgr();
handler->PSendSysMessage(" {} maps loaded with {} tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount()); handler->PSendSysMessage(" {} maps loaded with {} tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
+2 -2
View File
@@ -1063,9 +1063,9 @@ public:
static bool HandleReloadDisablesCommand(ChatHandler* handler) static bool HandleReloadDisablesCommand(ChatHandler* handler)
{ {
LOG_INFO("server.loading", "Reloading disables table..."); LOG_INFO("server.loading", "Reloading disables table...");
DisableMgr::LoadDisables(); sDisableMgr->LoadDisables();
LOG_INFO("server.loading", "Checking quest disables..."); LOG_INFO("server.loading", "Checking quest disables...");
DisableMgr::CheckQuestDisables(); sDisableMgr->CheckQuestDisables();
handler->SendGlobalGMSysMessage("DB table `disables` reloaded."); handler->SendGlobalGMSysMessage("DB table `disables` reloaded.");
return true; return true;
} }
@@ -62,6 +62,7 @@ void AddSC_wp_commandscript();
void AddSC_cache_commandscript(); void AddSC_cache_commandscript();
void AddSC_item_commandscript(); void AddSC_item_commandscript();
void AddSC_player_settings_commandscript(); void AddSC_player_settings_commandscript();
void AddSC_worldstate_commandscript();
// The name of this function should match: // The name of this function should match:
// void Add${NameOfDirectory}Scripts() // void Add${NameOfDirectory}Scripts()
@@ -113,4 +114,5 @@ void AddCommandsScripts()
AddSC_cache_commandscript(); AddSC_cache_commandscript();
AddSC_item_commandscript(); AddSC_item_commandscript();
AddSC_player_settings_commandscript(); AddSC_player_settings_commandscript();
AddSC_worldstate_commandscript();
} }
@@ -0,0 +1,133 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
Name: worldstate_commandscript
%Complete: 100
Comment: All worldstate related commands
Category: commandscripts
EndScriptData */
#include "Chat.h"
#include "CommandScript.h"
#include "Common.h"
#include "WorldState.h"
using namespace Acore::ChatCommands;
class worldstate_commandscript : public CommandScript
{
public:
worldstate_commandscript() : CommandScript("worldstate_commandscript") { }
ChatCommandTable GetCommands() const override
{
static ChatCommandTable sunsreachCommandTable =
{
{ "status", HandleSunsReachReclamationStatusCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "phase", HandleSunsReachReclamationPhaseCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "subphase", HandleSunsReachReclamationSubPhaseCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "counter", HandleSunsReachReclamationCounterCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "gate", HandleSunwellGateCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "gatecounter", HandleSunwellGateCounterCommand, SEC_ADMINISTRATOR, Console::Yes },
};
static ChatCommandTable worldStateCommandTable =
{
{ "sunsreach", sunsreachCommandTable }
};
static ChatCommandTable commandTable =
{
{ "worldstate", worldStateCommandTable }
};
return commandTable;
}
static bool HandleSunsReachReclamationStatusCommand(ChatHandler* handler )
{
handler->PSendSysMessage(sWorldState->GetSunsReachPrintout());
return true;
}
static bool HandleSunsReachReclamationPhaseCommand(ChatHandler* handler, uint32 phase)
{
if (phase > SUNS_REACH_PHASE_4_HARBOR)
{
handler->PSendSysMessage("Invalid phase, see \".worldstate sunsreach phase\" for usage");
return false;
}
sWorldState->HandleSunsReachPhaseTransition(phase);
handler->PSendSysMessage(sWorldState->GetSunsReachPrintout());
return true;
}
static bool HandleSunsReachReclamationSubPhaseCommand(ChatHandler* handler, uint32 subphase)
{
if (subphase > SUBPHASE_ALL)
{
handler->PSendSysMessage("Invalid subphase, see \".worldstate sunsreach subphase\" for usage");
return false;
}
sWorldState->HandleSunsReachSubPhaseTransition(subphase);;
handler->PSendSysMessage(sWorldState->GetSunsReachPrintout());
return true;
}
static bool HandleSunsReachReclamationCounterCommand(ChatHandler* handler, Optional<uint32> index, Optional<uint32> value)
{
if (!index || !value || index.value() >= COUNTERS_MAX)
{
handler->PSendSysMessage("Syntax: .worldstate sunsreach counter <index> <value>.");
handler->PSendSysMessage(sWorldState->GetSunsReachPrintout());
return true;
}
sWorldState->SetSunsReachCounter(SunsReachCounters(index.value()), value.value());
handler->PSendSysMessage(sWorldState->GetSunsReachPrintout());
return true;
}
static bool HandleSunwellGateCommand(ChatHandler* handler, uint32 newGate)
{
if (newGate > SUNWELL_ARCHONISUS_GATE3_OPEN)
{
handler->PSendSysMessage("Invalid phase, see \".worldstate sunsreach gate\" for usage");
return false;
}
sWorldState->HandleSunwellGateTransition(newGate);
handler->PSendSysMessage(sWorldState->GetSunsReachPrintout());
return true;
}
static bool HandleSunwellGateCounterCommand(ChatHandler* handler, Optional<uint32> index, Optional<uint32> value)
{
if (!index || !value || index.value() >= COUNTERS_MAX_GATES)
{
handler->PSendSysMessage("Syntax: .worldstate sunsreach gatecounter <index> <value>.");
handler->PSendSysMessage(sWorldState->GetSunsReachPrintout());
return true;
}
sWorldState->SetSunwellGateCounter(SunwellGateCounters(index.value()), value.value());
handler->PSendSysMessage(sWorldState->GetSunsReachPrintout());
return true;
}
};
void AddSC_worldstate_commandscript()
{
new worldstate_commandscript();
}
@@ -21,102 +21,120 @@
enum Yells enum Yells
{ {
SAY_AGGRO = 0, SAY_AGGRO = 0, // Combat start
SAY_ENERGY = 1, SAY_ENERGY = 1, // Pure energy spawn
SAY_OVERLOAD = 2, SAY_OVERLOAD = 2, // Final phase
SAY_KILL = 3, SAY_KILL = 3, // Player kill
EMOTE_DISCHARGE_ENERGY = 4 EMOTE_DISCHARGE_ENERGY = 4, // Energy discharge warning
EMOTE_OVERLOAD = 5 // Overload emote
}; };
enum Spells enum Spells
{ {
// Pure energy spell info SPELL_ENERGY_FEEDBACK_CHANNEL = 44328, // Pure energy channel
SPELL_ENERGY_FEEDBACK_CHANNEL = 44328, SPELL_ENERGY_FEEDBACK = 44335, // Pure energy death effect
SPELL_ENERGY_FEEDBACK = 44335, SPELL_CHAIN_LIGHTNING = 44318, // Basic attack
SPELL_OVERLOAD = 44352, // Enrage ability
// Vexallus spell info SPELL_ARCANE_SHOCK = 44319, // Basic attack
SPELL_CHAIN_LIGHTNING = 44318, SPELL_SUMMON_PURE_ENERGY_N = 44322, // Normal mode summon
SPELL_OVERLOAD = 44352, SPELL_SUMMON_PURE_ENERGY_H1 = 46154, // Heroic mode summon 1
SPELL_ARCANE_SHOCK = 44319, SPELL_SUMMON_PURE_ENERGY_H2 = 46159 // Heroic mode summon 2
SPELL_SUMMON_PURE_ENERGY_N = 44322,
SPELL_SUMMON_PURE_ENERGY_H1 = 46154,
SPELL_SUMMON_PURE_ENERGY_H2 = 46159
};
enum Misc
{
NPC_PURE_ENERGY = 24745
}; };
struct boss_vexallus : public BossAI struct boss_vexallus : public BossAI
{ {
boss_vexallus(Creature* creature) : BossAI(creature, DATA_VEXALLUS), _energyCooldown(false) { } boss_vexallus(Creature* creature) : BossAI(creature, DATA_VEXALLUS), _energyCooldown(false), _energyCount(0) { }
void Reset() override void Reset() override
{ {
_Reset(); _Reset();
_energyCooldown = false; _energyCooldown = false;
_energyCount = 0;
ScheduleHealthCheckEvent({ 85, 70, 55, 40, 25 }, [&] ScheduleHealthCheckEvent({ 85, 70, 55, 40, 25 }, [&]
{ {
if (!_energyCooldown) scheduler.Schedule(1s, [this](TaskContext context)
{ {
Talk(SAY_ENERGY); if (!_energyCooldown)
Talk(EMOTE_DISCHARGE_ENERGY);
if (IsHeroic())
{ {
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H1); Talk(SAY_ENERGY);
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H2); Talk(EMOTE_DISCHARGE_ENERGY);
if (IsHeroic())
{
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H1);
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_H2);
}
else
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_N);
_energyCooldown = true;
++_energyCount;
me->m_Events.AddEventAtOffset([&]
{
_energyCooldown = false;
}, 5s);
} }
else else
DoCastSelf(SPELL_SUMMON_PURE_ENERGY_N); context.Repeat(5s);
_energyCooldown = true; });
scheduler.Schedule(5s, [this](TaskContext)
{
_energyCooldown = false;
});
}
}); });
ScheduleHealthCheckEvent(20, [&] ScheduleHealthCheckEvent(20, [&]
{ {
scheduler.CancelAll(); scheduler.Schedule(1s, [this](TaskContext context)
DoCastSelf(SPELL_OVERLOAD, true); {
if (_energyCount == 5 && !_energyCooldown)
{
scheduler.CancelAll();
Talk(SAY_OVERLOAD);
Talk(EMOTE_OVERLOAD);
DoCastSelf(SPELL_OVERLOAD, true);
}
else
context.Repeat(5s);
});
}); });
} }
void JustDied(Unit*) override
{
_JustDied();
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_ENERGY_FEEDBACK);
}
void KilledUnit(Unit* victim) override void KilledUnit(Unit* victim) override
{ {
if (victim->IsPlayer()) if (victim->IsPlayer())
Talk(SAY_KILL); Talk(SAY_KILL);
} }
void JustEngagedWith(Unit* /*who*/) override void JustEngagedWith(Unit*) override
{ {
_JustEngagedWith(); _JustEngagedWith();
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
ScheduleTimedEvent(8s, [&] ScheduleTimedEvent(5s, [&]
{ {
DoCastRandomTarget(SPELL_CHAIN_LIGHTNING); DoCastRandomTarget(SPELL_CHAIN_LIGHTNING);
}, 8s, 8s); }, 8s);
ScheduleTimedEvent(5s, [&] ScheduleTimedEvent(5s, [&]
{ {
DoCastRandomTarget(SPELL_ARCANE_SHOCK); DoCastRandomTarget(SPELL_ARCANE_SHOCK);
}, 8s, 8s); }, 5s);
} }
void JustSummoned(Creature* summon) override void JustSummoned(Creature* summon) override
{ {
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{ {
summon->SetReactState(REACT_PASSIVE);
summon->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); summon->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);
summon->CastSpell(target, SPELL_ENERGY_FEEDBACK_CHANNEL, false); summon->CastSpell(target, SPELL_ENERGY_FEEDBACK_CHANNEL, false);
} }
summons.Summon(summon); summons.Summon(summon);
} }
@@ -130,6 +148,7 @@ struct boss_vexallus : public BossAI
private: private:
bool _energyCooldown; bool _energyCooldown;
uint8 _energyCount;
}; };
void AddSC_boss_vexallus() void AddSC_boss_vexallus()
@@ -96,14 +96,6 @@ public:
if (GameObject* gobj = GetGameObject(DATA_ICEBARRIER)) if (GameObject* gobj = GetGameObject(DATA_ICEBARRIER))
gobj->SendUpdateToPlayer(player); gobj->SendUpdateToPlayer(player);
} }
void OnCreatureCreate(Creature* creature) override
{
if (creature->GetSpawnId() > 0 || !creature->GetOwnerGUID().IsPlayer())
creature->CastSpell(creature, SPELL_SUNWELL_RADIANCE, true);
InstanceScript::OnCreatureCreate(creature);
}
}; };
InstanceScript* GetInstanceScript(InstanceMap* map) const override InstanceScript* GetInstanceScript(InstanceMap* map) const override
@@ -106,11 +106,6 @@ enum GameObjectIds
GO_ORB_OF_THE_BLUE_DRAGONFLIGHT4 = 188116 GO_ORB_OF_THE_BLUE_DRAGONFLIGHT4 = 188116
}; };
enum SpellIds
{
SPELL_SUNWELL_RADIANCE = 45769,
};
template <class AI, class T> template <class AI, class T>
inline AI* GetSunwellPlateauAI(T* obj) inline AI* GetSunwellPlateauAI(T* obj)
{ {
@@ -115,11 +115,13 @@ public:
for (uint8 i = 0; i < RAND_VENDOR; ++i) for (uint8 i = 0; i < RAND_VENDOR; ++i)
RandVendor[i] = NOT_STARTED; RandVendor[i] = NOT_STARTED;
StorePersistentData(DATA_TIMED_RUN, 0);
} }
void OnPlayerEnter(Player* /*player*/) override void OnPlayerEnter(Player* /*player*/) override
{ {
if (!scheduler.IsGroupScheduled(GROUP_TIMED_RUN)) if (!scheduler.IsGroupScheduled(GROUP_TIMED_RUN) && GetPersistentData(DATA_TIMED_RUN))
DoAction(ACTION_START_TIMED_RUN); DoAction(ACTION_START_TIMED_RUN);
} }
@@ -293,53 +295,36 @@ public:
if (!InstanceScript::SetBossState(type, state)) if (!InstanceScript::SetBossState(type, state))
return false; return false;
switch (type) if (state == DONE)
{ {
case DATA_NALORAKK: switch (type)
if (state == DONE) {
{ case DATA_NALORAKK:
if (uint32 timer = GetPersistentData(DATA_TIMED_RUN)) if (uint32 timer = GetPersistentData(DATA_TIMED_RUN))
{ {
StorePersistentData(DATA_TIMED_RUN, timer += 15); StorePersistentData(DATA_TIMED_RUN, timer += 15);
DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, timer); DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, timer);
} }
SummonHostage(0); SummonHostage(type);
} break;
break; case DATA_AKILZON:
case DATA_AKILZON:
if (state == DONE)
{
if (uint32 timer = GetPersistentData(DATA_TIMED_RUN)) if (uint32 timer = GetPersistentData(DATA_TIMED_RUN))
{ {
StorePersistentData(DATA_TIMED_RUN, timer += 10); StorePersistentData(DATA_TIMED_RUN, timer += 10);
DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, timer); DoUpdateWorldState(WORLDSTATE_TIME_TO_SACRIFICE, timer);
} }
SummonHostage(1); SummonHostage(type);
} break;
break; case DATA_JANALAI:
case DATA_JANALAI: case DATA_HALAZZI:
if (state == DONE) SummonHostage(type);
SummonHostage(2); break;
break; case DATA_HEXLORD:
case DATA_HALAZZI:
if (state == DONE)
SummonHostage(3);
break;
case DATA_HEXLORD:
if (state == IN_PROGRESS)
HandleGameObject(ObjectGuid::Empty, false, GetGameObject(DATA_HEXLORD_GATE));
else if (state == NOT_STARTED)
CheckInstanceStatus();
else if (state == DONE)
{
if (GameObject* zuljinGate = GetGameObject(DATA_ZULJIN_GATE)) if (GameObject* zuljinGate = GetGameObject(DATA_ZULJIN_GATE))
zuljinGate->RemoveGameObjectFlag(GO_FLAG_LOCKED); zuljinGate->RemoveGameObjectFlag(GO_FLAG_LOCKED);
} break;
break; }
}
if (state == DONE)
{
if (GetPersistentData(DATA_TIMED_RUN) && AllBossesDone({ DATA_NALORAKK, DATA_AKILZON, DATA_JANALAI, DATA_HALAZZI })) if (GetPersistentData(DATA_TIMED_RUN) && AllBossesDone({ DATA_NALORAKK, DATA_AKILZON, DATA_JANALAI, DATA_HALAZZI }))
{ {
StorePersistentData(DATA_TIMED_RUN, 0); StorePersistentData(DATA_TIMED_RUN, 0);
@@ -348,6 +333,16 @@ public:
CheckInstanceStatus(); CheckInstanceStatus();
} }
else
{
if (type == DATA_HEXLORD)
{
if (state == IN_PROGRESS)
HandleGameObject(ObjectGuid::Empty, false, GetGameObject(DATA_HEXLORD_GATE));
else if (state == NOT_STARTED)
CheckInstanceStatus();
}
}
return true; return true;
} }
@@ -191,7 +191,7 @@ public:
if (creature->IsSummon() && _bossWave != TO_BE_DECIDED) if (creature->IsSummon() && _bossWave != TO_BE_DECIDED)
{ {
if (_currentWave == 0) if (_currentWave == 0)
creature->SetDisableReputationGain(true); creature->SetReputationRewardDisabled(true);
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, ++trash); // Update the instance wave count on new trash spawn DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, ++trash); // Update the instance wave count on new trash spawn
_encounterNPCs.insert(creature->GetGUID()); // Used for despawning on wipe _encounterNPCs.insert(creature->GetGUID()); // Used for despawning on wipe
} }
@@ -107,7 +107,7 @@ public:
InstanceScript* pInstance; InstanceScript* pInstance;
EventMap events; EventMap events;
bool lock; bool lock, inCenter;
float x, y, z; float x, y, z;
int32 releaseLockTimer; int32 releaseLockTimer;
@@ -134,6 +134,7 @@ public:
me->CastSpell(me, SPELL_EVOCATION, true); me->CastSpell(me, SPELL_EVOCATION, true);
events.Reset(); events.Reset();
lock = false; lock = false;
inCenter = false;
x = 0.0f; x = 0.0f;
y = 0.0f; y = 0.0f;
z = 0.0f; z = 0.0f;
@@ -222,9 +223,14 @@ public:
{ {
pInstance->SetData(DATA_UROM, DONE); pInstance->SetData(DATA_UROM, DONE);
} }
me->SetCanFly(false);
me->SetDisableGravity(false); // Body teleportation required only when boss is flying in the center
me->NearTeleportTo(x, y, z, 0.0f); if (inCenter)
{
me->SetCanFly(false);
me->SetDisableGravity(false);
me->NearTeleportTo(x, y, z, 0.0f);
}
} }
void KilledUnit(Unit* /*victim*/) override void KilledUnit(Unit* /*victim*/) override
@@ -281,6 +287,7 @@ public:
me->SetCanFly(true); me->SetCanFly(true);
me->SetDisableGravity(true); me->SetDisableGravity(true);
me->NearTeleportTo(1103.69f, 1048.76f, 512.279f, 1.16f); me->NearTeleportTo(1103.69f, 1048.76f, 512.279f, 1.16f);
inCenter = true;
Talk(SAY_ARCANE_EXPLOSION); Talk(SAY_ARCANE_EXPLOSION);
Talk(EMOTE_ARCANE_EXPLOSION); Talk(EMOTE_ARCANE_EXPLOSION);
@@ -356,6 +363,7 @@ public:
me->SetControlled(false, UNIT_STATE_ROOT); me->SetControlled(false, UNIT_STATE_ROOT);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->GetMotionMaster()->MoveChase(me->GetVictim()); me->GetMotionMaster()->MoveChase(me->GetVictim());
inCenter = false;
break; break;
} }
} }
@@ -365,6 +373,7 @@ public:
me->SetCanFly(false); me->SetCanFly(false);
me->SetDisableGravity(false); me->SetDisableGravity(false);
me->SetControlled(false, UNIT_STATE_ROOT); me->SetControlled(false, UNIT_STATE_ROOT);
inCenter = false;
ScriptedAI::EnterEvadeMode(why); ScriptedAI::EnterEvadeMode(why);
} }
}; };
@@ -0,0 +1,49 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureScript.h"
#include "WorldState.h"
class npc_suns_reach_reclamation : public CreatureScript
{
public:
npc_suns_reach_reclamation() : CreatureScript("npc_suns_reach_reclamation") { }
bool OnQuestReward(Player* /*player*/, Creature* /*creature*/, const Quest* quest, uint32 /*slot*/) override
{
sWorldState->AddSunsReachProgress(quest->GetQuestId());
return true;
}
};
class npc_sunwell_gate : public CreatureScript
{
public:
npc_sunwell_gate() : CreatureScript("npc_sunwell_gate") { }
bool OnQuestReward(Player* /*player*/, Creature* /*creature*/, const Quest* quest, uint32 /*slot*/) override
{
sWorldState->AddSunwellGateProgress(quest->GetQuestId());
return true;
}
};
void AddSC_suns_reach_reclamation()
{
new npc_suns_reach_reclamation();
new npc_sunwell_gate();
}
@@ -33,6 +33,7 @@ void AddSC_player_scripts();
void AddSC_npc_stave_of_ancients(); void AddSC_npc_stave_of_ancients();
void AddSC_server_mail(); void AddSC_server_mail();
void AddSC_transport_zeppelins(); void AddSC_transport_zeppelins();
void AddSC_suns_reach_reclamation();
// The name of this function should match: // The name of this function should match:
// void Add${NameOfDirectory}Scripts() // void Add${NameOfDirectory}Scripts()
@@ -55,4 +56,5 @@ void AddWorldScripts()
AddSC_npc_stave_of_ancients(); AddSC_npc_stave_of_ancients();
AddSC_server_mail(); AddSC_server_mail();
AddSC_transport_zeppelins(); AddSC_transport_zeppelins();
AddSC_suns_reach_reclamation();
} }
+1 -1
View File
@@ -75,7 +75,7 @@ public:
MOCK_METHOD(void, SendGlobalMessage, (WorldPacket const* packet, WorldSession* self, TeamId teamId), ()); MOCK_METHOD(void, SendGlobalMessage, (WorldPacket const* packet, WorldSession* self, TeamId teamId), ());
MOCK_METHOD(void, SendGlobalGMMessage, (WorldPacket const* packet, WorldSession* self, TeamId teamId), ()); MOCK_METHOD(void, SendGlobalGMMessage, (WorldPacket const* packet, WorldSession* self, TeamId teamId), ());
MOCK_METHOD(bool, SendZoneMessage, (uint32 zone, WorldPacket const* packet, WorldSession* self, TeamId teamId), ()); MOCK_METHOD(bool, SendZoneMessage, (uint32 zone, WorldPacket const* packet, WorldSession* self, TeamId teamId), ());
MOCK_METHOD(void, SendZoneText, (uint32 zone, const char* text, WorldSession* self, TeamId teamId), ()); MOCK_METHOD(void, SendZoneText, (uint32 zone, std::string text, WorldSession* self, TeamId teamId), ());
MOCK_METHOD(void, SendServerMessage, (ServerMessageType messageID, std::string stringParam, Player* player)); MOCK_METHOD(void, SendServerMessage, (ServerMessageType messageID, std::string stringParam, Player* player));
MOCK_METHOD(bool, IsShuttingDown, (), (const)); MOCK_METHOD(bool, IsShuttingDown, (), (const));
MOCK_METHOD(uint32, GetShutDownTimeLeft, (), (const)); MOCK_METHOD(uint32, GetShutDownTimeLeft, (), (const));