【硬核模式】优化

1、增加”硬核模式类型“表设置多级难度
2、各种条件限制的设定和限制处理
3、插件的发包数据处理
This commit is contained in:
尚美 2025-10-03 15:04:45 +08:00
parent d766592c5b
commit 22f07eab1d
6 changed files with 1106 additions and 79 deletions

View File

@ -14,7 +14,8 @@ HardcoreDatabase* HardcoreDatabase::instance()
bool HardcoreDatabase::LoadHardcoreData(uint32 playerGuid, HardcoreData& data)
{
std::string query = Acore::StringFormat("SELECT 角色编号, 状态, UNIX_TIMESTAMP(启用时间), UNIX_TIMESTAMP(死亡时间), 最终等级, 死亡原因, 击杀者编号 FROM 角色硬核模式 WHERE 角色编号 = {}", playerGuid);
std::string query = Acore::StringFormat("SELECT 角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 死亡原因, 击杀者编号,奖励已领取 FROM 角色硬核模式 WHERE 角色编号 = {}", playerGuid);
QueryResult result = CharacterDatabase.Query(query);
if (!result)
@ -23,32 +24,33 @@ bool HardcoreDatabase::LoadHardcoreData(uint32 playerGuid, HardcoreData& data)
Field* fields = result->Fetch();
data.guid = fields[0].Get<uint32>();
data.status = static_cast<HardcoreStatus>(fields[1].Get<uint8>());
data.enableTime = fields[2].Get<uint32>();
data.deathTime = fields[3].Get<uint32>();
data.finalLevel = fields[4].Get<uint8>();
data.deathCause = fields[5].Get<std::string>();
data.killerGuid = fields[6].Get<uint32>();
data.difficultyTypeId = fields[2].Get<uint32>();
data.enableTime = fields[3].Get<uint32>();
data.deathTime = fields[4].Get<uint32>();
data.finalLevel = fields[5].Get<uint8>();
data.deathCause = fields[6].Get<std::string>();
data.killerGuid = fields[7].Get<uint32>();
data.rewardReceived = fields[8].Get<bool>(); // 奖励领取状态
return true;
}
void HardcoreDatabase::SaveHardcoreData(const HardcoreData& data)
{
std::string enableTimeStr = data.enableTime > 0 ? Acore::StringFormat("FROM_UNIXTIME({})", data.enableTime) : "NULL";
std::string deathTimeStr = data.deathTime > 0 ? Acore::StringFormat("FROM_UNIXTIME({})", data.deathTime) : "NULL";
std::string escapedCause = data.deathCause;
CharacterDatabase.EscapeString(escapedCause);
std::string query = Acore::StringFormat(
"REPLACE INTO 角色硬核模式 (角色编号, 状态, 启用时间, 死亡时间, 最终等级, 死亡原因, 击杀者编号) VALUES ({}, {}, {}, {}, {}, '{}', {})",
"REPLACE INTO 角色硬核模式 (角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 死亡原因, 击杀者编号) VALUES ({}, {}, {}, {}, {}, {}, '{}', {})",
data.guid,
static_cast<uint8>(data.status),
enableTimeStr,
deathTimeStr,
data.difficultyTypeId,
data.enableTime,
data.deathTime,
data.finalLevel,
escapedCause,
data.killerGuid
data.killerGuid,
data.rewardReceived ? 1 : 0 // 新增:保存奖励领取状态
);
CharacterDatabase.Execute(query);

View File

@ -9,20 +9,22 @@
// 前向声明,避免循环包含
enum HardcoreStatus : uint8
{
HC_STATUS_DISABLED = 0,
HC_STATUS_ENABLED = 1,
HC_STATUS_DEAD = 2
HC_STATUS_NORMAL = 0, // 未启用硬核模式 - 玩家处于正常游戏模式
HC_STATUS_HARDCORE= 1, // 已启用硬核模式 - 玩家处于硬核模式,死亡将是永久的
HC_STATUS_DEAD = 2 // 硬核模式中已死亡 - 玩家在硬核模式中死亡,无法复活
};
struct HardcoreData
{
uint32 guid;
HardcoreStatus status;
HardcoreStatus status; // 生存状态(正常/硬核/死亡)
uint32 difficultyTypeId; // 难度类型ID对应"硬核模式类型"表)
time_t enableTime;
time_t deathTime;
uint8 finalLevel;
std::string deathCause;
uint32 killerGuid;
bool rewardReceived = false; // 是否已获得奖励
};
class HardcoreDatabase

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,23 @@
#include "ChatCommand.h"
#include "Optional.h"
struct HardcoreModeType
{
uint32 id;
std::string name;
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 关联【_模板_奖励】表
};
class HardcoreMode
{
public:
@ -18,7 +35,7 @@ public:
bool IsHardcorePlayer(Player* player);
HardcoreStatus GetHardcoreStatus(Player* player);
HardcoreStatus GetHardcoreStatusByGuid(uint32 guid);
void EnableHardcoreMode(Player* player);
void EnableHardcoreMode(Player* player, uint32 difficultyTypeId);
void EnableHardcoreModeForOfflineCharacter(uint32 guid);
void DisableHardcoreModeForOfflineCharacter(uint32 guid);
void SetPlayerDead(Player* player, const std::string& cause, Unit* killer = nullptr);
@ -26,14 +43,42 @@ public:
bool CanGroupWith(Player* player, Player* target);
void LoadHardcoreData(Player* player);
void SaveHardcoreData(const HardcoreData& data);
void SetPlayerDifficultyType(Player* player, uint32 difficultyTypeId); // 当玩家选择特定难度时需要将难度类型ID存储到玩家的硬核数据中
// 新增:替代操作码的方法
const HardcoreModeType* GetModeTypeById(uint32 difficultyTypeId); // 获取难度类型信息
std::string GetPlayerModeName(Player* player); // 获取模式名称的方法
bool IsValidDifficultyType(uint32 difficultyTypeId); // 验证该难度类型是否在"硬核模式类型"表中存在防止无效的难度ID被设置
uint32 GetPlayerDifficultyType(Player* player); // 获取玩家硬核模式类型
void ToggleHardcoreModeForCharacter(WorldSession* session, const std::string& characterName, bool enable);
void SendHardcoreStatusToClient(WorldSession* session);
// 加载硬核模式类型
void LoadHardcoreModeTypes();
std::string GetHardcoreModeTypesData();
// 解除玩家限制状态
void RemoveHardcoreRestrictions(Player* player);
// 检查限制的方法
bool ShouldApplyGroupRestriction(Player* player);
bool ShouldApplyQuestRestriction(Player* player);
bool ShouldApplyAuctionRestriction(Player* player);
float GetExpModifier(Player* player);
bool CanGroupWithPlayer(Player* inviter, Player* invitee);
uint32 GetGroupRestrictionType(Player* player); // 获取玩家的组队限制类型
// 奖励发放
void GiveHardcoreReward(Player* player);
bool HasReceivedHardcoreReward(Player* player);
void MarkHardcoreRewardAsGiven(Player* player);
private:
std::unordered_map<uint32, HardcoreData> _hardcoreData;
std::mutex _dataMutex;
std::vector<HardcoreModeType> _hardcoreModeTypes;
std::mutex _typesMutex;
};
#define sHardcoreMode HardcoreMode::instance()
@ -43,11 +88,37 @@ class HardcorePlayerScript : public PlayerScript
public:
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 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 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 ApplyHardcoreRestrictions(Player* player);
// 启动5秒定时器
void StartHardcoreReminder(Player* player);
private:
TaskScheduler _scheduler;
std::unordered_set<uint32> _reminderPlayers; // 需要提醒的玩家GUID
std::unordered_map<uint32, uint64> _reminderStartTime; // 记录每个玩家的提醒开始时间
std::unordered_map<uint32, uint32> _reminderCount; // 玩家GUID -> 提醒计数
};
class HardcoreWorldScript : public WorldScript
@ -78,11 +149,16 @@ public:
private:
static bool HandleHardcoreEnableCommand(ChatHandler* handler);
static bool HandleHardcoreStatusCommand(ChatHandler* handler, Optional<Acore::ChatCommands::PlayerIdentifier> target);
static bool HandleHardcoreDisableCommand(ChatHandler* handler, Acore::ChatCommands::PlayerIdentifier target);
static bool HandleHardcoreReviveCommand(ChatHandler* handler, Acore::ChatCommands::PlayerIdentifier target);
static bool HandleHardcoreDisableCommand(ChatHandler* handler, Optional<Acore::ChatCommands::PlayerIdentifier> target);
static bool HandleHardcoreReviveCommand(ChatHandler* handler, Optional<Acore::ChatCommands::PlayerIdentifier> target);
// 新增:替代操作码的命令
static bool HandleHardcoreToggleCommand(ChatHandler* handler, Optional<std::string> characterName);
// 移除硬核模式
static bool HandleHardcoreDelCommand(ChatHandler* handler, Optional<std::string> characterName);
static bool HandleHardcoreListCommand(ChatHandler* handler);
};

