2025-01-04 23:00:19 +08:00

306 lines
10 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---@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;