This commit is contained in:
Ggafrik 2025-07-14 00:30:47 +08:00
parent ac7c83a9bb
commit 083331454f
13 changed files with 439 additions and 3 deletions

BIN
excel/ability.xlsx Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
[
{"id":20000,"type":1,"behaviourName":"swordWave","upgradeCost":[30000,5,10],"upgradeValue":[10,200],"recycle":[30000,100]}
]

View File

@ -12,6 +12,16 @@
{"id":11,"type":1,"effectAttribute":"iceDef","battleValue":[1,10]},
{"id":12,"type":1,"effectAttribute":"lightDef","battleValue":[1,10]},
{"id":13,"type":1,"effectAttribute":"shadowDef","battleValue":[1,10]},
{"id":20,"type":2,"effectAttribute":"critRate","battleValue":[1,10]},
{"id":21,"type":2,"effectAttribute":"critDamageRate","battleValue":[1,10]},
{"id":22,"type":2,"effectAttribute":"atkSpeedRate","battleValue":[1,10]},
{"id":23,"type":2,"effectAttribute":"cdRate","battleValue":[1,10]},
{"id":24,"type":2,"effectAttribute":"hpRate","battleValue":[1,10]},
{"id":25,"type":1,"effectAttribute":"mpBonus","battleValue":[1,10]},
{"id":26,"type":2,"effectAttribute":"mpReduceRate","battleValue":[1,10]},
{"id":27,"type":1,"effectAttribute":"mpRecoverBonus","battleValue":[1,10]},
{"id":28,"type":2,"effectAttribute":"vampireRate","battleValue":[1,10]},
{"id":29,"type":2,"effectAttribute":"coinBonus","battleValue":[1,10]},
{"id":50,"type":1,"effectAttribute":"wearNumber","battleValue":[1,10]},
{"id":51,"type":1,"effectAttribute":"skillNumber","battleValue":[1,10]},
{"id":52,"type":1,"effectAttribute":"extraAttributeNumber","battleValue":[1,10]},

View File

@ -0,0 +1,12 @@
[
{"id":20,"value":[10,20]},
{"id":21,"value":[10,20]},
{"id":22,"value":[10,20]},
{"id":23,"value":[10,20]},
{"id":24,"value":[10,20]},
{"id":25,"value":[10,20]},
{"id":26,"value":[10,20]},
{"id":27,"value":[10,20]},
{"id":28,"value":[10,20]},
{"id":29,"value":[10,20]}
]

View File

@ -57,5 +57,7 @@
{"id":13103,"type":4,"typeArgs":[],"quality":4,"iconId":64,"nameId":23103,"textId":33103,"buyPrice":[11,40],"sellPrice":[11,40],"use":[],"showPackage":null},
{"id":13104,"type":4,"typeArgs":[],"quality":5,"iconId":65,"nameId":23104,"textId":33104,"buyPrice":[11,50],"sellPrice":[11,50],"use":[],"showPackage":null},
{"id":13105,"type":4,"typeArgs":[],"quality":6,"iconId":66,"nameId":23105,"textId":33105,"buyPrice":[11,60],"sellPrice":[11,60],"use":[],"showPackage":null},
{"id":13106,"type":4,"typeArgs":[],"quality":7,"iconId":67,"nameId":23106,"textId":33106,"buyPrice":[11,70],"sellPrice":[11,70],"use":[],"showPackage":null}
{"id":13106,"type":4,"typeArgs":[],"quality":7,"iconId":67,"nameId":23106,"textId":33106,"buyPrice":[11,70],"sellPrice":[11,70],"use":[],"showPackage":null},
{"id":20000,"type":5,"typeArgs":[],"quality":1,"iconId":1,"nameId":30000,"textId":40000,"buyPrice":[],"sellPrice":[],"use":[],"showPackage":null},
{"id":30000,"type":6,"typeArgs":[],"quality":1,"iconId":2,"nameId":40000,"textId":50000,"buyPrice":[],"sellPrice":[],"use":[],"showPackage":null}
]

View File

