-- 装备代理 local EquipmentProxy = {} --> Services local ReplicatedStorage = game:GetService("ReplicatedStorage") local ServerStorage = game:GetService("ServerStorage") --> Variables local Utils = require(ReplicatedStorage.Tools.Utils) local Rng = require(ReplicatedStorage.Tools.Rng) local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy) local PlayerInfoProxy = require(ServerStorage.Proxy.PlayerInfoProxy) local PlayerFightProxy = require(ServerStorage.Proxy.PlayerFightProxy) local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy) local RuneProxy = require(ServerStorage.Proxy.RuneProxy) --> Json local JsonEquipment = require(ReplicatedStorage.Json.Equipment) local JsonAttributes = require(ReplicatedStorage.Json.Attributes) local JsonExAttributes = require(ReplicatedStorage.Json.ExAttributes) local JsonParam = require(ReplicatedStorage.Json.Param) local JsonBlessing = require(ReplicatedStorage.Json.Blessing) local JsonForge = require(ReplicatedStorage.Json.Forge) local JsonQualityEffect = require(ReplicatedStorage.Json.QualityEffect) --> Events local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip local RE_WearEquipment = ReplicatedStorage.Events.RE_WearEquipment local RE_RecycleEquipment = ReplicatedStorage.Events.RE_RecycleEquipment --> Constants local STORE_NAME = "Equipment" -------------------------------------------------------------------------------- -- 获取装备文件夹 local function GetPlayerEquipmentFolder(Player: Player) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end local EquipmentFolder = pData:FindFirstChild("Equipment") return EquipmentFolder end -- 计算词条等级加成上限 local function GetEntryLvBonus(PlayerLv: number, BonusData: table) local bonus = math.floor(PlayerLv / BonusData[1]) * BonusData[2] return math.min(bonus, BonusData[3]) end -- 改变装备数据 local function ChangeValue(Player: Player, EquipmentUniqueId: number, KeyName: string, Value: any) if not Player or not EquipmentUniqueId or not KeyName then warn("EquipmentProxy ChangeValue", Player.UserId, EquipmentUniqueId, KeyName, Value) return end local ValueInstance = GetPlayerEquipmentFolder(Player):FindFirstChild(EquipmentUniqueId) if not ValueInstance then warn("ValueInstance not found", KeyName) return end ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentUniqueId][KeyName] = Value ValueInstance:SetAttribute(KeyName, Value) end -------------------------------------------------------------------------------- -- 初始化玩家 function EquipmentProxy:InitPlayer(Player: Player) local pData = Utils:WaitPlayerDataFolder(Player) if not pData then return end Utils:CreateFolder("Equipment", pData) -- 新玩家数据初始化 if not ArchiveProxy.pData[Player.UserId][STORE_NAME] then ArchiveProxy.pData[Player.UserId][STORE_NAME] = {} end -- 初始化装备 for uniqueId, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do local config = Utils:CreateDataInstance(Player, tostring(uniqueId), EquipmentData, GetPlayerEquipmentFolder(Player)) end end -- 一些特殊记录或者不用记录的Key local EXCEPT_KEYS = { "id", "orgId", "name", "attributes"} -- 添加装备到背包 function EquipmentProxy:AddEquipment(Player: Player, EquipmentId: number) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end local EquipmentData = Utils:GetIdDataFromJson(JsonEquipment, EquipmentId) if not EquipmentData then return end local UniqueId = Utils:GenUniqueIdString(ArchiveProxy.pData[Player.UserId][STORE_NAME]) -- 配置表内容 local ResultData = {} for key, value in pairs(EquipmentData) do if not table.find(EXCEPT_KEYS, key) then ResultData[key] = value end end ResultData.id = UniqueId ResultData.orgId = EquipmentId -- 到时候记录穿戴槽位 ResultData.wearing = 0 -- 随机生成总变量 local rng = Random.new() local PlayerLevel = PlayerInfoProxy:GetPlayerLevel(Player) -- TODO: 之后这里可能根据等级限制权重 -- 获取锻造等级 local forgeTime = PlayerInfoProxy:GetForgeTime(Player) local maxForgeTime = Utils:GetMaxIdFromJson(JsonForge) -- 当前锻造次数限制 if forgeTime <= 0 then forgeTime = 1 end if forgeTime > maxForgeTime then forgeTime = maxForgeTime end -- 根据锻造等级获取品质权重 local qualityWeightTable = Utils:GetIdDataFromJson(JsonForge, forgeTime).qualityRate local quality = Rng:GetRandomWeightedIndex(qualityWeightTable) local qualityEffectData = Utils:GetIdDataFromJson(JsonQualityEffect, quality) -- 旧的固定值已经废弃 -- local qualityParam = Utils:GetIdDataFromJson(JsonParam, 1).intArray ResultData.quality = quality -- 生成装备基础词条(固定的) ResultData.attributes = {} for i = 1, #EquipmentData.attributes, 3 do local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, EquipmentData.attributes[i]) local baseLvValue = EquipmentData.attributes[i + 1] + EquipmentData.attributes[i + 2] * (PlayerLevel - 1) local qualityEffectValue -- 攻击速度词条特殊处理 if AttributeData.effectAttribute == "atkSpeed" then qualityEffectValue = baseLvValue else qualityEffectValue = math.floor(baseLvValue * (Rng:GetRandomInt(qualityEffectData.minValue, qualityEffectData.maxValue) / 100)) end ResultData.attributes[AttributeData.effectAttribute] = qualityEffectValue end -- TODO: 其他随机词条内容添加在下面 -- 随机生成额外属性数量 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:GetRandomIdFromJsonWithSpecialKey(JsonExAttributes, "specialType", 1, spawnExAttributesId) table.insert(spawnExAttributesId, newExAttributeId) local ExAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newExAttributeId) local minValue = ExAttributeData.randomValue[1] local maxValue = ExAttributeData.randomValue[2] + GetEntryLvBonus(PlayerLevel, ExAttributeData.bonus) local randomExAttributeValue = rng:NextInteger(minValue, maxValue) 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:GetRandomIdFromJsonWithSpecialKey(JsonExAttributes, "specialType", 2, spawnElementsId) table.insert(spawnElementsId, newElementAttributeId) local ElementAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newElementAttributeId) local minValue = ElementAttributeData.randomValue[1] local maxValue = ElementAttributeData.randomValue[2] + GetEntryLvBonus(PlayerLevel, ElementAttributeData.bonus) local randomElementAttributeValue = rng:NextInteger(minValue, maxValue) 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:GetRandomIdFromJsonWithSpecialKey(JsonExAttributes, "specialType", 3, spawnElementDefId) table.insert(spawnElementDefId, newElementDefId) local ElementDefAttributeData = Utils:GetIdDataFromJson(JsonExAttributes, newElementDefId) local minValue = ElementDefAttributeData.randomValue[1] local maxValue = ElementDefAttributeData.randomValue[2] + GetEntryLvBonus(PlayerLevel, ElementDefAttributeData.bonus) local randomElementDefAttributeValue = rng:NextInteger(minValue, maxValue) local AttributeData = Utils:GetIdDataFromJson(JsonAttributes, newElementDefId) ResultData.elementDef[AttributeData.name] = randomElementDefAttributeValue end end -- 祝福变量记录 local BookProxy = require(ServerStorage.Proxy.BookProxy) local blessingId, blessingRate = BookProxy:GetBlessingInfo(Player, EquipmentId) local blessingType, blessingEffect local blessingTableName local isNotTrigger = true if blessingId then local blessingData = Utils:GetIdDataFromJson(JsonBlessing, blessingId) blessingType = blessingData.type blessingEffect = blessingData.effect end -- 属性祝福处理 if blessingType == 1 then -- 找到对应祝福所属的表名 local attributeData = Utils:GetIdDataFromJson(JsonAttributes, blessingEffect) if attributeData.specialType then if attributeData.specialType == 1 then blessingTableName = "exAttributes" elseif attributeData.specialType == 2 then blessingTableName = "elements" elseif attributeData.specialType == 3 then blessingTableName = "elementDef" end end -- 如果表名存在,进行下一步处理 if blessingTableName then -- 不存在该属性时,且有其他属性时 if not ResultData[blessingTableName][attributeData.effectAttribute] and #ResultData[blessingTableName] > 0 then -- 随机替换功能是否触发 local isTrigger = Rng:GetRandomInt(1, 100) <= blessingRate if isTrigger and isNotTrigger then -- 将第一个属性替换为祝福属性,保留对应的随机值,只替换属性名 local oldAttributeValue for key, value in ResultData[blessingTableName] do oldAttributeValue = value ResultData[blessingTableName][key] = nil break end ResultData[blessingTableName][attributeData.effectAttribute] = oldAttributeValue isNotTrigger = false end end end end ------------------------------------------------------------ -- 随机生成技能槽位数量 local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy) local maxAbilityNumber = PlayerInfoProxy:GetPlayerInfo(Player)["AttributesUpgrade"]["11"] or 0 local abilityNumber = rng:NextInteger(0, maxAbilityNumber) ResultData.maxAbilityNumber = abilityNumber -- 随机生成宝石数量 local GemProxy = require(ServerStorage.Proxy.GemProxy) local maxGemNumber = PlayerInfoProxy:GetPlayerInfo(Player).gemNumber or 0 local gemNumber = rng:NextInteger(0, maxGemNumber) ResultData.maxGemNumber = gemNumber -- 随机生成符文数量 local RuneProxy = require(ServerStorage.Proxy.RuneProxy) local maxRuneNumber = PlayerInfoProxy:GetPlayerInfo(Player)["AttributesUpgrade"]["15"] or 0 local runeNumber = rng:NextInteger(0, maxRuneNumber) ResultData.maxRuneNumber = runeNumber ------------------------------------------------------------ ArchiveProxy.pData[Player.UserId][STORE_NAME][UniqueId] = ResultData local equipmentInstance = Utils:CreateDataInstance(Player, UniqueId, ResultData, GetPlayerEquipmentFolder(Player)) print("生成装备符文孔数", equipmentInstance.Name, runeNumber, maxRuneNumber) ------------------------------------------------------------ -- 下面逻辑会找Instance实例,所以放在之后执行逻辑 if abilityNumber > 0 then local spawnAbilitiesId = {} for i = 1, abilityNumber do -- 技能祝福处理 local specialAbilityId if blessingType == 2 and isNotTrigger then -- 没触发过,中了概率就指定技能id local isTrigger = Rng:GetRandomInt(1, 100) <= blessingRate if isTrigger then specialAbilityId = blessingEffect isNotTrigger = false end end local newAbilityId = specialAbilityId or AbilityProxy:GetRandomAbilityId(spawnAbilitiesId) table.insert(spawnAbilitiesId, newAbilityId) local newAbilityData, newAbilityInstance = AbilityProxy:AddAbility(Player, newAbilityId) AbilityProxy:WearAbility(Player, newAbilityData.id, UniqueId) end end 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 if runeNumber > 0 then local spawnRunesId = {} -- 符文祝福处理 local blessingTrigger = false local blessingRuneId if blessingType == 3 and not blessingTrigger then -- 没触发过,中了概率就指定符文id local isTrigger = Rng:RandomPercent(blessingRate) if isTrigger then blessingTrigger = true blessingRuneId = blessingEffect end end for i = 1, runeNumber do -- 是否生成符文 local isTrigger = Rng:GetRandomInt(1, 100) <= 5 if isTrigger or blessingTrigger then -- 随机生成符文,如果祝福触发,就指定符文id local newRuneId = blessingRuneId or RuneProxy:GetRandomRuneId(spawnRunesId) table.insert(spawnRunesId, newRuneId) local newRuneData, newRuneInstance = RuneProxy:AddRune(Player, newRuneId) RuneProxy:WearRune(Player, newRuneData.id, UniqueId) -- 重置祝福状态(触发1次,就停止了) if blessingTrigger then blessingTrigger = false blessingRuneId = nil end end end end ------------------------------------------------------------ -- 添加图鉴记录 local BookProxy = require(ServerStorage.Proxy.BookProxy) BookProxy:AddBook(Player, EquipmentId, UniqueId) return equipmentInstance end -- 回收单件装备 function EquipmentProxy:RecycleEquipment(Player: Player, EquipmentId: number) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId] if not EquipmentData then return end -- 根据对应功能模块进行对应回收 local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy) -- AbilityProxy:RecycleAbility(Player, EquipmentData.id) local GemProxy = require(ServerStorage.Proxy.GemProxy) -- GemProxy:RecycleGem(Player, EquipmentData.id) -- 回收装备返回金币 -- 处理关卡金币产出加成和词条加成 local getNumber = EquipmentData.recycle local coinBonus = Player.Character:FindFirstChild("Attributes"):GetAttribute("coinBonus") if coinBonus then getNumber = math.floor(getNumber * (1 + coinBonus / 100)) end -- 返回金币 local rewardData = {["1"] = getNumber} PlayerInfoProxy:ChangeItemCount(Player, 1, getNumber) ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId] = nil local EquipmentInstance = GetPlayerEquipmentFolder(Player):FindFirstChild(EquipmentId) if EquipmentInstance then EquipmentInstance:Destroy() end return rewardData end -- 批量回收装备 function EquipmentProxy:RecycleEquipmentList(Player: Player, EquipmentUniqueIds: table) local rewardData = {} for _, EquipmentUniqueId in EquipmentUniqueIds do local newRewardData = EquipmentProxy:RecycleEquipment(Player, EquipmentUniqueId) if newRewardData then Utils:TableSafeAddTableValue(rewardData, newRewardData) end end return rewardData end -- 穿戴装备 function EquipmentProxy:WearEquipment(Player: Player, EquipmentId: number, Slot: number) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end -- TODO :穿戴装备时再生成模型 -- 查看槽位数量是否超出 local PlayerInfoData = PlayerInfoProxy:GetPlayerInfo(Player) -- 没升级是没有键值对的,所以做了个括号简单判断 if Slot > (PlayerInfoData.AttributesUpgrade.wearingNumber or 1) then RE_PlayerTip:FireClient(Player, '穿戴装备槽位超出') return end -- 查看该槽位是否穿戴装备,穿戴就返回 for _, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do if EquipmentData.wearing == Slot then RE_PlayerTip:FireClient(Player, '该槽位已穿戴装备') return end end -- 穿戴装备 local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId] if not EquipmentData then return end ChangeValue(Player, EquipmentId, "wearing", Slot) -- 更新玩家数据 PlayerFightProxy:UpdatePlayerFightData(Player) -- 给前端的提示(模型穿戴) if Slot == 1 then RE_WearEquipment:FireClient(Player, true, EquipmentId, Slot) end end -- 卸下装备 function EquipmentProxy:UnwearEquipment(Player: Player, EquipmentId: number) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end -- 卸下装备 local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][EquipmentId] if not EquipmentData then return end -- 给前端的提示(模型卸下) if EquipmentData.wearing == 1 then RE_WearEquipment:FireClient(Player, false, EquipmentId, EquipmentData.wearing) end ChangeValue(Player, EquipmentId, "wearing", 0) -- 更新玩家数据 PlayerFightProxy:UpdatePlayerFightData(Player) end -- 获取穿戴中的装备UniqueId function EquipmentProxy:GetPlayerWearingEquipmentUniqueId(Player: Player) local wearingEquipmentUniqueId = {} -- 穿戴中的填入 for _, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do if EquipmentData.wearing > 0 then wearingEquipmentUniqueId[EquipmentData.wearing] = EquipmentData.id end end -- 补全空缺没填进去的槽位 local wearingNumber = PlayerInfoProxy:GetPlayerAttributesUpgrade(Player, "wearingNumber") if wearingNumber <= 0 then return wearingEquipmentUniqueId end for i = 1, wearingNumber do if not wearingEquipmentUniqueId[i] then wearingEquipmentUniqueId[i] = 0 end end return wearingEquipmentUniqueId end -- 获取装备属性(汇总,不进行最终属性计算) function EquipmentProxy:GetPlayerAttributes(Player: Player) local AttributesData = {} for _, EquipmentData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do if EquipmentData.wearing > 0 then -- 增加装备基础属性 for AttributeName, AttributeValue in EquipmentData.attributes do if AttributeName == "atkSpeed" then if EquipmentData.wearing == 1 then Utils:TableSafeAddValue(AttributesData, AttributeName, AttributeValue) end else Utils:TableSafeAddValue(AttributesData, AttributeName, AttributeValue) end end -- 增加装备额外属性 Utils:TableSafeAddTableValue(AttributesData, EquipmentData.exAttributes) -- 增加装备元素属性 Utils:TableSafeAddTableValue(AttributesData, EquipmentData.elements) -- 增加装备元素抗性 Utils:TableSafeAddTableValue(AttributesData, EquipmentData.elementDef) -- print("属性表", AttributesData) -- 计算特殊词条加成是否激活 if EquipmentData.specialType then local isActive = false -- 属性类型加成 if EquipmentData.specialType == 1 then local attributeData = Utils:GetIdDataFromJson(JsonAttributes, EquipmentData.specialRequire) -- 根据配置的id转换一下 if AttributesData[attributeData.effectAttribute] then isActive = true end -- 技能类型加成 elseif EquipmentData.specialType == 2 then local wearingAbilityUniqueId, wearingOrgId = AbilityProxy:GetPlayerAbilityByEquipmentUniqueId(Player, EquipmentData.id) if table.find(wearingOrgId, EquipmentData.specialRequire) then isActive = true end -- 晶石类型加成 elseif EquipmentData.specialType == 3 then local wearingRuneUniqueId, wearingOrgId = RuneProxy:GetPlayerRuneByEquipmentUniqueId(Player, EquipmentData.id) if table.find(wearingOrgId, EquipmentData.specialRequire) then isActive = true end end if isActive then local newAddAttribute = Utils:GetIdDataFromJson(JsonAttributes, EquipmentData.specialActive[1]) Utils:TableSafeAddValue(AttributesData, newAddAttribute.effectAttribute, EquipmentData.specialActive[2]) end end end end -- print("结果属性表", AttributesData) return AttributesData end -- 获取装备数据 function EquipmentProxy:GetEquipmentData(Player: Player, EquipmentUniqueId: number) local EquipmentData = ArchiveProxy.pData[Player.UserId][STORE_NAME][tostring(EquipmentUniqueId)] return EquipmentData end function EquipmentProxy:OnPlayerRemoving(Player: Player) end ReplicatedStorage.Remotes.PlayerRemoving.Event:Connect(function(PlayerUserId: string) EquipmentProxy:OnPlayerRemoving(PlayerUserId) end) RE_WearEquipment.OnServerEvent:Connect(function(Player: Player, EquipmentUniqueId: number, SlotId: number, Unwear: boolean?) if Unwear then EquipmentProxy:UnwearEquipment(Player, EquipmentUniqueId) else EquipmentProxy:WearEquipment(Player, EquipmentUniqueId, SlotId) end end) RE_RecycleEquipment.OnServerEvent:Connect(function(Player: Player, EquipmentUniqueIds: table) EquipmentProxy:RecycleEquipmentList(Player, EquipmentUniqueIds) end) return EquipmentProxy