View File

@ -88,6 +88,7 @@
#include "mod_Creature_MultiLifeMultiplier.h" //生物血量扩展
#include <MirrorClone.h>
#include <Mythic_Script.h>
#include <HardcoreMode.h>
using namespace Acore::ChatCommands;
@ -279,6 +280,8 @@ void DataLoader::LoadAll()
sMirrorCloneConfigMgr->LoadMirrorConfigs();
sMythicPlusCache->Initialize();
sHardcoreMode->LoadHardcoreModeTypes(); // 硬核模式
}
class DataLoaderWorldScript : public WorldScript

View File

@ -18,6 +18,9 @@
#include "MythicPlusWrapperInstance.h"
#include <MapMgr.h>
#include <GridNotifiers.h>
#include <HardcoreMode.h>
#include <Reward.h>
#include <CommonFunc.h>
void ResetInstanceCreaturesAndObjects(Player* player, InstanceMap* instanceMap)
{
@ -881,6 +884,57 @@ bool ModSMAddon::OnRecv(Player* player, std::string msg)
}
}
}
// 查看当前难度奖励信息
else if (sGCAddon->IsOpcode(opcode, "SM_C_VIRWHARDCORE_REWINFO"))
{
std::string RewIDStr = sGCAddon->SplitStr(msg, 1);
uint32 RewID = std::stoul(RewIDStr);
std::ostringstream oss;
if (!sRew->IsExist(RewID))
{
LOG_ERROR("server.loading", "难度ID {} 不存在", RewID);
oss << "|TInterface\\DialogFrame\\UI-Dialog-Icon-AlertNew:60:60:0:-10|t"
<< "\n|cFFFF0606[警告]|r\n难度ID [" << RewID << "] [不存在] \n";
sCF->SendAcceptOrCancel(player, 9999, oss.str());
return false;
}
std::string Reward = sRew->GetDescription(RewID, true);
oss << "当前难度奖励\n\n" << Reward<< "\n";
sCF->SendAcceptOrCancel(player, 9999, oss.str());
}
// 选择硬核模式难度
else if (sGCAddon->IsOpcode(opcode, "SM_C_SELECTHARDCOREMODE"))
{
std::string difficultyIdStr = sGCAddon->SplitStr(msg, 1);
uint32 difficultyId = std::stoul(difficultyIdStr);
// 验证难度类型是否有效
if (!sHardcoreMode->IsValidDifficultyType(difficultyId))
{
LOG_ERROR("server.loading", "Player {} selected invalid difficulty type {}", player->GetName(), difficultyId);
return false;
}
HardcoreStatus aaaa = sHardcoreMode->GetHardcoreStatus(player);
// 检查玩家是否已经设置过难度
if (aaaa != HC_STATUS_NORMAL)
{
LOG_WARN("server.loading", "Player {} attempted to change difficulty but already has hardcore mode set", player->GetName());
return false;
}
// 解除所有限制
sHardcoreMode->RemoveHardcoreRestrictions(player);
// 设置玩家的硬核模式和难度类型
sHardcoreMode->EnableHardcoreMode(player, difficultyId);
LOG_INFO("server.loading", "Player {} selected hardcore difficulty type {}", player->GetName(), difficultyId);
return true;
}
return false;
}