@ -68,6 +68,33 @@ function Utils:GetIdDataFromJson(JsonData: table, id: number)
return nil -- 没有找到对应id
end
-- 获取随机idExceptIdList为可选参数如果传入则排除ExceptIdList中的id
function Utils:GetRandomIdFromJson(JsonData: table, ExceptIdList: table?)
local rng = Random.new()
local randomId = rng:NextInteger(1, #JsonData)
while ExceptIdList and table.find(ExceptIdList, randomId) do
randomId = rng:NextInteger(1, #JsonData)
end
return randomId
end
-- 获取随机idExceptIdList为可选参数如果传入则排除ExceptIdList中的id
function Utils:GetRandomIdFromJsonWithType(JsonData: table, Type: number, ExceptIdList: table?)
local result = {}
for _, item in ipairs(JsonData) do
if item.type == Type then
table.insert(result, item.id)
end
end
local rng = Random.new()
local randomId = rng:NextInteger(1, #result)
while ExceptIdList and table.find(ExceptIdList, randomId) do
randomId = rng:NextInteger(1, #result)
end
return randomId
end
function Utils:GetMaxIdFromJson(JsonData: table)
local maxId = 0
for _, item in ipairs(JsonData) do
@ -111,6 +138,7 @@ function Utils:CreateDataInstance(Player: Player, UniqueId: number, EquipmentDat
end
local Config = Instance.new("Configuration")
Config.Name = UniqueId
-- TODO: 子表数据也要处理
Utils:SetAttributesList(Config, EquipmentData)
Config.Parent = Folder
return Config
@ -125,6 +153,18 @@ function Utils:CopyTable(t: table)
return newTable
end
-- 深度复制表
function Utils:DeepCopyTable(t: table)
local newTable = {}
for k, v in pairs(t) do
if type(v) == "table" then
newTable[k] = self:DeepCopyTable(v)
else
newTable[k] = v
end
end
return newTable
end
--------------------------------------------------------------------------------
return Utils

View File

@ -0,0 +1,238 @@
-- 玩家通用信息
local AbilityProxy = {}
--> Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Variables
local Utils = require(ReplicatedStorage.Tools.Utils)
local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy)
--> Json
local JsonAbility = require(ReplicatedStorage.Json.Ability)
--> Events
local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip
local RE_UpgradeAttributes = ReplicatedStorage.Events.RE_UpgradeAttributes
--> Constants
local STORE_NAME = "Ability"
--------------------------------------------------------------------------------
-- 获取玩家信息文件夹
local function GetPlayerAbilityFolder(Player: Player)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
local AbilityFolder = pData:FindFirstChild("Ability")
return AbilityFolder
end
--------------------------------------------------------------------------------
-- 初始化玩家
function AbilityProxy:InitPlayer(Player: Player)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
local AbilityFolder = Utils:CreateFolder("Ability", pData)
-- 新玩家数据初始化
if not ArchiveProxy.pData[Player.UserId][STORE_NAME] then
ArchiveProxy.pData[Player.UserId][STORE_NAME] = {}
ArchiveProxy.pData[Player.UserId][STORE_NAME].Ability = {}
end
-- 创建玩家信息实例
for AbilityUniqueId, AbilityData in ArchiveProxy.pData[Player.UserId][STORE_NAME].Ability do
Utils:CreateDataInstance(Player, AbilityUniqueId, AbilityData, AbilityFolder)
end
end
--------------------------------------------------------------------------------
-- 添加技能
local EXCEPT_KEYS = {"id"}
function AbilityProxy:AddAbility(Player: Player, AbilityId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
local AbilityData = Utils:GetIdDataFromJson(JsonAbility, AbilityId)
if not AbilityData then return end
local UniqueId = Utils:GenUniqueId(ArchiveProxy.pData[Player.UserId])
-- 配置表内容
local ResultData = {}
for key, value in pairs(AbilityData) do
if not table.find(EXCEPT_KEYS, key) then
ResultData[key] = value
end
end
ResultData.id = UniqueId
ResultData.orgId = AbilityId
ResultData.level = 1
-- 记录穿戴的装备UniqueId
ResultData.wearing = 0
ArchiveProxy.pData[Player.UserId][UniqueId] = ResultData
local AbilityInstance = Utils:CreateDataInstance(Player, UniqueId, ResultData, GetPlayerAbilityFolder(Player))
return Utils:DeepCopyTable(ResultData), AbilityInstance
end
-- 升级技能
function AbilityProxy:UpgradeAbility(Player: Player, UniqueId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
-- 获取技能实例存储数据
local UniqueData = ArchiveProxy.pData[Player.UserId][UniqueId]
if not UniqueData then return end
-- 获取技能数据
local AbilityData = Utils:GetIdDataFromJson(JsonAbility, UniqueData.orgId)
if not AbilityData then warn('技能数据不存在: ' , Player.Name, UniqueId) return end
-- 检查是否有技能实例
local AbilityInstance = GetPlayerAbilityFolder(Player):FindFirstChild(UniqueId)
if not AbilityInstance then warn('技能实例不存在: ' , Player.Name, UniqueId) return end
-- 检查是否有充足的技能碎片
local shouldCost = AbilityData.upgradeCost[2] + AbilityData.upgradeCost[3] * (AbilityData.level - 1)
if not Utils:CheckPlayerHasEnoughItem(Player, AbilityData.upgradeCost[1], shouldCost) then
RE_PlayerTip:FireClient(Player, "技能不足")
return
end
-- 扣除技能碎片
Utils:RemoveItem(Player, AbilityData.upgradeCost[1], shouldCost)
-- 升级
AbilityData.level = AbilityData.level + 1
AbilityInstance:SetAttribute("Level", AbilityData.level)
end
-- 回收技能
function AbilityProxy:RecycleAbility(Player: Player, UniqueId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
-- 获取技能实例存储数据
local UniqueData = ArchiveProxy.pData[Player.UserId][UniqueId]
if not UniqueData then return end
-- 获取技能数据
local AbilityData = Utils:GetIdDataFromJson(JsonAbility, UniqueData.orgId)
if not AbilityData then warn('技能数据不存在: ' , Player.Name, UniqueId) return end
-- 检查是否有技能实例
local AbilityInstance = GetPlayerAbilityFolder(Player):FindFirstChild(UniqueId)
if not AbilityInstance then warn('技能实例不存在: ' , Player.Name, UniqueId) return end
-- 计算升级一共消耗多少材料
local upgradeTotalCost = AbilityData.upgradeCost[2] + AbilityData.upgradeCost[3] * (AbilityData.level - 1)
-- 回收材料
Utils:AddItem(Player, AbilityData.upgradeCost[1], upgradeTotalCost)
-- 销毁
AbilityInstance:Destroy()
ArchiveProxy.pData[Player.UserId][UniqueId] = nil
end
-- 穿戴技能
function AbilityProxy:WearAbility(Player: Player, AbilityUniqueId: number, EquipmentUniqueId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
-- 获取技能实例存储数据
local UniqueData = ArchiveProxy.pData[Player.UserId][AbilityUniqueId]
if not UniqueData then return end
-- 获取装备实例存储数据
local EquipmentData = ArchiveProxy.pData[Player.UserId][EquipmentUniqueId]
if not EquipmentData then return end
-- 检查是否有技能实例
local AbilityInstance = GetPlayerAbilityFolder(Player):FindFirstChild(AbilityUniqueId)
if not AbilityInstance then warn('技能实例不存在: ' , Player.Name, AbilityUniqueId) return end
-- 获取装备数据
local EquipmentProxy = require(ServerStorage.Proxy.EquipmentProxy)
local EquipmentData = EquipmentProxy:GetEquipmentData(Player, EquipmentUniqueId)
-- 遍历技能查看现在穿了几个
local wearingCount = 0
for _, AbilityData in ArchiveProxy.pData[Player.UserId] do
if AbilityData.wearing == EquipmentUniqueId then
wearingCount = wearingCount + 1
end
end
-- TODO: 获取这个装备最多穿几个技能,穿戴数量>=穿戴上限就返回
-- 穿戴技能
UniqueData.wearing = EquipmentUniqueId
AbilityInstance:SetAttribute("Wearing", EquipmentUniqueId)
end
-- 获取技能等级数值(对应技能调用这个函数获取数值)
function AbilityProxy:GetAbilityLevelValue(Player: Player, UniqueId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
-- 获取技能实例存储数据
local UniqueData = ArchiveProxy.pData[Player.UserId][UniqueId]
if not UniqueData then return end
-- 获取技能数据
local AbilityData = Utils:GetIdDataFromJson(JsonAbility, UniqueData.orgId)
if not AbilityData then warn('技能数据不存在: ' , Player.Name, UniqueId) return end
-- 获取技能等级数值
local upgradeValue = AbilityData.upgradeValue[1] + AbilityData.upgradeValue[2] * (UniqueData.level - 1)
return upgradeValue
end
-- 获取随机技能id
function AbilityProxy:GetRandomAbilityId(ExceptIdList: table)
ExceptIdList = ExceptIdList or {}
local candidateIds = {}
for _, ability in ipairs(JsonAbility) do
local id = ability.id
if not table.find(ExceptIdList, id) then
table.insert(candidateIds, id)
end
end
if #candidateIds == 0 then
return nil -- 没有可用技能
end
local rng = Random.new()
local idx = rng:NextInteger(1, #candidateIds)
return candidateIds[idx]
end
--------------------------------------------------------------------------------
-- 获取技能属性
function AbilityProxy:GetPlayerAbilityWearingAttributes(Player: Player)
-- TODO暂时没有之后如果技能附带属性值时再加
end
-- 获取玩家属性
function AbilityProxy:GetPlayerAttributes(Player: Player)
local attributesList = {}
attributesList.AbilityWearingAttributes = self:GetPlayerAbilityWearingAttributes(Player)
return attributesList
end
--------------------------------------------------------------------------------
function AbilityProxy:OnPlayerRemoving(Player: Player)
end
ReplicatedStorage.Remotes.PlayerRemoving.Event:Connect(function(Player: Player)
AbilityProxy:OnPlayerRemoving(Player)
end)
return AbilityProxy

View File

@ -12,6 +12,8 @@ local PlayerInfoProxy = require(ServerStorage.Proxy.PlayerInfoProxy)
--> Json
local JsonEquipment = require(ReplicatedStorage.Json.Equipment)
local JsonAttributes = require(ReplicatedStorage.Json.Attributes)
local JsonExAttributes = require(ReplicatedStorage.Json.ExAttributes)
--> Constants
local STORE_NAME = "Equipment"
@ -70,7 +72,96 @@ function EquipmentProxy:AddEquipment(Player: Player, EquipmentId: number)
ResultData.wearing = 0
-- TODO: 其他随机词条内容添加在下面
-- TODO: 之后回收修改随机生成
-- 随机生成额外属性数量
local rng = Random.new()
local maxExAttributeNumber = PlayerInfoProxy:GetPlayerInfo(Player).exAttributeNumber or 0
local exAttributeNumber = rng:NextInteger(0, maxExAttributeNumber)
ResultData.maxExAttributeNumber = exAttributeNumber
ResultData.exAttributes = {}
if exAttributeNumber > 0 then
local spawnExAttributesId = {}
for i = 1, exAttributeNumber do
local newExAttributeId = Utils:GetRandomIdFromJsonWithType(JsonExAttributes, 1, spawnExAttributesId)
table.insert(spawnExAttributesId, newExAttributeId)
local ExAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newExAttributeId)
local randomExAttributeValue = rng:NextInteger(ExAttributeData.randomValue[1], ExAttributeData.randomValue[2])
local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, newExAttributeId)
ResultData.exAttributes[AttributeData.name] = randomExAttributeValue
end
end
-- 随机生成元素属性数量(暂时跟额外属性相同,之后可以改逻辑)
local maxElementNumber = PlayerInfoProxy:GetPlayerInfo(Player).elementNumber or 0
local elementNumber = rng:NextInteger(0, maxElementNumber)
ResultData.maxElementNumber = elementNumber
ResultData.elements = {}
if elementNumber > 0 then
local spawnElementsId = {}
for i = 1, elementNumber do
local newElementAttributeId = Utils:GetRandomIdFromJsonWithType(JsonExAttributes, 1, spawnElementsId)
table.insert(spawnElementsId, newElementAttributeId)
local ElementAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newElementAttributeId)
local randomElementAttributeValue = rng:NextInteger(ElementAttributeData.randomValue[1], ElementAttributeData.randomValue[2])
local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, newElementAttributeId)
ResultData.elements[AttributeData.name] = randomElementAttributeValue
end
end
-- 随机生成元素抗性数量
local maxElementDefNumber = PlayerInfoProxy:GetPlayerInfo(Player).elementDefNumber or 0
local elementDefNumber = rng:NextInteger(0, maxElementDefNumber)
ResultData.maxElementDefNumber = elementDefNumber
ResultData.elementDef = {}
if elementDefNumber > 0 then
local spawnElementDefId = {}
for i = 1, elementDefNumber do
local newElementDefId = Utils:GetRandomIdFromJsonWithType(JsonExAttributes, 1, spawnElementDefId)
table.insert(spawnElementDefId, newElementDefId)
local ElementDefAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newElementDefId)
local randomElementDefAttributeValue = rng:NextInteger(ElementDefAttributeData.randomValue[1], ElementDefAttributeData.randomValue[2])
local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, newElementDefId)
ResultData.elementDef[AttributeData.name] = randomElementDefAttributeValue
end
end
-- 随机生成技能槽位数量
local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy)
local maxAbilityNumber = PlayerInfoProxy:GetPlayerInfo(Player).abilityNumber or 0
local abilityNumber = rng:NextInteger(0, maxAbilityNumber)
ResultData.maxAbilityNumber = abilityNumber
if abilityNumber > 0 then
local spawnAbilitiesId = {}
for i = 1, abilityNumber do
local newAbilityId = AbilityProxy:GetRandomAbilityId(spawnAbilitiesId)
table.insert(spawnAbilitiesId, newAbilityId)
local newAbilityData, newAbilityInstance = AbilityProxy:AddAbility(Player, newAbilityId)
AbilityProxy:WearAbility(Player, newAbilityData.id, UniqueId)
end
end
-- 随机生成宝石数量
local GemProxy = require(ServerStorage.Proxy.GemProxy)
local maxGemNumber = PlayerInfoProxy:GetPlayerInfo(Player).gemNumber or 0
local gemNumber = rng:NextInteger(0, maxGemNumber)
ResultData.maxGemNumber = gemNumber
if gemNumber > 0 then
local spawnGemsId = {}
for i = 1, gemNumber do
local newGemId = GemProxy:GetRandomGemId(spawnGemsId)
table.insert(spawnGemsId, newGemId)
local newGemData, newGemInstance = GemProxy:AddGem(Player, newGemId)
GemProxy:WearGem(Player, newGemData.id, UniqueId)
end
end
------------------------------------------------------------
@ -86,6 +177,8 @@ function EquipmentProxy:RecycleEquipment(Player: Player, EquipmentId: number)
local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId]
if not EquipmentData then return end
-- TODO根据对应功能模块生成对应技能
-- 回收装备返回金币
PlayerInfoProxy:ChangeItem(Player, 1, EquipmentData.recycle)

View File

@ -55,7 +55,6 @@ end
-- 添加宝石
local EXCEPT_KEYS = {"id", "orgId", "iconId"}
function GemProxy:AddGem(Player: Player, GemId: number)
local pData = Utils:GetPlayerDataFolder(Player)
if not pData then return end
@ -165,6 +164,38 @@ function GemProxy:WearGem(Player: Player, GemUniqueId: number, EquipmentUniqueId
GemInstance:SetAttribute("Wearing", EquipmentUniqueId)
end
-- 卸下宝石
function GemProxy:UnwearGem(Player: Player, GemUniqueId: number)
local GemData = ArchiveProxy.pData[Player.UserId][GemUniqueId]
if not GemData then warn('无法获取宝石数据: ' , Player.Name, GemUniqueId) return end
-- 检查是否有宝石实例
local GemInstance = GetPlayerGemFolder(Player):FindFirstChild(GemUniqueId)
if not GemInstance then warn('宝石实例不存在: ' , Player.Name, GemUniqueId) return end
-- 卸下
GemData.wearing = 0
GemInstance:SetAttribute("Wearing", 0)
end
-- 获取随机技能id
function GemProxy:GetRandomGemId(ExceptIdList: table)
ExceptIdList = ExceptIdList or {}
local candidateIds = {}
for _, gem in ipairs(JsonGem) do
local id = gem.id
if not table.find(ExceptIdList, id) then
table.insert(candidateIds, id)
end
end
if #candidateIds == 0 then
return nil -- 没有可用技能
end
local rng = Random.new()
local idx = rng:NextInteger(1, #candidateIds)
return candidateIds[idx]
end
--------------------------------------------------------------------------------
-- 获取升级加点属性

View File

@ -111,6 +111,13 @@ function PlayerInfoProxy:InitPlayer(Player: Player)
end
end
-- 获取玩家信息
function PlayerInfoProxy:GetPlayerInfo(Player: Player)
if not Player then warn('获取玩家信息失败: ', Player.Name) return end
local playerInfoData = Utils:DeepCopyTable(ArchiveProxy.pData[Player.UserId][STORE_NAME])
return playerInfoData
end
-- 玩家属性升级
function PlayerInfoProxy:UpgradeAttribute(Player: Player, AttributeId: number)
if not Player or not AttributeId then warn('升级属性失败: ', Player.Name, AttributeId) return end