306 lines
10 KiB
Lua
Raw Permalink Normal View History

2025-01-04 23:00:19 +08:00
---@class SoldierBase
---@field Init fun() 初始化兵种信息
---@field PlayerKey PlayerKey 拥有者的玩家 Key
---@field Skills table<int32, EBuffType> 拥有的技能
---@field Features table<ESpecialType, float> 拥有的特性
---@field SetPlayerKey fun(InPlayerKey:PlayerKey) 设置玩家 Key
---@field StartPlay fun() 正式开始游戏
---@field EnableFeature fun(IsEnable:bool) 启用特性
---@field TriggerSkill fun(InSkillId: EBuffType|nil, ...:vararg) 执行技能
---@field StopTriggerSkill fun(InSkillId: EBuffType|nil) 停止执行 Skill
---@field Tick fun(DeltaTime: float) 每帧执行
---@field HasActiveSkill fun() 是否有主动技能
---@class SoldierBuffInfo
---@field StartTime float 当前使用的开始时间
---@field EndTime float 当前使用的开始时间
---@field IsDefault bool 是否是被动技能
---@field BuffId int32 当前执行的 Buff ID
require('Script.Global.Table.SoldierConfig')
require('Script.Global.Table.ItemTable')
-- 兵种类型基类
local SoldierBase = {
---@type PlayerKey
PlayerKey = nil;
---@type table<int32, EBuffType>
Skills = { };
---@type table<ESpecialType, float> 当前的特性
Features = {
[SoldierConfig.ESpecialType.Health ] = 1, -- 生命
[SoldierConfig.ESpecialType.Damage ] = 1, -- 伤害
[SoldierConfig.ESpecialType.Speed ] = 1, -- 移速
[SoldierConfig.ESpecialType.Poison ] = 1, -- 毒杀
[SoldierConfig.ESpecialType.Defence ] = 1, -- 防御值
};
---@type ESoldierType 当前的兵种类型
SoldierType = 0;
---@type table<EBuffType, SoldierBuffInfo> 下一次可以使用 Buff 的时间,包含可以使用的 Buff
BuffInfo = { };
};
--- 初始化,分为客户端和服务器,仅在最开始的时候设置一次;在设置兵种的时候进行初始化
---@param InPlayerKey PlayerKey
function SoldierBase:Init(InPlayerKey, InSoldierType)
self.PlayerKey = InPlayerKey;
self.SoldierType = InSoldierType;
if UGCGameSystem.IsServer() then
-- 检查当前数值是否都是 1如果不是就改变
local Feature = SoldierConfig.Features[self.SoldierType]
for i, v in pairs(SoldierConfig.ESpecialType) do
if Feature[v] ~= nil then self.Features[v] = Feature[v]; end
end
self:CheckSoldierType();
self:SendRPC(false, "Init", self.PlayerKey, self.SoldierType);
else
-- 执行对应操作
end
end
--- 检查兵种是否有可执行的技能,如果有,立刻执行;没有就返回
function SoldierBase:CheckSoldierType(InBuffInfo, InSkill)
if self:HasAuthority() then
self.BuffInfo = {};
self.Skills = {};
-- 检查是否含有被动
local Config = SoldierConfig.Skills[self.SoldierType];
if table.isEmpty(Config) then return; end
local Skills = {};
local CurrTime = KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState);
for i, v in pairs(Config.Skills) do
self.Skills[#self.Skills + 1] = v.BuffType;
self.BuffInfo[v.BuffType] = {
StartTime = CurrTime;
EndTime = CurrTime;
IsDefault = v.Cooldown == nil;
BuffId = nil; -- 之后填充
};
if v.Cooldown == nil then
self:TriggerSkill();
end
end
UGCLogSystem.LogTree("[SoldierBase:CheckSoldierType] self.BuffInfo = self.SoldierType = " .. tostring(self.SoldierType), self.BuffInfo);
-- 发送到客户端
self:SendRPC(false, "CheckSoldierType", self.BuffInfo, self.Skills);
else
-- 如果没有的话通知没有技能,就不显示技能图标了
self.BuffInfo = InBuffInfo;
self.Skills = InSkill;
end
end
-- 正式开始游戏
function SoldierBase:StartPlay()
if UGCGameSystem.IsServer() then self:EnableFeature(true); end
end
--- S & C
function SoldierBase:HasSkill()
return not table.isEmpty(self.BuffInfo);
end
--- 执行对应的技能
--- S
---@param InSkillId EBuffType|nil|table<EBuffType>
---@vararg any|nil 传入技能是否会被改变的参数
function SoldierBase:TriggerSkill(InSkillId, ...)
if table.isEmpty(self.Skills) then return false; end
-- 检查是否存在当前技能
local UseSkills = {};
if InSkillId == nil then
UseSkills = self.Skills;
else
if not table.hasValue(InSkillId) then return false; end
UseSkills[#UseSkills + 1] = InSkillId;
end
-- 开始执行
local CanUseBuffs = {};
local CurrTime = KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState);
for Index, BuffType in pairs(UseSkills) do
local Info = self.BuffInfo[BuffType];
if Info.EndTime <= CurrTime then
CanUseBuffs[#CanUseBuffs + 1] = BuffType;
end
end
if table.isEmpty(CanUseBuffs) then
UGCLogSystem.Log("[SoldierBase:TriggerSkill] 可以使用的时间还未到。");
return CanUseBuffs;
end
local ConfigSkills = SoldierConfig.Skills[self.SoldierType];
if table.isEmpty(ConfigSkills) then return CanUseBuffs; end
-- 依次执行技能
for Index, BuffType in pairs(CanUseBuffs) do
-- 检查是否有参数,先使用默认参数
for i, v in pairs(ConfigSkills.Skills) do
if BuffType ~= v.BuffType then return; end
local BuffManager = BP_BuffManager.GetBuffManager();
local IsSucceed, BuffId = BuffManager:AddBuff(BuffType, self.PlayerKey, BuffType, table.unpackTable(v.Params));
if IsSucceed == BP_BuffManager.EResult.Succeed then
self.BuffInfo[BuffType].BuffId = BuffId;
if v.Cooldown == nil then
self.BuffInfo[BuffType].IsDefault = true;
else
self.BuffInfo[BuffType].IsDefault = false;
local ContinueTime = 0;
if v.ContinueTime ~= nil and v.ContinueTime > 0 then
ContinueTime = v.ContinueTime
BuffManager:SetBuffDuration(BuffId, ContinueTime);
end
if v.Cooldown > 0 then
self.BuffInfo[BuffType].StartTime = CurrTime;
CurrTime = CurrTime + v.Cooldown + ContinueTime
self.BuffInfo[BuffType].EndTime = CurrTime;
end
end
self:PostTriggerSkill(BuffType, self.BuffInfo[BuffType]);
-- 发送通知
else
UGCLogSystem.LogError("[SoldierBase:TriggerSkill] 当前 %d没有启动 BUFF: %d报错信息%s", self.PlayerKey, BuffType, IsSucceed);
end
end
end
end
--- 触发技能之后执行的,子类进行继承,可以实现不同效果,父类默认发送给自身
function SoldierBase:PostTriggerSkill(InBuffType, InBuffInfo)
local CurrTime = KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState);
UGCGameSystem.GameState:ClientSendEvent(nil, EventTypes.PlayerUseBuff, self.PlayerKey, InBuffType, InBuffInfo, CurrTime);
UGCLogSystem.Log("[SoldierBase:PostTriggerSkill] PlayerKey = %s", tostring(self.PlayerKey));
self:SendRPC(true, "Client_TriggerSkill", self.PlayerKey, InBuffType, InBuffInfo);
end
---@param InPlayerKey PlayerKey
---@param InBuffType EBuffType
---@param InBuffInfo table<EBuffType, SoldierBuffInfo>
function SoldierBase:Client_TriggerSkill(InPlayerKey, InBuffType, InBuffInfo)
-- 通知所有客户端xxx的xxx技能已经执行了
UGCLogSystem.Log("[SoldierBase:Client_TriggerSkill] %s 客户端触发技能:%s", tostring(InPlayerKey), tostring(InBuffType));
end
--- 停止执行技能
---@param InSkillId EBuffType|nil 传入对应
function SoldierBase:StopTriggerSkill(InSkillId)
-- 直接移除即可
local BuffManager = BP_BuffManager.GetBuffManager();
local CurrTime = KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState);
if self.BuffInfo[InSkillId] == nil then return; end
if self.BuffInfo[InSkillId].EndTime < CurrTime then
BuffManager:RemoveBuffDuration(self.BuffInfo[InSkillId].BuffId);
end
end
--- 启用特性
--- S
---@param IsEnable bool
function SoldierBase:EnableFeature(IsEnable)
local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(self.PlayerKey);
for i, v in pairs(self.Features) do
if i == SoldierConfig.ESpecialType.Health then
UGCPawnAttrSystem.SetHealthMax(Pawn, UGCPawnAttrSystem.GetHealthMax(Pawn) * v);
UGCPawnAttrSystem.SetHealth(Pawn, UGCPawnAttrSystem.GetHealthMax(Pawn));
elseif i == SoldierConfig.ESpecialType.Speed then
UGCPawnAttrSystem.SetSpeedScale(Pawn, UGCPawnAttrSystem.GetSpeedScale(self) * v);
elseif i == SoldierConfig.ESpecialType.Strong then
-- 设置对应数据即可
Pawn:SetParam('Strong', Pawn:GetParam('Strong') * v);
elseif i == SoldierConfig.ESpecialType.Defence then
Pawn:SetParam('Defence', Pawn:GetParam('Defence') * v);
elseif i == SoldierConfig.ESpecialType.Poison then
-- 设置毒圈属性
Pawn:SetParam('PoisonDefence', Pawn:GetParam('PoisonDefence') * v);
end
end
end
--- 停止特性
--- S
function SoldierBase:UnEnableFeature()
local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(self.PlayerKey);
for i, v in pairs(self.Features) do
if i == SoldierConfig.ESpecialType.Health then
UGCPawnAttrSystem.SetHealthMax(Pawn, UGCPawnAttrSystem.GetHealthMax(Pawn) / v);
UGCPawnAttrSystem.SetHealth(Pawn, UGCPawnAttrSystem.GetHealthMax(Pawn));
elseif i == SoldierConfig.ESpecialType.Speed then
UGCPawnAttrSystem.SetSpeedScale(Pawn, UGCPawnAttrSystem.GetSpeedScale(self) / v);
elseif i == SoldierConfig.ESpecialType.Strong then
-- 设置对应数据即可
Pawn:SetParam('Strong', Pawn:GetParam('Strong') / v);
elseif i == SoldierConfig.ESpecialType.Defence then
Pawn:SetParam('Defence', Pawn:GetParam('Defence') / v); -- 永久改变
elseif i == SoldierConfig.ESpecialType.Poison then
-- 设置毒
Pawn:SetParam('PoisonDefence', Pawn:GetParam('PoisonDefence') / v);
end
end
end
--- 判断当前是否是服务器
function SoldierBase:HasAuthority() return UGCGameSystem.IsServer(); end
---@param IsMulti bool 是否是 mrpc
---@param FuncName string 函数名称
function SoldierBase:SendRPC(IsMulti, FuncName, ...)
UGCGameSystem.GameState:SendSoldierRPC(IsMulti, FuncName, self.PlayerKey, self.SoldierType, ...)
end
--- tick 函数
---@param DeltaTime float
function SoldierBase:Tick(DeltaTime) end
--- 获取兵种类型
---@return ESoldierType
function SoldierBase:GetSoldierType()
return self.SoldierType;
end
--- 重置兵种信息
function SoldierBase:RestSoldier()
local Curr = KismetSystemLibrary.GetGameTimeInSeconds(UGCGameSystem.GameState);
for i, v in pairs(self.BuffInfo) do
if v.BuffId ~= nil then
-- 销毁
self:StopTriggerSkill(v.BuffId);
end
v.EndTime = Curr;
v.StartTime = Curr;
end
end
--- 是否有主动技能
function SoldierBase:HasActiveSkill()
UGCLogSystem.LogTree("[SoldierBase:HasActiveSkill] self.BuffInfo = ", self.BuffInfo);
for i, v in pairs(self.BuffInfo) do
if v.IsDefault == false then
return true;
end
end
return false;
end
function SoldierBase:new()
local newObj = SoldierBase
self.__index = self;
return setmetatable(newObj, self);
end
return SoldierBase;