diff --git a/modules/mod-hardcore/src/HardcoreDatabase.cpp b/modules/mod-hardcore/src/HardcoreDatabase.cpp index e1a073a..2443a72 100644 --- a/modules/mod-hardcore/src/HardcoreDatabase.cpp +++ b/modules/mod-hardcore/src/HardcoreDatabase.cpp @@ -14,8 +14,8 @@ HardcoreDatabase* HardcoreDatabase::instance() bool HardcoreDatabase::LoadHardcoreData(uint32 playerGuid, HardcoreData& data) { - std::string query = Acore::StringFormat("SELECT 角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 死亡原因, 击杀者编号,奖励已领取 FROM 角色硬核模式 WHERE 角色编号 = {}", playerGuid); - + std::string query = Acore::StringFormat("SELECT 角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 状态信息, 击杀者编号,是否已领取奖励 FROM 角色硬核模式 WHERE 角色编号 = {}", playerGuid); + QueryResult result = CharacterDatabase.Query(query); if (!result) @@ -30,7 +30,7 @@ bool HardcoreDatabase::LoadHardcoreData(uint32 playerGuid, HardcoreData& data) data.finalLevel = fields[5].Get(); data.deathCause = fields[6].Get(); data.killerGuid = fields[7].Get(); - data.rewardReceived = fields[8].Get(); // 奖励领取状态 + data.rewardReceived = fields[8].Get(); // 加载奖励领取状态 return true; } @@ -40,8 +40,7 @@ void HardcoreDatabase::SaveHardcoreData(const HardcoreData& data) std::string escapedCause = data.deathCause; CharacterDatabase.EscapeString(escapedCause); - std::string query = Acore::StringFormat( - "REPLACE INTO 角色硬核模式 (角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 死亡原因, 击杀者编号) VALUES ({}, {}, {}, {}, {}, {}, '{}', {})", + std::string query = Acore::StringFormat("REPLACE INTO 角色硬核模式 (角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 状态信息, 击杀者编号,是否已领取奖励) VALUES ({}, {}, {}, {}, {}, {}, '{}', {}, {})", data.guid, static_cast(data.status), data.difficultyTypeId, @@ -50,7 +49,7 @@ void HardcoreDatabase::SaveHardcoreData(const HardcoreData& data) data.finalLevel, escapedCause, data.killerGuid, - data.rewardReceived ? 1 : 0 // 新增:保存奖励领取状态 + data.rewardReceived ? 1 : 0 // 保存奖励领取状态 ); CharacterDatabase.Execute(query); diff --git a/modules/mod-hardcore/src/HardcoreDatabase.h b/modules/mod-hardcore/src/HardcoreDatabase.h index 95fe5d5..cf102c5 100644 --- a/modules/mod-hardcore/src/HardcoreDatabase.h +++ b/modules/mod-hardcore/src/HardcoreDatabase.h @@ -6,12 +6,13 @@ #include "Define.h" #include "QueryResult.h" -// 前向声明,避免循环包含 +// 前向声明,避免循环包含 enum HardcoreStatus : uint8 { - HC_STATUS_NORMAL = 0, // 未启用硬核模式 - 玩家处于正常游戏模式 - HC_STATUS_HARDCORE= 1, // 已启用硬核模式 - 玩家处于硬核模式,死亡将是永久的 - HC_STATUS_DEAD = 2 // 硬核模式中已死亡 - 玩家在硬核模式中死亡,无法复活 + HC_STATUS_NORMAL = 0, // 从未选择过硬核模式 + HC_STATUS_HARDCORE = 1, // 正在进行硬核模式 + HC_STATUS_DEAD = 2, // 硬核模式中死亡 + HC_STATUS_COMPLETED = 3 // 已完成硬核模式 }; struct HardcoreData diff --git a/modules/mod-hardcore/src/HardcoreMode.cpp b/modules/mod-hardcore/src/HardcoreMode.cpp index 030868b..ca59f85 100644 --- a/modules/mod-hardcore/src/HardcoreMode.cpp +++ b/modules/mod-hardcore/src/HardcoreMode.cpp @@ -13,20 +13,33 @@ #include "Opcodes.h" #include #include -// HardcoreMode 单例实现 + +// 单例实现 HardcoreMode* HardcoreMode::instance() { static HardcoreMode instance; return &instance; } + +// 玩家是否开启了硬核模式 bool HardcoreMode::IsHardcorePlayer(Player* player) { if (!player) return false; - std::lock_guard lock(_dataMutex); + + std::lock_guard lock(_dataMutex); auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - return it != _hardcoreData.end() && it->second.status != HC_STATUS_NORMAL; + if (it == _hardcoreData.end() || it->second.status == HC_STATUS_NORMAL) + return false; + + // 检查是否为正常模式(编号1) + if (it->second.difficultyTypeId == 1) + return false; + + return (it->second.status == HC_STATUS_HARDCORE || it->second.status == HC_STATUS_DEAD); } + +// 获取玩家硬核模式状态 HardcoreStatus HardcoreMode::GetHardcoreStatus(Player* player) { if (!player) @@ -35,26 +48,8 @@ HardcoreStatus HardcoreMode::GetHardcoreStatus(Player* player) auto it = _hardcoreData.find(player->GetGUID().GetCounter()); return it != _hardcoreData.end() ? it->second.status : HC_STATUS_NORMAL; } -HardcoreStatus HardcoreMode::GetHardcoreStatusByGuid(uint32 guid) -{ - // 首先检查内存缓存 - { - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(guid); - if (it != _hardcoreData.end()) - return it->second.status; - } - // 如果内存中没有,从数据库加载 - HardcoreData data; - if (HardcoreDatabase::instance()->LoadHardcoreData(guid, data)) - { - std::lock_guard lock(_dataMutex); - _hardcoreData[guid] = data; - return data.status; - } - return HC_STATUS_NORMAL; -} +// 设置玩家的硬核模式和难度类型 void HardcoreMode::EnableHardcoreMode(Player* player, uint32 difficultyTypeId) { if (!player) @@ -100,16 +95,13 @@ void HardcoreMode::EnableHardcoreMode(Player* player, uint32 difficultyTypeId) data.finalLevel = 0; data.deathCause = ""; data.killerGuid = 0; + { std::lock_guard lock(_dataMutex); _hardcoreData[data.guid] = data; } - // 更新 characters 表,存储具体的难度类型ID - std::string updateQuery = Acore::StringFormat("UPDATE characters SET 硬核模式 = {} WHERE guid = {}", difficultyTypeId, player->GetGUID().GetCounter()); - CharacterDatabase.Execute(updateQuery); - - SaveHardcoreData(data); + SaveHardcoreData(data);// 移除 characters 表更新,只保存到角色硬核模式表 // 构建动态消息 std::string message = "已选择" + modeName + "!\n"; @@ -149,99 +141,135 @@ void HardcoreMode::EnableHardcoreMode(Player* player, uint32 difficultyTypeId) } ChatHandler(player->GetSession()).SendSysMessage(message); - LOG_INFO("hardcore", "Player {} ({}) enabled {} (difficulty type {})", - player->GetName(), player->GetGUID().ToString(), modeName, difficultyTypeId); + LOG_INFO("server.loading", "Player {} ({}) enabled {} (difficulty type {})", player->GetName(), player->GetGUID().ToString(), modeName, difficultyTypeId); } +// 命令启用硬核模式 void HardcoreMode::EnableHardcoreModeForOfflineCharacter(uint32 guid) { HardcoreData data; data.guid = guid; data.status = HC_STATUS_HARDCORE; + data.difficultyTypeId = 1; // 设置默认难度类型为正常 data.enableTime = GameTime::GetGameTime().count(); data.deathTime = 0; data.finalLevel = 0; data.deathCause = ""; data.killerGuid = 0; + data.rewardReceived = false; // 奖励领取初始化 + { std::lock_guard lock(_dataMutex); _hardcoreData[guid] = data; } - SaveHardcoreData(data); - // 新增:直接使用 SQL 查询更新 characters 表的硬核模式字段 - std::string updateQuery = Acore::StringFormat("UPDATE characters SET 硬核模式 = 1 WHERE guid = {}", guid); - CharacterDatabase.Execute(updateQuery); + SaveHardcoreData(data); // 移除 characters 表更新,只保存到角色硬核模式表 - LOG_INFO("hardcore", "Enabled hardcore mode for offline character GUID: {}", guid); + LOG_INFO("server.loading", "Enabled hardcore mode for offline character GUID: {}", guid); } +// 完成硬核模式后移除硬核数据 void HardcoreMode::DisableHardcoreModeForOfflineCharacter(uint32 guid) { HardcoreData data; data.guid = guid; - data.status = HC_STATUS_NORMAL; + data.status = HC_STATUS_COMPLETED; + data.difficultyTypeId = 0; // 设置为0表示正常模式 data.enableTime = 0; data.deathTime = 0; data.finalLevel = 0; data.deathCause = "GM Disabled"; data.killerGuid = 0; + data.rewardReceived = false; + { std::lock_guard lock(_dataMutex); _hardcoreData[guid] = data; } - SaveHardcoreData(data); - // 新增:直接使用 SQL 查询更新 characters 表的硬核模式字段 - std::string updateQuery = Acore::StringFormat("UPDATE characters SET 硬核模式 = 0 WHERE guid = {}", guid); - CharacterDatabase.Execute(updateQuery); + SaveHardcoreData(data); // 移除 characters 表更新,只保存到角色硬核模式表 - LOG_INFO("hardcore", "Disabled hardcore mode for offline character GUID: {}", guid); + LOG_INFO("server.loading", "Disabled hardcore mode for offline character GUID: {}", guid); } +// 设置硬核模式中死亡 void HardcoreMode::SetPlayerDead(Player* player, const std::string& cause, Unit* killer) { if (!player || !IsHardcorePlayer(player)) return; - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - if (it != _hardcoreData.end()) + + HardcoreData dataToSave; { - it->second.status = HC_STATUS_DEAD; - it->second.deathTime = GameTime::GetGameTime().count(); - it->second.finalLevel = player->GetLevel(); - it->second.deathCause = cause; - it->second.killerGuid = killer ? killer->GetGUID().GetCounter() : 0; - SaveHardcoreData(it->second); - } - ChatHandler(player->GetSession()).SendSysMessage("你在硬核模式中死亡了!这是永久的。"); - LOG_INFO("hardcore", "Hardcore player {} ({}) died permanently. Cause: {}, Level: {}", - player->GetName(), player->GetGUID().ToString(), cause, player->GetLevel()); + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(player->GetGUID().GetCounter()); + if (it != _hardcoreData.end()) + { + it->second.status = HC_STATUS_DEAD; + it->second.deathTime = GameTime::GetGameTime().count(); + it->second.finalLevel = player->GetLevel(); + it->second.deathCause = cause; + + // 修改这里:使用 GetSpawnId() 获取数据库中的 guid + if (killer) + { + if (Creature* creature = killer->ToCreature()) + { + it->second.killerGuid = creature->GetSpawnId(); + } + else + { + // 如果击杀者是玩家,仍然使用 GetCounter() + it->second.killerGuid = killer->GetGUID().GetCounter(); + } + } + else + { + it->second.killerGuid = 0; + } + + dataToSave = it->second; // 复制数据 + } + } // 锁在这里自动释放 + + // 现在在锁外调用SaveHardcoreData + SaveHardcoreData(dataToSave); + + ChatHandler(player->GetSession()).SendSysMessage(cause.c_str()); + LOG_INFO("server.loading", "Hardcore player {} ({}) died permanently. Cause: {}, Level: {}", player->GetName(), player->GetGUID().ToString(), cause, player->GetLevel()); } + +// 检查玩家的难度类型是否有永久死亡 +bool HardcoreMode::HasPermanentDeath(Player* player) +{ + if (!player) + return false; + + uint32 difficultyType = GetPlayerDifficultyType(player); + + std::lock_guard typeLock(_typesMutex); + for (const auto& modeType : _hardcoreModeTypes) + { + if (modeType.id == difficultyType) + return modeType.permanentDeath; + } + return false; +} + +// 检查可复活状态,硬核玩家模式下的死亡状态不能复活,已完成的可以正常复活 bool HardcoreMode::CanResurrect(Player* player) { if (!player) return true; + + // 如果不是硬核玩家,可以正常复活 + if (!IsHardcorePlayer(player)) + return true; + HardcoreStatus status = GetHardcoreStatus(player); - return status != HC_STATUS_DEAD; -} -bool HardcoreMode::CanGroupWith(Player* player, Player* target) -{ - if (!player || !target) - return true; - bool playerHardcore = IsHardcorePlayer(player); - bool targetHardcore = IsHardcorePlayer(target); - if (!playerHardcore && !targetHardcore) - return true; - if (playerHardcore != targetHardcore) - return false; - uint8 playerLevel = player->GetLevel(); - uint8 targetLevel = target->GetLevel(); - if ((playerLevel == 60 && targetLevel < 60) || (targetLevel == 60 && playerLevel < 60)) - return false; - return true; + return status != HC_STATUS_DEAD; // 只有死亡状态的硬核玩家不能复活 } +// 加载硬核模式数据 void HardcoreMode::LoadHardcoreData(Player* player) { if (!player) @@ -254,167 +282,15 @@ void HardcoreMode::LoadHardcoreData(Player* player) } } -// 新增:替代操作码的方法 -void HardcoreMode::ToggleHardcoreModeForCharacter(WorldSession* session, const std::string& characterName, bool enable) -{ - std::string escapedName = characterName; - CharacterDatabase.EscapeString(escapedName); - std::string query = Acore::StringFormat( - "SELECT guid, account FROM characters WHERE name = '{}' ", - escapedName - ); - QueryResult result = CharacterDatabase.Query(query); - if (!result) - { - ChatHandler(session).PSendSysMessage("角色 '{}' 不存在或不属于你的账号。", characterName.c_str()); - return; - } - Field* fields = result->Fetch(); - uint32 characterGuid = fields[0].Get(); - if (ObjectAccessor::FindConnectedPlayer(ObjectGuid::Create(characterGuid))) - { - ChatHandler(session).SendSysMessage("无法为在线角色切换硬核模式,请让角色下线后再试。"); - return; - } - if (enable) - { - EnableHardcoreModeForOfflineCharacter(characterGuid); - ChatHandler(session).PSendSysMessage("已为角色 '{}' 启用硬核模式。", characterName.c_str()); - } - else if (session->GetSecurity() >= SEC_GAMEMASTER) - { - DisableHardcoreModeForOfflineCharacter(characterGuid); - ChatHandler(session).PSendSysMessage("已为角色 '{}' 移除硬核模式。", characterName.c_str()); - } - else - { - ChatHandler(session).SendSysMessage("只有GM可以移除硬核模式。"); - } -} - -void HardcoreMode::SendHardcoreStatusToClient(WorldSession* session) -{ - if (!session) - return; - - std::string query = Acore::StringFormat( - "SELECT c.guid, c.name, c.level, COALESCE(h.状态, 0) as hardcore_status " - "FROM characters c " - "LEFT JOIN 角色硬核模式 h ON c.guid = h.角色编号 " - "WHERE c.account = {} ORDER BY c.name", - session->GetAccountId() - ); - - QueryResult result = CharacterDatabase.Query(query); - if (!result) - return; - - std::ostringstream statusMsg; - statusMsg << "|cFFFFD700[硬核模式状态]|r\n"; - - bool hasHardcoreCharacters = false; - - do - { - Field* fields = result->Fetch(); - std::string charName = fields[1].Get(); - uint8 level = fields[2].Get(); - uint8 status = fields[3].Get(); - - if (status > 0) // 只显示有硬核状态的角色 - { - hasHardcoreCharacters = true; - std::string statusText; - switch (status) - { - case 1: statusText = "|cFFFFFF00硬核模式|r"; break; - case 2: statusText = "|cFFFF0000已死亡|r"; break; - default: statusText = "|cFF808080未知|r"; break; - } - - statusMsg << charName << " (等级" << static_cast(level) << "): " << statusText << "\n"; - } - - } while (result->NextRow()); - - if (hasHardcoreCharacters) - { - statusMsg << "\n使用 .hardcore 命令管理硬核模式"; - ChatHandler(session).SendSysMessage(statusMsg.str().c_str()); - } -} - -void HardcoreMode::LoadHardcoreModeTypes() -{ - uint32 oldMSTime = getMSTime(); - - std::lock_guard lock(_typesMutex); - _hardcoreModeTypes.clear(); - - QueryResult result = WorldDatabase.Query("SELECT 编号, 名称, 子标题, 描述, 背景纹理,难度标志图, 奖励宝箱纹理,永久死亡, 经验倍率, 组队限制, 任务限制, 拍卖行限制,奖励ID FROM acore_custom.硬核模式类型 WHERE 启用状态 = 1 ORDER BY 编号"); - if (!result) return; - - uint32 count = 0; - do - { - Field* fields = result->Fetch(); - HardcoreModeType modeType; - - modeType.id = fields[0].Get(); - modeType.name = fields[1].Get(); - modeType.subtitle = fields[2].Get(); - modeType.description = fields[3].Get(); - modeType.backtexture = fields[4].Get(); - modeType.HardcoreLogo = fields[5].Get(); - modeType.RewBoxTexture = fields[6].Get(); // 奖励宝箱纹理 - modeType.permanentDeath = fields[7].Get(); - modeType.expModifier = fields[8].Get(); - modeType.groupRestrictions = fields[9].Get(); - modeType.questRestrictions = fields[10].Get(); - modeType.auctionRestrictions = fields[11].Get(); - modeType.RewID = fields[12].Get(); - - _hardcoreModeTypes.push_back(modeType); - ++count; - - } while (result->NextRow()); - - LOG_INFO("hardcore", ">> Loaded {} hardcore mode types in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); -} - -std::string HardcoreMode::GetHardcoreModeTypesData() -{ - std::lock_guard lock(_typesMutex); - std::ostringstream modeData; - - for (size_t i = 0; i < _hardcoreModeTypes.size(); ++i) - { - const auto& modeType = _hardcoreModeTypes[i]; - - if (i > 0) - modeData << "^"; - - modeData - << modeType.id << ":" // 0 编号 - << modeType.name << ":" // 1 名称 - << modeType.subtitle << ":" // 2 子标题 - << modeType.description << ":" // 3 描述 - << modeType.backtexture << ":" // 4 背景纹理 - << modeType.HardcoreLogo << ":" // 5 难度标志图 - << (modeType.RewBoxTexture.empty() ? "无" : modeType.RewBoxTexture) << ":" // 6 奖励宝箱纹理 如果没有设置就设置为"无",要不然客户端截取数据有问题 - << (modeType.permanentDeath ? 1 : 0) << ":" // 7 是否永久死亡 - << modeType.expModifier << ":" // 8 经验倍率 - << (modeType.groupRestrictions ? 1 : 0) << ":" // 9 组队限制 - << (modeType.questRestrictions ? 1 : 0) << ":" // 10 任务限制 - << (modeType.auctionRestrictions ? 1 : 0) << ":" // 11 拍卖行限制 - << modeType.RewID; // 12 奖励ID 关联【_模板_奖励】表 - } - return modeData.str(); -} - +// 保存硬核模式数据 void HardcoreMode::SaveHardcoreData(const HardcoreData& data) { + // 保存到数据库 HardcoreDatabase::instance()->SaveHardcoreData(data); + + // 同时更新内存缓存 + std::lock_guard lock(_dataMutex); + _hardcoreData[data.guid] = data; } // 当玩家选择特定难度时,需要将难度类型ID存储到玩家的硬核数据中 @@ -424,35 +300,35 @@ void HardcoreMode::SetPlayerDifficultyType(Player* player, uint32 difficultyType return; uint32 playerGuid = player->GetGUID().GetCounter(); + HardcoreData dataToSave; - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(playerGuid); - - if (it != _hardcoreData.end()) { - // 更新现有数据 - it->second.difficultyTypeId = difficultyTypeId; - it->second.status = HC_STATUS_HARDCORE; // 设置为硬核状态 - SaveHardcoreData(it->second); - } - else - { - // 创建新的硬核数据 - HardcoreData data; - data.guid = playerGuid; - data.status = HC_STATUS_HARDCORE; - data.difficultyTypeId = difficultyTypeId; - data.enableTime = time(nullptr); - data.deathTime = 0; - data.finalLevel = 0; - data.deathCause = ""; - data.killerGuid = 0; + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(playerGuid); + if (it != _hardcoreData.end()) + { + it->second.difficultyTypeId = difficultyTypeId; + it->second.status = HC_STATUS_HARDCORE; + dataToSave = it->second; // 复制数据 + } + else + { + dataToSave.guid = playerGuid; + dataToSave.status = HC_STATUS_HARDCORE; + dataToSave.difficultyTypeId = difficultyTypeId; + dataToSave.enableTime = time(nullptr); + dataToSave.deathTime = 0; + dataToSave.finalLevel = 0; + dataToSave.deathCause = ""; + dataToSave.killerGuid = 0; + _hardcoreData[playerGuid] = dataToSave; + } + } // 锁在这里释放 - _hardcoreData[playerGuid] = data; - SaveHardcoreData(data); - } + // 在锁外调用 + SaveHardcoreData(dataToSave); - LOG_INFO("hardcore", "Player {} set to difficulty type {}", player->GetName(), difficultyTypeId); + LOG_INFO("server.loading", "Player {} set to difficulty type {}", player->GetName(), difficultyTypeId); } // 获取难度类型信息 @@ -510,72 +386,166 @@ uint32 HardcoreMode::GetPlayerDifficultyType(Player* player) return it != _hardcoreData.end() ? it->second.difficultyTypeId : 0; } -void HardcorePlayerScript::OnPlayerFirstLogin(Player* player) +// 切换角色的硬核模式 +void HardcoreMode::ToggleHardcoreModeForCharacter(WorldSession* session, const std::string& characterName, bool enable) { - if (!player) + std::string escapedName = characterName; + CharacterDatabase.EscapeString(escapedName); + std::string query = Acore::StringFormat( + "SELECT guid, account FROM characters WHERE name = '{}' ", + escapedName + ); + QueryResult result = CharacterDatabase.Query(query); + if (!result) + { + ChatHandler(session).PSendSysMessage("角色 '{}' 不存在或不属于你的账号。", characterName.c_str()); return; - - // 检查玩家是否已经选择过难度 - if (sHardcoreMode->GetHardcoreStatus(player) != HC_STATUS_NORMAL) + } + Field* fields = result->Fetch(); + uint32 characterGuid = fields[0].Get(); + if (ObjectAccessor::FindConnectedPlayer(ObjectGuid::Create(characterGuid))) + { + ChatHandler(session).SendSysMessage("无法为在线角色切换硬核模式,请让角色下线后再试。"); return; - - // 发送硬核模式数据 - std::string modeData = sHardcoreMode->GetHardcoreModeTypesData(); - - // 发送硬核模式类型数据 - sGCAddon->SendPacketTo(player, "SM_S_GETHARDCOREMODE", modeData); - - // 立即发送一次主按钮触发包 - sGCAddon->SendPacketTo(player, "SM_S_SHOWHARDCOREBUTTON", ""); - - // 启动60秒定时器 - StartHardcoreReminder(player); + } + if (enable) + { + EnableHardcoreModeForOfflineCharacter(characterGuid); + ChatHandler(session).PSendSysMessage("已为角色 '{}' 启用硬核模式。", characterName.c_str()); + } + else if (session->GetSecurity() >= SEC_GAMEMASTER) + { + DisableHardcoreModeForOfflineCharacter(characterGuid); + ChatHandler(session).PSendSysMessage("已为角色 '{}' 移除硬核模式。", characterName.c_str()); + } + else + { + ChatHandler(session).SendSysMessage("只有GM可以移除硬核模式。"); + } } -// 脚本实现 -void HardcorePlayerScript::OnPlayerLogin(Player* player) +// 发送硬核状态 +void HardcoreMode::SendHardcoreStatusToClient(WorldSession* session) { - sHardcoreMode->LoadHardcoreData(player); + if (!session) + return; - // 处理硬核模式中已死亡的玩家 - if (sHardcoreMode->GetHardcoreStatus(player) == HC_STATUS_DEAD) + std::string query = Acore::StringFormat( + "SELECT c.guid, c.name, c.level, COALESCE(h.状态, 0) as hardcore_status " + "FROM characters c " + "LEFT JOIN 角色硬核模式 h ON c.guid = h.角色编号 " + "WHERE c.account = {} ORDER BY c.name", + session->GetAccountId() + ); + + QueryResult result = CharacterDatabase.Query(query); + if (!result) + return; + + std::ostringstream statusMsg; + statusMsg << "|cFFFFD700[硬核模式状态]|r\n"; + + bool hasHardcoreCharacters = false; + + do { - if (player->IsAlive()) + Field* fields = result->Fetch(); + std::string charName = fields[1].Get(); + uint8 level = fields[2].Get(); + uint8 status = fields[3].Get(); + + if (status > 0) // 只显示有硬核状态的角色 { - player->KillPlayer(); - player->BuildPlayerRepop(); + hasHardcoreCharacters = true; + std::string statusText; + switch (status) + { + case 1: statusText = "|cFFFFFF00硬核模式|r"; break; + case 2: statusText = "|cFFFF0000已死亡|r"; break; + case 3: statusText = "|cFFFF0000已完成硬核模式挑战|r"; break; + default: statusText = "|cFF808080未知|r"; break; + } + + statusMsg << charName << " (等级" << static_cast(level) << "): " << statusText << "\n"; } - } - // 检查是否需要发送硬核模式选择提醒(包括非首次登录) - if (sHardcoreMode->GetHardcoreStatus(player) == HC_STATUS_NORMAL) + } while (result->NextRow()); + + if (hasHardcoreCharacters) { - ChatHandler(player->GetSession()).SendSysMessage("请选择游戏难度,否则将在90秒后踢出游戏。"); - - // 发送硬核模式数据 - std::string modeData = sHardcoreMode->GetHardcoreModeTypesData(); - - // 发送硬核模式类型数据 - sGCAddon->SendPacketTo(player, "SM_S_GETHARDCOREMODE", modeData); - - // 立即发送一次主按钮触发包 - sGCAddon->SendPacketTo(player, "SM_S_SHOWHARDCOREBUTTON", ""); - - // 启动60秒定时器 - StartHardcoreReminder(player); + statusMsg << "\n使用 .hardcore 命令管理硬核模式"; + ChatHandler(session).SendSysMessage(statusMsg.str().c_str()); } } -// 设置玩家限制状态 -void HardcorePlayerScript::ApplyHardcoreRestrictions(Player* player) +// 加载[硬核模式类型]表数据 +void HardcoreMode::LoadHardcoreModeTypes() { - player->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, SEC_GAMEMASTER); // 设置玩家为GM级别的幽灵可见性 - 让玩家只对GM可见,普通玩家看不到 - player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); // 和平化状态 - 禁用玩家的近战攻击能力,无法进行物理攻击 - player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED); // 沉默状态 - 禁用玩家的法术施放能力,无法使用任何法术 - player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); // 眩晕状态 - 完全控制玩家,无法移动、攻击或施法 - player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); // 混乱状态 - 玩家失去控制,随机移动和行动 - player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED); // 缴械状态 - 禁用玩家的武器攻击,无法使用需要武器的技能 - player->SetMovement(MOVE_ROOT); // 禁用移动 + uint32 oldMSTime = getMSTime(); + + std::lock_guard lock(_typesMutex); + _hardcoreModeTypes.clear(); + + QueryResult result = WorldDatabase.Query("SELECT 编号, 名称, 子标题, 描述, 背景纹理,难度标志图, 奖励宝箱纹理,永久死亡, 经验倍率, 组队限制, 任务限制, 拍卖行限制,奖励ID FROM acore_custom.硬核模式类型 WHERE 启用状态 = 1 ORDER BY 编号"); + if (!result) return; + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + HardcoreModeType modeType; + + modeType.id = fields[0].Get(); + modeType.name = fields[1].Get(); + modeType.subtitle = fields[2].Get(); + modeType.description = fields[3].Get(); + modeType.backtexture = fields[4].Get(); + modeType.HardcoreLogo = fields[5].Get(); + modeType.RewBoxTexture = fields[6].Get(); // 奖励宝箱纹理 + modeType.permanentDeath = fields[7].Get(); + modeType.expModifier = fields[8].Get(); + modeType.groupRestrictions = fields[9].Get(); + modeType.questRestrictions = fields[10].Get(); + modeType.auctionRestrictions = fields[11].Get(); + modeType.RewID = fields[12].Get(); + + _hardcoreModeTypes.push_back(modeType); + ++count; + + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} hardcore mode types in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +// 获取硬核模式数据 +std::string HardcoreMode::GetHardcoreModeTypesData() +{ + std::lock_guard lock(_typesMutex); + std::ostringstream modeData; + + for (size_t i = 0; i < _hardcoreModeTypes.size(); ++i) + { + const auto& modeType = _hardcoreModeTypes[i]; + + if (i > 0) + modeData << "^"; + + modeData + << modeType.id << ":" // 0 编号 + << modeType.name << ":" // 1 名称 + << modeType.subtitle << ":" // 2 子标题 + << modeType.description << ":" // 3 描述 + << modeType.backtexture << ":" // 4 背景纹理 + << modeType.HardcoreLogo << ":" // 5 难度标志图 + << (modeType.RewBoxTexture.empty() ? "无" : modeType.RewBoxTexture) << ":" // 6 奖励宝箱纹理 如果没有设置就设置为"无",要不然客户端截取数据有问题 + << (modeType.permanentDeath ? 1 : 0) << ":" // 7 是否永久死亡 + << modeType.expModifier << ":" // 8 经验倍率 + << (modeType.groupRestrictions ? 1 : 0) << ":" // 9 组队限制 + << (modeType.questRestrictions ? 1 : 0) << ":" // 10 任务限制 + << (modeType.auctionRestrictions ? 1 : 0) << ":" // 11 拍卖行限制 + << modeType.RewID; // 12 奖励ID 关联【_模板_奖励】表 + } + return modeData.str(); } // 解除玩家限制状态 @@ -598,6 +568,593 @@ void HardcoreMode::RemoveHardcoreRestrictions(Player* player) player->UpdateObjectVisibility(); } +// 检查是否有组队限制 +bool HardcoreMode::ShouldApplyGroupRestriction(Player* player) +{ + if (!player) + return false; + + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(player->GetGUID().GetCounter()); + if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) + return false; + + std::lock_guard typeLock(_typesMutex); + for (const auto& modeType : _hardcoreModeTypes) + { + if (modeType.id == it->second.difficultyTypeId) + return modeType.groupRestrictions > 0; // 改为检查是否大于0 + } + return false; +} + +// 检查是否设置任务限制 +bool HardcoreMode::ShouldApplyQuestRestriction(Player* player) +{ + if (!player) + return false; + + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(player->GetGUID().GetCounter()); + if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) + return false; + + std::lock_guard typeLock(_typesMutex); + for (const auto& modeType : _hardcoreModeTypes) + { + if (modeType.id == it->second.difficultyTypeId) + return modeType.questRestrictions; + } + return false; +} + +// 检查是否设置拍卖行限制 +bool HardcoreMode::ShouldApplyAuctionRestriction(Player* player) +{ + if (!player) + return false; + + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(player->GetGUID().GetCounter()); + if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) + return false; + + std::lock_guard typeLock(_typesMutex); + for (const auto& modeType : _hardcoreModeTypes) + { + if (modeType.id == it->second.difficultyTypeId) + return modeType.auctionRestrictions; + } + return false; +} + +// 获取经验设置的倍率 +float HardcoreMode::GetExpModifier(Player* player) +{ + if (!player) + return 1.0f; + + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(player->GetGUID().GetCounter()); + if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) + return 1.0f; + + std::lock_guard typeLock(_typesMutex); + for (const auto& modeType : _hardcoreModeTypes) + { + if (modeType.id == it->second.difficultyTypeId) + return modeType.expModifier; + } + return 1.0f; +} + +// 检查两个玩家是否可以组队 +bool HardcoreMode::CanGroupWithPlayer(Player* inviter, Player* invitee) +{ + if (!inviter || !invitee) + return true; + + // 获取邀请者的组队限制类型 + uint32 inviterRestriction = GetGroupRestrictionType(inviter); + uint32 inviteeRestriction = GetGroupRestrictionType(invitee); + + // 如果邀请者无限制,可以邀请任何人 + if (inviterRestriction == 0) + return true; + + // 根据限制类型判断 + switch (inviterRestriction) + { + case 1: // 完全禁止组队 + return false; + + case 2: // 同难度且近等级组队 + { + // 检查难度是否相同 + uint32 inviterDifficulty = GetPlayerDifficultyType(inviter); + uint32 inviteeDifficulty = GetPlayerDifficultyType(invitee); + if (inviterDifficulty != inviteeDifficulty) + return false; + + // 检查等级差距 + uint8 levelDiff = abs(inviter->GetLevel() - invitee->GetLevel()); + return levelDiff <= 5; + } + + case 3: // 同难度组队 + { + uint32 inviterDifficulty = GetPlayerDifficultyType(inviter); + uint32 inviteeDifficulty = GetPlayerDifficultyType(invitee); + return inviterDifficulty == inviteeDifficulty; + } + + default: + return true; + } +} + +// 获取玩家的组队限制类型 +uint32 HardcoreMode::GetGroupRestrictionType(Player* player) +{ + if (!player) + return 0; + + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(player->GetGUID().GetCounter()); + if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) + return 0; + + std::lock_guard typeLock(_typesMutex); + for (const auto& modeType : _hardcoreModeTypes) + { + if (modeType.id == it->second.difficultyTypeId) + return modeType.groupRestrictions; // 组队限制类型 + } + return 0; +} + +// 处理完成硬核模式 +void HardcoreMode::GiveHardcoreReward(Player* player) +{ + uint32 difficultyType = GetPlayerDifficultyType(player); + if (difficultyType == 1) // 正常模式不给奖励 + return; + + // 检查是否已经发放过奖励 + if (HasReceivedHardcoreReward(player)) + return; + + std::lock_guard typeLock(_typesMutex); + for (const auto& modeType : _hardcoreModeTypes) + { + if (modeType.id == difficultyType) + { + sRew->Rew(player, modeType.RewID); // 发放奖励 + MarkHardcoreRewardAsGiven(player); // 记录已发放奖励 + SetPlayerHardcoreCompleted(player->GetGUID().GetCounter()); // 设置为已完成状态 + RemoveHardcoreRestrictions(player);// 解除玩家限制状态 + ChatHandler(player->GetSession()).PSendSysMessage("恭喜!你完成了{}难度挑战,获得专属奖励!硬核模式已完成,现在可以正常游戏了。", modeType.name.c_str()); + break; + } + } +} + +// 检查是否已获得过奖励 +bool HardcoreMode::HasReceivedHardcoreReward(Player* player) +{ + // 检查数据库或内存中是否已记录该玩家获得过奖励 + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(player->GetGUID().GetCounter()); + if (it != _hardcoreData.end()) + return it->second.rewardReceived; + + return false; +} + +// 记录已发放奖励 +void HardcoreMode::MarkHardcoreRewardAsGiven(Player* player) +{ + HardcoreData dataToSave; + { + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(player->GetGUID().GetCounter()); + if (it != _hardcoreData.end()) + { + it->second.rewardReceived = true; + dataToSave = it->second; + } + } // 锁在这里释放 + + // 锁外调用SaveHardcoreData + SaveHardcoreData(dataToSave); +} + +// 完成状态设置 +void HardcoreMode::SetPlayerHardcoreCompleted(uint32 guid) +{ + HardcoreData dataToSave; + { + std::lock_guard lock(_dataMutex); + auto it = _hardcoreData.find(guid); + if (it != _hardcoreData.end()) + { + it->second.status = HC_STATUS_COMPLETED; + dataToSave = it->second; + } + else + { + // 如果内存中没有,从数据库加载 + if (HardcoreDatabase::instance()->LoadHardcoreData(guid, dataToSave)) + { + dataToSave.status = HC_STATUS_COMPLETED; + _hardcoreData[guid] = dataToSave; + } + } + } + SaveHardcoreData(dataToSave); // 移除 characters 表更新,只保存到角色硬核模式表 +} + + +//////////////////////////// HardcorePlayerScript //////////////////////////// +// 当玩家首次登陆时 +void HardcorePlayerScript::OnPlayerFirstLogin(Player* player){} + +// 当玩家登陆时 +void HardcorePlayerScript::OnPlayerLogin(Player* player) +{ + sHardcoreMode->LoadHardcoreData(player); + + // 处理硬核模式中已死亡的玩家 + if (sHardcoreMode->GetHardcoreStatus(player) == HC_STATUS_DEAD) + { + if (player->IsAlive()) + { + player->KillPlayer(); + player->BuildPlayerRepop(); + } + } + + // 只有从未选择过硬核模式的玩家才显示选择界面 + if (sHardcoreMode->GetHardcoreStatus(player) == HC_STATUS_NORMAL && sHardcoreMode->GetPlayerDifficultyType(player) == 0) + { + ChatHandler(player->GetSession()).SendSysMessage("请选择游戏难度,否则将在90秒后踢出游戏。"); + std::string modeData = sHardcoreMode->GetHardcoreModeTypesData(); // 获取硬核模式数据 + sGCAddon->SendPacketTo(player, "SM_S_GETHARDCOREMODE", modeData); // 发送硬核模式类型数据 + sGCAddon->SendPacketTo(player, "SM_S_SHOWHARDCOREBUTTON", ""); // 立即发送一次主按钮触发包 + StartHardcoreReminder(player); // 启动60秒定时器 + } +} + +// 当玩家退出游戏时 +void HardcorePlayerScript::OnPlayerLogout(Player* player) +{ +} + +// 当玩家复活时调用 +bool HardcorePlayerScript::OnPlayerCanResurrect(Player* player) +{ + return sHardcoreMode->CanResurrect(player); +} + +// 玩家刚刚死亡时 +void HardcorePlayerScript::OnPlayerJustDied(Player* player) +{ + if (!sHardcoreMode->IsHardcorePlayer(player)) + return; + + if (!sHardcoreMode->HasPermanentDeath(player)) + return; + + // 检查是否已经被其他钩子处理过 + uint32 playerGuid = player->GetGUID().GetCounter(); + if (_processedDeaths.count(playerGuid)) + { + _processedDeaths.erase(playerGuid); // 清理标记 + return; + } + + // 只处理环境死亡,PvP和生物击杀由专门的钩子处理 + std::string deathMessage = GetEnvironmentalDeathMessage(player); + sHardcoreMode->SetPlayerDead(player, deathMessage, nullptr); +} + +void HardcorePlayerScript::OnPlayerPVPKill(Player* killer, Player* killed) +{ + if (!sHardcoreMode->IsHardcorePlayer(killed)) + return; + + if (!sHardcoreMode->HasPermanentDeath(killed)) + return; + + // 标记为已处理 + _processedDeaths.insert(killed->GetGUID().GetCounter()); + + std::string deathMessage = FormatPvPDeathMessage(killer, killed); + sHardcoreMode->SetPlayerDead(killed, deathMessage, killer); +} + +void HardcorePlayerScript::OnPlayerKilledByCreature(Creature* killer, Player* killed) +{ + if (!sHardcoreMode->IsHardcorePlayer(killed)) + return; + + if (!sHardcoreMode->HasPermanentDeath(killed)) + return; + + // 标记为已处理 + _processedDeaths.insert(killed->GetGUID().GetCounter()); + + std::string deathMessage = FormatCreatureDeathMessage(killer, killed); + sHardcoreMode->SetPlayerDead(killed, deathMessage, killer); +} + +// 玩家释放灵魂变成幽灵时 +void HardcorePlayerScript::OnPlayerReleasedGhost(Player* player) +{ + if (sHardcoreMode->GetHardcoreStatus(player) == HC_STATUS_DEAD) + { + ChatHandler(player->GetSession()).SendSysMessage("你已在硬核模式中死亡,无法复活。"); + } +} + +// 玩家每次更新时 +void HardcorePlayerScript::OnPlayerUpdate(Player* player, uint32 p_time) +{ + // 对于已选择难度的玩家直接返回,减少性能开销 + if (sHardcoreMode->GetHardcoreStatus(player) != HC_STATUS_NORMAL && + _reminderPlayers.find(player->GetGUID().GetCounter()) == _reminderPlayers.end()) + { + return; + } + + // 更新硬核模式的调度器 + _scheduler.Update(p_time); + + // 轻量级检查:只在状态不一致时重新应用限制 + if (sHardcoreMode->GetHardcoreStatus(player) == HC_STATUS_NORMAL && !player->HasUnitFlag(UNIT_FLAG_STUNNED)) // 检查限制是否已失效 + { + ApplyHardcoreRestrictions(player); + } +} + +// 玩家尝试邀请他人组队前 +bool HardcorePlayerScript::OnPlayerCanGroupInvite(Player* player, std::string& membername) +{ + Player* invitee = ObjectAccessor::FindPlayerByName(membername, false); + if (!invitee) + return true; + + // 获取双方的模式信息 + std::string inviterMode = sHardcoreMode->GetPlayerModeName(player); + std::string inviteeMode = sHardcoreMode->GetPlayerModeName(invitee); + + // 双向检查:检查邀请者是否能邀请被邀请者 + bool inviterCanInvite = sHardcoreMode->CanGroupWithPlayer(player, invitee); + // 同时检查被邀请者是否能接受邀请者的邀请 + bool inviteeCanAccept = sHardcoreMode->CanGroupWithPlayer(invitee, player); + + // 如果任何一方不能组队,就阻止邀请 + if (!inviterCanInvite || !inviteeCanAccept) + { + // 给邀请者发送提示 + uint32 inviterRestriction = sHardcoreMode->GetGroupRestrictionType(player); + uint32 inviteeRestriction = sHardcoreMode->GetGroupRestrictionType(invitee); + + if (inviterRestriction == 1) // 邀请者完全禁止组队 + { + ChatHandler(player->GetSession()).PSendSysMessage("{} 禁止组队", inviterMode.c_str()); + } + else if (inviteeRestriction == 1) // 被邀请者完全禁止组队 + { + ChatHandler(player->GetSession()).PSendSysMessage("目标玩家{} 禁止组队", inviteeMode.c_str()); + } + else if (inviterRestriction == 2 || inviteeRestriction == 2) // 检查是否是等级差异问题 + { + uint32 inviterDifficulty = sHardcoreMode->GetPlayerDifficultyType(player); + uint32 inviteeDifficulty = sHardcoreMode->GetPlayerDifficultyType(invitee); + + if (inviterDifficulty == inviteeDifficulty) + { + // 同难度但等级差异过大 + uint8 levelDiff = abs(player->GetLevel() - invitee->GetLevel()); + if (levelDiff > 5) + { + ChatHandler(player->GetSession()).PSendSysMessage( + "{}模式限制:等级差异过大({}级),只能与等级相近(±5级)的玩家组队", + inviterMode.c_str(), levelDiff); + + ChatHandler(invitee->GetSession()).PSendSysMessage( + "{}玩家 {} 尝试邀请你组队,但等级差异过大({}级),无法组队", + inviterMode.c_str(), player->GetName().c_str(), levelDiff); + + return false; + } + } + } + else // 其他限制情况 + { + ChatHandler(player->GetSession()).PSendSysMessage("无法与 {} 玩家组队,模式限制", inviteeMode.c_str()); + } + + // 给被邀请者发送提示 + ChatHandler(invitee->GetSession()).PSendSysMessage("{} 玩家【{}】尝试邀请你组队,但因为模式限制无法组队", + inviterMode.c_str(), player->GetName().c_str()); + + return false; // 阻止邀请发送 + } + + return true; +} + +// 玩家接受组队邀请前 +bool HardcorePlayerScript::OnPlayerCanGroupAccept(Player* player, Group* group) +{ + Player* leader = ObjectAccessor::FindConnectedPlayer(group->GetLeaderGUID()); + if (!leader) + return true; + + // 检查双方是否有组队限制 + bool playerHasRestriction = sHardcoreMode->ShouldApplyGroupRestriction(player); + bool leaderHasRestriction = sHardcoreMode->ShouldApplyGroupRestriction(leader); + + // 如果双方都没有限制,直接允许 + if (!playerHasRestriction && !leaderHasRestriction) + return true; + + // 双向检查组队限制 + bool canGroup = sHardcoreMode->CanGroupWithPlayer(leader, player) && + sHardcoreMode->CanGroupWithPlayer(player, leader); + + if (!canGroup) + { + // 获取双方的模式名称 + std::string playerMode = sHardcoreMode->GetPlayerModeName(player); + std::string leaderMode = sHardcoreMode->GetPlayerModeName(leader); + + // 给接受者发送提示 - 解决问题1 + uint32 playerRestriction = sHardcoreMode->GetGroupRestrictionType(player); + if (playerRestriction == 1) // 完全禁止组队 + { + ChatHandler(player->GetSession()).PSendSysMessage("{} 禁止组队", playerMode.c_str()); + } + else if (playerRestriction == 2) // 同难度近等级 + { + ChatHandler(player->GetSession()).PSendSysMessage("{} 只能与同难度且等级相近的玩家组队,邀请者当前为{}", + playerMode.c_str(), leaderMode.c_str()); + } + + // 给邀请者(组长)发送提示 + ChatHandler(leader->GetSession()).PSendSysMessage("{} 玩家 {} 无法接受组队邀请,因为模式限制", + playerMode.c_str(), player->GetName().c_str()); + + return false; + } + + return true; +} + +// 玩家竞拍拍卖行物品前 +bool HardcorePlayerScript::OnPlayerCanPlaceAuctionBid(Player* player, AuctionEntry* auction) +{ + if (sHardcoreMode->ShouldApplyAuctionRestriction(player)) + { + ChatHandler(player->GetSession()).SendSysMessage("硬核模式限制:无法使用拍卖行"); + return false; + } + return true; +} + +// 玩家完成任务准备交任务前 +bool HardcorePlayerScript::OnPlayerBeforeQuestComplete(Player* player, uint32 quest_id) +{ + if (sHardcoreMode->ShouldApplyQuestRestriction(player)) + { + ChatHandler(player->GetSession()).SendSysMessage("硬核模式限制:无法完成任务"); + return false; + } + return true; +} + +// 玩家获得经验时调用 +void HardcorePlayerScript::OnPlayerGiveXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource) +{ + float modifier = sHardcoreMode->GetExpModifier(player); + if (modifier != 1.0f) + { + amount = static_cast(amount * modifier); + } +} + +// 玩家等级发生变化后调用 +void HardcorePlayerScript::OnPlayerLevelChanged(Player* player, uint8 oldLevel) +{ + // 检查是否刚达到满级 + if (player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) && oldLevel < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + sHardcoreMode->GiveHardcoreReward(player); + } + + // 检查组队限制 + CheckGroupLevelRestrictions(player); +} + +// 检查组队限制 +void HardcorePlayerScript::CheckGroupLevelRestrictions(Player* player) +{ + Group* group = player->GetGroup(); + if (!group) + return; + + uint32 playerRestriction = sHardcoreMode->GetGroupRestrictionType(player); + if (playerRestriction != 2) // 只处理"同难度且近等级"限制 + return; + + uint32 playerDifficulty = sHardcoreMode->GetPlayerDifficultyType(player); + uint8 playerLevel = player->GetLevel(); + + // 检查所有组员 + std::vector playersToKick; + + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + { + Player* member = itr->GetSource(); + if (!member || member == player) + continue; + + uint32 memberDifficulty = sHardcoreMode->GetPlayerDifficultyType(member); + uint32 memberRestriction = sHardcoreMode->GetGroupRestrictionType(member); + + // 检查是否同难度且有等级限制 + if (memberRestriction == 2 && memberDifficulty == playerDifficulty) + { + uint8 levelDiff = abs(playerLevel - member->GetLevel()); + if (levelDiff > 5) + { + // 决定踢出等级较高的玩家 + if (playerLevel > member->GetLevel()) + { + playersToKick.push_back(player); + } + else + { + playersToKick.push_back(member); + } + } + } + } + + // 踢出违反限制的玩家 + for (Player* kickPlayer : playersToKick) + { + // 获取双方的模式名称 + std::string playerMode = sHardcoreMode->GetPlayerModeName(player); + std::string leaderMode = sHardcoreMode->GetPlayerModeName(kickPlayer); + + ChatHandler(kickPlayer->GetSession()).PSendSysMessage("{} 由于等级差异超过限制,你被移出队伍", leaderMode); + + // 通知其他队员 + std::string kickMessage = playerMode + " 玩家 " + kickPlayer->GetName() + " 因等级差异过大被移出队伍"; + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, kickMessage); + group->BroadcastPacket(&data, false, -1, kickPlayer->GetGUID()); + + group->RemoveMember(kickPlayer->GetGUID()); + } +} + +// 设置玩家限制状态 +void HardcorePlayerScript::ApplyHardcoreRestrictions(Player* player) +{ + player->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, SEC_GAMEMASTER); // 设置玩家为GM级别的幽灵可见性 - 让玩家只对GM可见,普通玩家看不到 + player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); // 和平化状态 - 禁用玩家的近战攻击能力,无法进行物理攻击 + player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED); // 沉默状态 - 禁用玩家的法术施放能力,无法使用任何法术 + player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); // 眩晕状态 - 完全控制玩家,无法移动、攻击或施法 + player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); // 混乱状态 - 玩家失去控制,随机移动和行动 + player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED); // 缴械状态 - 禁用玩家的武器攻击,无法使用需要武器的技能 + player->SetMovement(MOVE_ROOT); // 禁用移动 +} + +// 启动定时器 void HardcorePlayerScript::StartHardcoreReminder(Player* player) { uint32 playerGuid = player->GetGUID().GetCounter(); @@ -657,287 +1214,139 @@ void HardcorePlayerScript::StartHardcoreReminder(Player* player) }); } -void HardcorePlayerScript::OnPlayerLogout(Player* player) +std::string HardcorePlayerScript::GetMapName(Player* player) { -} + Map* map = player->GetMap(); + if (!map) + return "未知地图"; -bool HardcorePlayerScript::OnPlayerCanResurrect(Player* player) -{ - return sHardcoreMode->CanResurrect(player); -} - -void HardcorePlayerScript::OnPlayerJustDied(Player* player) -{ - if (sHardcoreMode->IsHardcorePlayer(player)) + // 获取地图信息 + MapEntry const* mapEntry = sMapStore.LookupEntry(player->GetMapId()); + if (mapEntry) { - std::string deathCause = "Unknown"; - Unit* killer = nullptr; // 需要通过其他方式获取killer信息 - sHardcoreMode->SetPlayerDead(player, deathCause, killer); + int locale = player->GetSession()->GetSessionDbcLocale(); + return mapEntry->name[locale]; // 使用DBC中的地图名称 + } + + return "地图ID:" + std::to_string(player->GetMapId()); +} + +std::string HardcorePlayerScript::GetAreaName(Player* player) +{ + uint32 areaId = player->GetAreaId(); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId); + if (areaEntry) + { + int locale = player->GetSession()->GetSessionDbcLocale(); + return areaEntry->area_name[locale]; // 使用DBC中的区域名称 + } + + return "区域ID:" + std::to_string(areaId); +} + +std::string HardcorePlayerScript::GetCreatureRankName(uint32 rank) +{ + switch (rank) + { + case CREATURE_ELITE_NORMAL: return "普通"; + case CREATURE_ELITE_ELITE: return "精英"; + case CREATURE_ELITE_RAREELITE: return "稀有精英"; + case CREATURE_ELITE_WORLDBOSS: return "首领"; + case CREATURE_ELITE_RARE: return "稀有"; + default: return "未知"; } } -void HardcorePlayerScript::OnPlayerReleasedGhost(Player* player) +std::string HardcorePlayerScript::FormatPosition(float x, float y, float z) { - if (sHardcoreMode->GetHardcoreStatus(player) == HC_STATUS_DEAD) - { - ChatHandler(player->GetSession()).SendSysMessage("你已在硬核模式中死亡,无法复活。"); - } + return "(" + std::to_string((int)x) + ", " + std::to_string((int)y) + ", " + std::to_string((int)z) + ")"; } -void HardcorePlayerScript::OnPlayerUpdate(Player* player, uint32 p_time) +std::string HardcorePlayerScript::FormatPvPDeathMessage(Player* killer, Player* killed) { - // 对于已选择难度的玩家直接返回,减少性能开销 - if (sHardcoreMode->GetHardcoreStatus(player) != HC_STATUS_NORMAL && - _reminderPlayers.find(player->GetGUID().GetCounter()) == _reminderPlayers.end()) - { - return; - } + std::string mapName = GetMapName(killed); + std::string areaName = GetAreaName(killed); + std::string position = FormatPosition(killed->GetPositionX(), killed->GetPositionY(), killed->GetPositionZ()); - // 更新硬核模式的调度器 - _scheduler.Update(p_time); - - // 轻量级检查:只在状态不一致时重新应用限制 - if (sHardcoreMode->GetHardcoreStatus(player) == HC_STATUS_NORMAL && - !player->HasUnitFlag(UNIT_FLAG_STUNNED)) // 检查限制是否已失效 - { - ApplyHardcoreRestrictions(player); - } + return "在地图[" + mapName + "]的[" + areaName + "],位置" + position + ",被玩家[" + killer->GetName() + "]击杀"; } -bool HardcorePlayerScript::OnPlayerCanGroupInvite(Player* player, std::string& membername) +std::string HardcorePlayerScript::FormatCreatureDeathMessage(Creature* killer, Player* killed) { - Player* invitee = ObjectAccessor::FindPlayerByName(membername, false); - if (!invitee) - return true; + std::string mapName = GetMapName(killed); + std::string areaName = GetAreaName(killed); + std::string position = FormatPosition(killed->GetPositionX(), killed->GetPositionY(), killed->GetPositionZ()); + std::string rankName = GetCreatureRankName(killer->GetCreatureTemplate()->rank); - // 获取双方的模式信息 - std::string inviterMode = sHardcoreMode->GetPlayerModeName(player); - std::string inviteeMode = sHardcoreMode->GetPlayerModeName(invitee); + return "在地图[" + mapName + "]的[" + areaName + "],位置" + position + ",被" + rankName + "生物[" + + killer->GetName() + "]击杀,生物ID:" + std::to_string(killer->GetEntry()); +} - // 双向检查:检查邀请者是否能邀请被邀请者 - bool inviterCanInvite = sHardcoreMode->CanGroupWithPlayer(player, invitee); - // 同时检查被邀请者是否能接受邀请者的邀请 - bool inviteeCanAccept = sHardcoreMode->CanGroupWithPlayer(invitee, player); +std::string HardcorePlayerScript::GetEnvironmentalDeathMessage(Player* player) +{ + std::string mapName = GetMapName(player); + std::string areaName = GetAreaName(player); + std::string position = FormatPosition(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); - // 如果任何一方不能组队,就阻止邀请 - if (!inviterCanInvite || !inviteeCanAccept) + // 检查液体环境死亡 + LiquidData const& liquidData = player->GetLiquidData(); + if (liquidData.Status != LIQUID_MAP_NO_WATER) { - // 给邀请者发送提示 - uint32 inviterRestriction = sHardcoreMode->GetGroupRestrictionType(player); - uint32 inviteeRestriction = sHardcoreMode->GetGroupRestrictionType(invitee); - - if (inviterRestriction == 1) // 邀请者完全禁止组队 + if (liquidData.Flags & MAP_LIQUID_TYPE_MAGMA) { - ChatHandler(player->GetSession()).PSendSysMessage("{} 禁止组队", inviterMode.c_str()); + return "在地图[" + mapName + "]的[" + areaName + "],位置" + position + ",熔岩烧死"; } - else if (inviteeRestriction == 1) // 被邀请者完全禁止组队 + else if (liquidData.Flags & MAP_LIQUID_TYPE_SLIME) { - ChatHandler(player->GetSession()).PSendSysMessage("目标玩家{} 禁止组队", inviteeMode.c_str()); + return "在地图[" + mapName + "]的[" + areaName + "],位置" + position + ",毒液腐蚀死亡"; } - else if (inviterRestriction == 2 || inviteeRestriction == 2) // 检查是否是等级差异问题 + else if (liquidData.Flags & MAP_LIQUID_TYPE_DARK_WATER) { - uint32 inviterDifficulty = sHardcoreMode->GetPlayerDifficultyType(player); - uint32 inviteeDifficulty = sHardcoreMode->GetPlayerDifficultyType(invitee); - - if (inviterDifficulty == inviteeDifficulty) - { - // 同难度但等级差异过大 - uint8 levelDiff = abs(player->GetLevel() - invitee->GetLevel()); - if (levelDiff > 5) - { - ChatHandler(player->GetSession()).PSendSysMessage( - "{}模式限制:等级差异过大({}级),只能与等级相近(±5级)的玩家组队", - inviterMode.c_str(), levelDiff); - - ChatHandler(invitee->GetSession()).PSendSysMessage( - "{}玩家 {} 尝试邀请你组队,但等级差异过大({}级),无法组队", - inviterMode.c_str(), player->GetName().c_str(), levelDiff); - - return false; - } - } + return "在地图[" + mapName + "]的[" + areaName + "],位置" + position + ",疲劳死亡(世界边界)"; } - else // 其他限制情况 + else if (player->IsInWater()) { - ChatHandler(player->GetSession()).PSendSysMessage("无法与 {} 玩家组队,模式限制", inviteeMode.c_str()); - } - - // 给被邀请者发送提示 - ChatHandler(invitee->GetSession()).PSendSysMessage("{} 玩家【{}】尝试邀请你组队,但因为模式限制无法组队", - inviterMode.c_str(), player->GetName().c_str()); - - return false; // 阻止邀请发送 - } - - return true; -} - -bool HardcorePlayerScript::OnPlayerCanGroupAccept(Player* player, Group* group) -{ - Player* leader = ObjectAccessor::FindConnectedPlayer(group->GetLeaderGUID()); - if (!leader) - return true; - - // 检查双方是否有组队限制 - bool playerHasRestriction = sHardcoreMode->ShouldApplyGroupRestriction(player); - bool leaderHasRestriction = sHardcoreMode->ShouldApplyGroupRestriction(leader); - - // 如果双方都没有限制,直接允许 - if (!playerHasRestriction && !leaderHasRestriction) - return true; - - // 双向检查组队限制 - bool canGroup = sHardcoreMode->CanGroupWithPlayer(leader, player) && - sHardcoreMode->CanGroupWithPlayer(player, leader); - - if (!canGroup) - { - // 获取双方的模式名称 - std::string playerMode = sHardcoreMode->GetPlayerModeName(player); - std::string leaderMode = sHardcoreMode->GetPlayerModeName(leader); - - // 给接受者发送提示 - 解决问题1 - uint32 playerRestriction = sHardcoreMode->GetGroupRestrictionType(player); - if (playerRestriction == 1) // 完全禁止组队 - { - ChatHandler(player->GetSession()).PSendSysMessage("{} 禁止组队", playerMode.c_str()); - } - else if (playerRestriction == 2) // 同难度近等级 - { - ChatHandler(player->GetSession()).PSendSysMessage("{} 只能与同难度且等级相近的玩家组队,邀请者当前为{}", - playerMode.c_str(), leaderMode.c_str()); - } - - // 给邀请者(组长)发送提示 - ChatHandler(leader->GetSession()).PSendSysMessage("{} 玩家 {} 无法接受组队邀请,因为模式限制", - playerMode.c_str(), player->GetName().c_str()); - - return false; - } - - return true; -} - -bool HardcorePlayerScript::OnPlayerCanPlaceAuctionBid(Player* player, AuctionEntry* auction) -{ - if (sHardcoreMode->ShouldApplyAuctionRestriction(player)) - { - ChatHandler(player->GetSession()).SendSysMessage("硬核模式限制:无法使用拍卖行"); - return false; - } - return true; -} - -bool HardcorePlayerScript::OnPlayerBeforeQuestComplete(Player* player, uint32 quest_id) -{ - if (sHardcoreMode->ShouldApplyQuestRestriction(player)) - { - ChatHandler(player->GetSession()).SendSysMessage("硬核模式限制:无法完成任务"); - return false; - } - return true; -} - -// 玩家获得经验时调用 -void HardcorePlayerScript::OnPlayerGiveXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource) -{ - float modifier = sHardcoreMode->GetExpModifier(player); - if (modifier != 1.0f) - { - amount = static_cast(amount * modifier); - } -} - -// 玩家等级发生变化后调用 -void HardcorePlayerScript::OnPlayerLevelChanged(Player* player, uint8 oldLevel) -{ - // 检查是否刚达到满级 - if (player->GetLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) && - oldLevel < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - sHardcoreMode->GiveHardcoreReward(player); - } - - // 检查组队限制 - CheckGroupLevelRestrictions(player); -} - -// 检查组队限制 -void HardcorePlayerScript::CheckGroupLevelRestrictions(Player* player) -{ - Group* group = player->GetGroup(); - if (!group) - return; - - uint32 playerRestriction = sHardcoreMode->GetGroupRestrictionType(player); - if (playerRestriction != 2) // 只处理"同难度且近等级"限制 - return; - - uint32 playerDifficulty = sHardcoreMode->GetPlayerDifficultyType(player); - uint8 playerLevel = player->GetLevel(); - - // 检查所有组员 - std::vector playersToKick; - - for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) - { - Player* member = itr->GetSource(); - if (!member || member == player) - continue; - - uint32 memberDifficulty = sHardcoreMode->GetPlayerDifficultyType(member); - uint32 memberRestriction = sHardcoreMode->GetGroupRestrictionType(member); - - // 检查是否同难度且有等级限制 - if (memberRestriction == 2 && memberDifficulty == playerDifficulty) - { - uint8 levelDiff = abs(playerLevel - member->GetLevel()); - if (levelDiff > 5) - { - // 决定踢出等级较高的玩家 - if (playerLevel > member->GetLevel()) - { - playersToKick.push_back(player); - } - else - { - playersToKick.push_back(member); - } - } + return "在地图[" + mapName + "]的[" + areaName + "],位置" + position + ",溺水死亡"; } } - // 踢出违反限制的玩家 - for (Player* kickPlayer : playersToKick) + // 检查坠落死亡 + Map* map = player->GetMap(); + if (map) { - // 获取双方的模式名称 - std::string playerMode = sHardcoreMode->GetPlayerModeName(player); - std::string leaderMode = sHardcoreMode->GetPlayerModeName(kickPlayer); - - ChatHandler(kickPlayer->GetSession()).PSendSysMessage("{} 由于等级差异超过限制,你被移出队伍", leaderMode); - - // 通知其他队员 - std::string kickMessage = playerMode + " 玩家 " + kickPlayer->GetName() + " 因等级差异过大被移出队伍"; - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, kickMessage); - group->BroadcastPacket(&data, false, -1, kickPlayer->GetGUID()); - - group->RemoveMember(kickPlayer->GetGUID()); + float groundZ = map->GetHeight(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); + if (player->GetPositionZ() - groundZ > 10.0f) + { + return "在地图[" + mapName + "]的[" + areaName + "],位置" + position + ",坠落死亡"; + } } + + // 默认环境死亡 + return "在地图[" + mapName + "]的[" + areaName + "],位置" + position + ",环境伤害死亡"; } +void HardcorePlayerScript::SendDeathMessage(Player* player, const std::string& message) +{ + ChatHandler(player->GetSession()).SendSysMessage(message.c_str()); + LOG_INFO("server.loading", "Death: {}", message); +} + + +//////////////////////////// HardcoreWorldScript //////////////////////////// // WorldScript 实现 - 处理世界事件 void HardcoreWorldScript::OnAfterConfigLoad(bool reload) { - LOG_INFO("hardcore", "Hardcore mode system initialized"); + LOG_INFO("server.loading", "Hardcore mode system initialized"); } + void HardcoreWorldScript::OnStartup() { //sHardcoreMode->LoadHardcoreModeTypes(); - LOG_INFO("hardcore", "Hardcore mode system ready - using command interface"); + LOG_INFO("server.loading", "Hardcore mode system ready - using command interface"); } -// ServerScript 实现 - 处理包钩子 +//////////////////////////// HardcoreServerScript //////////////////////////// +// 处理包钩子 bool HardcoreServerScript::CanPacketReceive(WorldSession* session, WorldPacket& packet) { Player* player = session->GetPlayer(); @@ -950,7 +1359,7 @@ bool HardcoreServerScript::CanPacketReceive(WorldSession* session, WorldPacket& // 使用正确的回调方式,避免lambda转换错误 if (session) { - // 直接在这里发送硬核状态,而不是使用回调 + // 发送硬核状态 sHardcoreMode->SendHardcoreStatusToClient(session); } } @@ -975,6 +1384,8 @@ bool HardcoreServerScript::CanPacketReceive(WorldSession* session, WorldPacket& return true; // 允许包继续处理 } +//////////////////////////// HardcoreCommandScript //////////////////////////// + // CommandScript 实现 - 新增切换和列表命令 Acore::ChatCommands::ChatCommandTable HardcoreCommandScript::GetCommands() const { @@ -996,6 +1407,145 @@ Acore::ChatCommands::ChatCommandTable HardcoreCommandScript::GetCommands() const return commandTable; } +// 启用硬核模式 +bool HardcoreCommandScript::HandleHardcoreEnableCommand(ChatHandler* handler) +{ + Player* player = handler->GetSession()->GetPlayer(); + if (!player) + return false; + if (sHardcoreMode->IsHardcorePlayer(player)) + { + handler->SendSysMessage("你已经启用了硬核模式。"); + return true; + } + + // GM命令使用默认难度类型(比如ID=1的正常模式) + uint32 defaultDifficultyId = 1; + sHardcoreMode->EnableHardcoreMode(player, defaultDifficultyId); + return true; +} + +// 查看自己的硬核模式状态 +bool HardcoreCommandScript::HandleHardcoreStatusCommand(ChatHandler* handler, Optional target) +{ + Player* targetPlayer = nullptr; + if (target) + { + targetPlayer = target->GetConnectedPlayer(); + if (!targetPlayer) + { + handler->SendSysMessage("玩家未找到或不在线。"); + return false; + } + } + else + { + targetPlayer = handler->GetSession()->GetPlayer(); + } + if (!targetPlayer) + return false; + HardcoreStatus status = sHardcoreMode->GetHardcoreStatus(targetPlayer); + uint32 difficultyType = sHardcoreMode->GetPlayerDifficultyType(targetPlayer); + switch (status) + { + case HC_STATUS_NORMAL: + handler->PSendSysMessage("玩家 {} 处于正常模式。", targetPlayer->GetName().c_str()); + break; + case HC_STATUS_HARDCORE: + handler->PSendSysMessage("玩家 {} 处于硬核模式,难度类型:{}。", targetPlayer->GetName().c_str(), difficultyType); + break; + case HC_STATUS_DEAD: + handler->PSendSysMessage("玩家 {} 在硬核模式中已死亡,难度类型:{}。", targetPlayer->GetName().c_str(), difficultyType); + break; + case HC_STATUS_COMPLETED: + handler->PSendSysMessage("玩家 {} 已完成硬核模式挑战。", targetPlayer->GetName().c_str()); + break; + } + return true; +} + +// 移除自己的硬核模式 +bool HardcoreCommandScript::HandleHardcoreDisableCommand(ChatHandler* handler, Optional target) +{ + if (!target) + { + target = Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { + handler->SendSysMessage("玩家未找到。"); + return false; + } + + Player* targetPlayer = target->GetConnectedPlayer(); + if (!targetPlayer) + { + handler->SendSysMessage("玩家未找到或不在线。"); + return false; + } + + if (!sHardcoreMode->IsHardcorePlayer(targetPlayer)) + { + handler->SendSysMessage("该玩家未启用硬核模式。"); + return false; + } + + sHardcoreMode->DisableHardcoreModeForOfflineCharacter(targetPlayer->GetGUID().GetCounter()); + handler->PSendSysMessage("已为玩家 {} 移除硬核模式。", targetPlayer->GetName().c_str()); + ChatHandler(targetPlayer->GetSession()).SendSysMessage("GM已为你移除硬核模式。"); + return true; +} + +// 复活硬核模式玩家 +bool HardcoreCommandScript::HandleHardcoreReviveCommand(ChatHandler* handler, Optional target) +{ + if (!target) + { + target = Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { + handler->SendSysMessage("玩家未找到。"); + return false; + } + + Player* targetPlayer = target->GetConnectedPlayer(); + if (!targetPlayer) + { + handler->SendSysMessage("玩家未找到或不在线。"); + return false; + } + + if (sHardcoreMode->GetHardcoreStatus(targetPlayer) != HC_STATUS_DEAD) + { + handler->SendSysMessage("该玩家未在硬核模式中死亡。"); + return false; + } + + // 加载现有的硬核数据 + HardcoreData existingData; + if (HardcoreDatabase::instance()->LoadHardcoreData(targetPlayer->GetGUID().GetCounter(), existingData)) + { + // 保留原有的难度类型ID,只修改状态 + existingData.status = HC_STATUS_HARDCORE; + existingData.deathTime = 0; + existingData.deathCause = "GM复活"; + sHardcoreMode->SaveHardcoreData(existingData); // 保存修改后的数据 + } + + if (!targetPlayer->IsAlive()) + { + targetPlayer->ResurrectPlayer(1.0f); + targetPlayer->SpawnCorpseBones(); + } + + handler->PSendSysMessage("已复活硬核模式玩家 {}。", targetPlayer->GetName().c_str()); + ChatHandler(targetPlayer->GetSession()).SendSysMessage("GM已复活你的硬核模式角色。"); + return true; +} + // 切换命令处理器 bool HardcoreCommandScript::HandleHardcoreToggleCommand(ChatHandler* handler, Optional characterName) { @@ -1041,7 +1591,7 @@ bool HardcoreCommandScript::HandleHardcoreDelCommand(ChatHandler* handler, Optio return true; } -// 新增:列表命令处理器 +// 查看硬核模式列表 bool HardcoreCommandScript::HandleHardcoreListCommand(ChatHandler* handler) { WorldSession* session = handler->GetSession(); @@ -1050,325 +1600,3 @@ bool HardcoreCommandScript::HandleHardcoreListCommand(ChatHandler* handler) sHardcoreMode->SendHardcoreStatusToClient(session); return true; } - -// 保留原有的其他命令处理函数 -bool HardcoreCommandScript::HandleHardcoreEnableCommand(ChatHandler* handler) -{ - Player* player = handler->GetSession()->GetPlayer(); - if (!player) - return false; - if (sHardcoreMode->IsHardcorePlayer(player)) - { - handler->SendSysMessage("你已经启用了硬核模式。"); - return true; - } - - // GM命令使用默认难度类型(比如ID=1的正常模式) - uint32 defaultDifficultyId = 1; - sHardcoreMode->EnableHardcoreMode(player, defaultDifficultyId); - return true; -} - -bool HardcoreCommandScript::HandleHardcoreStatusCommand(ChatHandler* handler, Optional target) -{ - Player* targetPlayer = nullptr; - if (target) - { - targetPlayer = target->GetConnectedPlayer(); - if (!targetPlayer) - { - handler->SendSysMessage("玩家未找到或不在线。"); - return false; - } - } - else - { - targetPlayer = handler->GetSession()->GetPlayer(); - } - if (!targetPlayer) - return false; - HardcoreStatus status = sHardcoreMode->GetHardcoreStatus(targetPlayer); - uint32 difficultyType = sHardcoreMode->GetPlayerDifficultyType(targetPlayer); - switch (status) - { - case HC_STATUS_NORMAL: - handler->PSendSysMessage("玩家 {} 处于正常模式。", targetPlayer->GetName().c_str()); - break; - case HC_STATUS_HARDCORE: - handler->PSendSysMessage("玩家 {} 处于硬核模式,难度类型:{}。", targetPlayer->GetName().c_str(), difficultyType); - break; - case HC_STATUS_DEAD: - handler->PSendSysMessage("玩家 {} 在硬核模式中已死亡,难度类型:{}。", targetPlayer->GetName().c_str(), difficultyType); - break; - } - return true; -} - -bool HardcoreCommandScript::HandleHardcoreDisableCommand(ChatHandler* handler, Optional target) -{ - if (!target) - { - target = Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(handler); - } - - if (!target) - { - handler->SendSysMessage("玩家未找到。"); - return false; - } - - Player* targetPlayer = target->GetConnectedPlayer(); - if (!targetPlayer) - { - handler->SendSysMessage("玩家未找到或不在线。"); - return false; - } - - if (!sHardcoreMode->IsHardcorePlayer(targetPlayer)) - { - handler->SendSysMessage("该玩家未启用硬核模式。"); - return false; - } - - sHardcoreMode->DisableHardcoreModeForOfflineCharacter(targetPlayer->GetGUID().GetCounter()); - handler->PSendSysMessage("已为玩家 {} 移除硬核模式。", targetPlayer->GetName().c_str()); - ChatHandler(targetPlayer->GetSession()).SendSysMessage("GM已为你移除硬核模式。"); - return true; -} - -bool HardcoreCommandScript::HandleHardcoreReviveCommand(ChatHandler* handler, Optional target) -{ - if (!target) - { - target = Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(handler); - } - - if (!target) - { - handler->SendSysMessage("玩家未找到。"); - return false; - } - - Player* targetPlayer = target->GetConnectedPlayer(); - if (!targetPlayer) - { - handler->SendSysMessage("玩家未找到或不在线。"); - return false; - } - - if (sHardcoreMode->GetHardcoreStatus(targetPlayer) != HC_STATUS_DEAD) - { - handler->SendSysMessage("该玩家未在硬核模式中死亡。"); - return false; - } - - sHardcoreMode->EnableHardcoreModeForOfflineCharacter(targetPlayer->GetGUID().GetCounter()); - if (!targetPlayer->IsAlive()) - { - targetPlayer->ResurrectPlayer(1.0f); - targetPlayer->SpawnCorpseBones(); - } - - handler->PSendSysMessage("已复活硬核模式玩家 {}。", targetPlayer->GetName().c_str()); - ChatHandler(targetPlayer->GetSession()).SendSysMessage("GM已复活你的硬核模式角色。"); - return true; -} - -// 检查限制的方法 -bool HardcoreMode::ShouldApplyGroupRestriction(Player* player) -{ - if (!player) - return false; - - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) - return false; - - std::lock_guard typeLock(_typesMutex); - for (const auto& modeType : _hardcoreModeTypes) - { - if (modeType.id == it->second.difficultyTypeId) - return modeType.groupRestrictions > 0; // 改为检查是否大于0 - } - return false; -} - - -// 获取玩家的组队限制类型 -uint32 HardcoreMode::GetGroupRestrictionType(Player* player) -{ - if (!player) - return 0; - - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) - return 0; - - std::lock_guard typeLock(_typesMutex); - for (const auto& modeType : _hardcoreModeTypes) - { - if (modeType.id == it->second.difficultyTypeId) - return modeType.groupRestrictions; // 现在这个字段存储限制类型而不是布尔值 - } - return 0; -} - -void HardcoreMode::GiveHardcoreReward(Player* player) -{ - uint32 difficultyType = GetPlayerDifficultyType(player); - if (difficultyType == 1) // 正常模式不给奖励 - return; - - // 检查是否已经发放过奖励 - if (HasReceivedHardcoreReward(player)) - return; - - std::lock_guard typeLock(_typesMutex); - for (const auto& modeType : _hardcoreModeTypes) - { - if (modeType.id == difficultyType) - { - // 调用你的奖励系统发放奖励 - sRew->Rew(player, modeType.RewID); - - // 记录已发放奖励 - MarkHardcoreRewardAsGiven(player); - - ChatHandler(player->GetSession()).PSendSysMessage( - "恭喜!你完成了{}难度挑战,获得专属奖励!", - modeType.name.c_str() - ); - break; - } - } -} - -bool HardcoreMode::HasReceivedHardcoreReward(Player* player) -{ - // 检查数据库或内存中是否已记录该玩家获得过奖励 - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - if (it != _hardcoreData.end()) - { - // 可以在 HardcoreData 结构体中添加一个 rewardReceived 字段 - return it->second.rewardReceived; - } - return false; -} - -void HardcoreMode::MarkHardcoreRewardAsGiven(Player* player) -{ - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - if (it != _hardcoreData.end()) - { - it->second.rewardReceived = true; - SaveHardcoreData(it->second); - } -} - - -bool HardcoreMode::ShouldApplyQuestRestriction(Player* player) -{ - if (!player) - return false; - - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) - return false; - - std::lock_guard typeLock(_typesMutex); - for (const auto& modeType : _hardcoreModeTypes) - { - if (modeType.id == it->second.difficultyTypeId) - return modeType.questRestrictions; - } - return false; -} - -bool HardcoreMode::ShouldApplyAuctionRestriction(Player* player) -{ - if (!player) - return false; - - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) - return false; - - std::lock_guard typeLock(_typesMutex); - for (const auto& modeType : _hardcoreModeTypes) - { - if (modeType.id == it->second.difficultyTypeId) - return modeType.auctionRestrictions; - } - return false; -} - -float HardcoreMode::GetExpModifier(Player* player) -{ - if (!player) - return 1.0f; - - std::lock_guard lock(_dataMutex); - auto it = _hardcoreData.find(player->GetGUID().GetCounter()); - if (it == _hardcoreData.end() || it->second.status != HC_STATUS_HARDCORE) - return 1.0f; - - std::lock_guard typeLock(_typesMutex); - for (const auto& modeType : _hardcoreModeTypes) - { - if (modeType.id == it->second.difficultyTypeId) - return modeType.expModifier; - } - return 1.0f; -} - -// 核心方法:检查两个玩家是否可以组队 -bool HardcoreMode::CanGroupWithPlayer(Player* inviter, Player* invitee) -{ - if (!inviter || !invitee) - return true; - - // 获取邀请者的组队限制类型 - uint32 inviterRestriction = GetGroupRestrictionType(inviter); - uint32 inviteeRestriction = GetGroupRestrictionType(invitee); - - // 如果邀请者无限制,可以邀请任何人 - if (inviterRestriction == 0) - return true; - - // 根据限制类型判断 - switch (inviterRestriction) - { - case 1: // 完全禁止组队 - return false; - - case 2: // 同难度且近等级组队 - { - // 检查难度是否相同 - uint32 inviterDifficulty = GetPlayerDifficultyType(inviter); - uint32 inviteeDifficulty = GetPlayerDifficultyType(invitee); - if (inviterDifficulty != inviteeDifficulty) - return false; - - // 检查等级差距 - uint8 levelDiff = abs(inviter->GetLevel() - invitee->GetLevel()); - return levelDiff <= 5; - } - - case 3: // 同难度组队 - { - uint32 inviterDifficulty = GetPlayerDifficultyType(inviter); - uint32 inviteeDifficulty = GetPlayerDifficultyType(invitee); - return inviterDifficulty == inviteeDifficulty; - } - - default: - return true; - } -} - diff --git a/modules/mod-hardcore/src/HardcoreMode.h b/modules/mod-hardcore/src/HardcoreMode.h index 78f04f6..1319a29 100644 --- a/modules/mod-hardcore/src/HardcoreMode.h +++ b/modules/mod-hardcore/src/HardcoreMode.h @@ -17,14 +17,14 @@ struct HardcoreModeType std::string subtitle; // 子标题 std::string description; // 描述文本 std::string backtexture; // 背景纹理 - std::string HardcoreLogo; // 难度标志图 - std::string RewBoxTexture; // 奖励宝箱纹理 - bool permanentDeath; - float expModifier; - uint32 groupRestrictions; // 组队限制 - bool questRestrictions; - bool auctionRestrictions; - uint32 RewID; // 奖励ID 关联【_模板_奖励】表 + std::string HardcoreLogo; // 难度标志图 + std::string RewBoxTexture; // 奖励宝箱纹理 + bool permanentDeath; // 永久死亡 + float expModifier; // 经验倍率 + uint32 groupRestrictions; // 组队限制 + bool questRestrictions; // 任务限制 + bool auctionRestrictions; // 拍卖行限制 + uint32 RewID; // 奖励ID 关联【_模板_奖励】表 }; class HardcoreMode @@ -32,15 +32,14 @@ class HardcoreMode public: static HardcoreMode* instance(); - bool IsHardcorePlayer(Player* player); + bool IsHardcorePlayer(Player* player);// 玩家是否开启了硬核模式 HardcoreStatus GetHardcoreStatus(Player* player); - HardcoreStatus GetHardcoreStatusByGuid(uint32 guid); void EnableHardcoreMode(Player* player, uint32 difficultyTypeId); - void EnableHardcoreModeForOfflineCharacter(uint32 guid); + void EnableHardcoreModeForOfflineCharacter(uint32 guid); // 命令启用硬核模式 void DisableHardcoreModeForOfflineCharacter(uint32 guid); void SetPlayerDead(Player* player, const std::string& cause, Unit* killer = nullptr); + bool HasPermanentDeath(Player* player); // 检查玩家的难度类型是否有永久死亡 bool CanResurrect(Player* player); - bool CanGroupWith(Player* player, Player* target); void LoadHardcoreData(Player* player); void SaveHardcoreData(const HardcoreData& data); void SetPlayerDifficultyType(Player* player, uint32 difficultyTypeId); // 当玩家选择特定难度时,需要将难度类型ID存储到玩家的硬核数据中 @@ -72,6 +71,7 @@ public: void GiveHardcoreReward(Player* player); bool HasReceivedHardcoreReward(Player* player); void MarkHardcoreRewardAsGiven(Player* player); + void SetPlayerHardcoreCompleted(uint32 guid); // 完成状态设置 private: std::unordered_map _hardcoreData; @@ -86,56 +86,59 @@ private: class HardcorePlayerScript : public PlayerScript { public: - HardcorePlayerScript() : PlayerScript("HardcorePlayerScript") { } + HardcorePlayerScript() : PlayerScript("HardcorePlayerScript") {} void OnPlayerFirstLogin(Player* player) override; // 当角色创建时调用 void OnPlayerLogin(Player* player) override; void OnPlayerLogout(Player* player) override; bool OnPlayerCanResurrect(Player* player) override; void OnPlayerJustDied(Player* player) override; + void OnPlayerPVPKill(Player* killer, Player* killed) override; + void OnPlayerKilledByCreature(Creature* killer, Player* killed) override; void OnPlayerReleasedGhost(Player* player) override; void OnPlayerUpdate(Player* player, uint32 p_time) override; - - bool OnPlayerCanGroupInvite(Player* player, std::string& membername) override; // 限制组队行为 - bool OnPlayerCanGroupAccept(Player* player, Group* group) override; // 限制接受组队行为 - bool OnPlayerCanPlaceAuctionBid(Player* /*player*/, AuctionEntry* /*auction*/)override; // 拍卖行交易 + bool OnPlayerCanGroupInvite(Player* player, std::string& membername) override; // 限制组队行为 + bool OnPlayerCanGroupAccept(Player* player, Group* group) override; // 限制接受组队行为 + bool OnPlayerCanPlaceAuctionBid(Player* /*player*/, AuctionEntry* /*auction*/)override; // 拍卖行交易 bool OnPlayerBeforeQuestComplete(Player* player, uint32 quest_id) override; void OnPlayerGiveXP(Player* /*player*/, uint32& /*amount*/, Unit* /*victim*/, uint8 /*xpSource*/) override; // 玩家获得经验时调用 - void OnPlayerLevelChanged(Player* /*player*/, uint8 /*oldlevel*/) override; // 玩家等级发生变化后调用 - - void CheckGroupLevelRestrictions(Player* player); // 检查组队限制 + void OnPlayerLevelChanged(Player* /*player*/, uint8 /*oldlevel*/) override; // 玩家等级发生变化后调用 - // 限制玩家状态 - void ApplyHardcoreRestrictions(Player* player); - - - - // 启动5秒定时器 - void StartHardcoreReminder(Player* player); - + void CheckGroupLevelRestrictions(Player* player); // 检查组队限制 + void ApplyHardcoreRestrictions(Player* player); // 限制玩家状态 + void StartHardcoreReminder(Player* player); // 启动5秒定时器 private: TaskScheduler _scheduler; - std::unordered_set _reminderPlayers; // 需要提醒的玩家GUID + std::unordered_set _reminderPlayers; // 需要提醒的玩家GUID std::unordered_map _reminderStartTime; // 记录每个玩家的提醒开始时间 std::unordered_map _reminderCount; // 玩家GUID -> 提醒计数 + std::unordered_set _processedDeaths; // 记录已处理的死亡 + + std::string GetMapName(Player* player); + std::string GetAreaName(Player* player); + std::string GetCreatureRankName(uint32 rank); + std::string FormatPosition(float x, float y, float z); + std::string FormatPvPDeathMessage(Player* killer, Player* killed); + std::string FormatCreatureDeathMessage(Creature* killer, Player* killed); + std::string GetEnvironmentalDeathMessage(Player* player); + void SendDeathMessage(Player* player, const std::string& message); }; class HardcoreWorldScript : public WorldScript { public: - HardcoreWorldScript() : WorldScript("HardcoreWorldScript") { } + HardcoreWorldScript() : WorldScript("HardcoreWorldScript") {} void OnAfterConfigLoad(bool reload) override; void OnStartup() override; }; -// 新增:ServerScript 用于包处理 +// 包处理 class HardcoreServerScript : public ServerScript { public: - HardcoreServerScript() : ServerScript("HardcoreServerScript") { } - + HardcoreServerScript() : ServerScript("HardcoreServerScript") {} bool CanPacketReceive(WorldSession* session, WorldPacket& packet) override; }; @@ -147,19 +150,13 @@ public: Acore::ChatCommands::ChatCommandTable GetCommands() const override; private: - static bool HandleHardcoreEnableCommand(ChatHandler* handler); + static bool HandleHardcoreEnableCommand(ChatHandler* handler); // 启用硬核模式 static bool HandleHardcoreStatusCommand(ChatHandler* handler, Optional target); - static bool HandleHardcoreDisableCommand(ChatHandler* handler, Optional target); - static bool HandleHardcoreReviveCommand(ChatHandler* handler, Optional target); - - // 新增:替代操作码的命令 - static bool HandleHardcoreToggleCommand(ChatHandler* handler, Optional characterName); - - // 移除硬核模式 - static bool HandleHardcoreDelCommand(ChatHandler* handler, Optional characterName); - - - static bool HandleHardcoreListCommand(ChatHandler* handler); + static bool HandleHardcoreDisableCommand(ChatHandler* handler, Optional target); // 移除自己的硬核模式 + static bool HandleHardcoreReviveCommand(ChatHandler* handler, Optional target); // 复活硬核模式玩家 + static bool HandleHardcoreToggleCommand(ChatHandler* handler, Optional characterName); // 切换命令处理器 + static bool HandleHardcoreDelCommand(ChatHandler* handler, Optional characterName); // 移除硬核模式 + static bool HandleHardcoreListCommand(ChatHandler* handler);// 查看硬核模式列表 }; #endif diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 9eba58b..6e677d6 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -40,15 +40,39 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_GUID_BY_NAME_FILTER, "SELECT guid, name FROM characters WHERE name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_BANINFO_LIST, "SELECT bandate, unbandate, bannedby, banreason FROM character_banned WHERE guid = ? ORDER BY unbandate", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_BANNED_NAME, "SELECT characters.name FROM characters, character_banned WHERE character_banned.guid = ? AND character_banned.guid = characters.guid", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " - "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, c.extra_flags, c.硬核模式 " - "FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? LEFT JOIN guild_member AS gm ON c.guid = gm.guid " - "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL ORDER BY COALESCE(c.order, c.guid)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, " - "c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, " - "cb.guid, c.extra_flags, c.硬核模式, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? " - "LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid " - "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL ORDER BY COALESCE(c.order, c.guid)", CONNECTION_ASYNC); + + // [自定义模组:硬核模式] 添加角色硬核模式表的 LEFT JOIN 以获取难度类型 + PrepareStatement(CHAR_SEL_ENUM, + "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, " + "c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " + "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, " + "cb.guid, c.extra_flags, hc.难度类型编号 " // [自定义] 从外部表读取硬核难度类型 + "FROM characters AS c " + "LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? " + "LEFT JOIN guild_member AS gm ON c.guid = gm.guid " + "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 " + "LEFT JOIN 角色硬核模式 AS hc ON c.guid = hc.角色编号 " // [自定义模组:硬核模式] 外部表关联 + "WHERE c.account = ? AND c.deleteInfos_Name IS NULL " + "ORDER BY COALESCE(c.order, c.guid)", + CONNECTION_ASYNC); + + // [自定义模组:硬核模式] 调整字段顺序,将 declined name 保持在索引 25 + PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, + "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, " + "c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " + "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, " + "cb.guid, c.extra_flags, cd.genitive, hc.难度类型编号 " // [自定义] 调整顺序:先 genitive 后硬核模式 + "FROM characters AS c " + "LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? " + "LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid " + "LEFT JOIN guild_member AS gm ON c.guid = gm.guid " + "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 " + "LEFT JOIN 角色硬核模式 AS hc ON c.guid = hc.角色编号 " // [自定义模组:硬核模式] 外部表关联 + "WHERE c.account = ? AND c.deleteInfos_Name IS NULL " + "ORDER BY COALESCE(c.order, c.guid)", + CONNECTION_ASYNC); + + PrepareStatement(CHAR_SEL_FREE_NAME, "SELECT guid, name, at_login FROM characters WHERE guid = ? AND account = ? AND NOT EXISTS (SELECT NULL FROM characters WHERE name = ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHAR_ZONE, "SELECT zone FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHARACTER_NAME_DATA, "SELECT race, class, gender, level FROM characters WHERE guid = ?", CONNECTION_SYNCH); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 968bf44..35149a5 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1147,12 +1147,24 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) *data << uint8(hairColor); *data << uint8(facialStyle); - // 获取硬核模式状态 - 使用硬核模式字段 - uint8 hardcoreModeId = fields[25].Get(); + // [自定义模组:硬核模式] 根据查询类型读取硬核模式字段 - 开始 + uint32 hardcoreModeId = 0; + if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) + { + // CHAR_SEL_ENUM_DECLINED_NAME: 硬核模式在索引 26 + hardcoreModeId = fields[26].IsNull() ? 0 : fields[26].Get(); + } + else + { + // CHAR_SEL_ENUM: 硬核模式在索引 25 + hardcoreModeId = fields[25].IsNull() ? 0 : fields[25].Get(); + } + uint8 actualLevel = fields[10].Get(); - // 如果是硬核模式(ID > 0),使用最高位标记 - bool isHardcore = hardcoreModeId > 0; + bool isHardcore = hardcoreModeId > 1; // 只有难度类型 > 1 才是硬核模式 uint8 encodedLevel = actualLevel | (isHardcore ? 1 << 7 : 0); + // [自定义模组:硬核模式] 根据查询类型读取硬核模式字段 - 结束 + *data << uint8(encodedLevel); // level *data << uint32(zone); // zone *data << uint32(fields[12].Get()); // map diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index f02dfa5..7d4ee0e 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -35,6 +35,7 @@ #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "../../../../modules/mod_GhostScripts/src/mod_CharNameMod/CharNameMod.h" class Aura; @@ -66,6 +67,16 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) recvData >> membername; recvData.read_skip(); + // 自定义名字清理逻辑 - 让拥有自定义前缀后缀的玩家能够正常组队 + if (sCharNameMod) + { + std::string cleanName = sCharNameMod->GetPureName(membername); + if (!cleanName.empty() && cleanName != membername) + { + membername = cleanName; // 用清理后的纯净名称替换原始输入 + } + } + // attempt add selected player // cheating