diff --git a/excel/cha.xlsx b/excel/cha.xlsx index 5552c54..cb4048d 100644 Binary files a/excel/cha.xlsx and b/excel/cha.xlsx differ diff --git a/src/ReplicatedStorage/Json/AttributesUpgrade.json b/src/ReplicatedStorage/Json/AttributesUpgrade.json new file mode 100644 index 0000000..c8db73d --- /dev/null +++ b/src/ReplicatedStorage/Json/AttributesUpgrade.json @@ -0,0 +1,13 @@ +[ +{"id":1,"type":1,"effectAttribute":"attack","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, +{"id":2,"type":1,"effectAttribute":"hp","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, +{"id":3,"type":1,"effectAttribute":"swordAtk","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, +{"id":4,"type":1,"effectAttribute":"swordWearBase","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, +{"id":5,"type":1,"effectAttribute":"swordWearSpe","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, +{"id":10,"type":2,"effectAttribute":"wearNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":4}, +{"id":11,"type":2,"effectAttribute":"skillNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3}, +{"id":12,"type":2,"effectAttribute":"extraAttributeNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3}, +{"id":13,"type":2,"effectAttribute":"elementNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3}, +{"id":14,"type":2,"effectAttribute":"elementDefNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3}, +{"id":15,"type":2,"effectAttribute":"gemNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3} +] \ No newline at end of file diff --git a/src/ServerStorage/Base/Behaviour.luau b/src/ServerStorage/Base/Behaviour.luau index 509c7c7..f61b055 100644 --- a/src/ServerStorage/Base/Behaviour.luau +++ b/src/ServerStorage/Base/Behaviour.luau @@ -40,22 +40,21 @@ end -- 检查当前状态是否可执行 function Behaviour:CheckStat() - if not self.Character then warn("Behaviour Character not found") return false end + if not self.Character then return true end -- 死亡检查 - if self.Character:GetState("Died") then return false end + if self.Character:GetState("Died") then return true end -- 执行状态中检查 local ExecutingState = self.PlayerAI.ExecutingState -- 其他内容执行中,就false - if ExecutingState == true then return false end - return true + if ExecutingState == true then return true end + return false end -- 改变当前执行状态标记 function Behaviour:ChangeExecutingState(State: boolean) if not self.Character then warn("Behaviour Character not found") return end - local ExecutingState = self.PlayerAI.ExecutingState - ExecutingState.Value = State + self.PlayerAI.ExecutingState = State end -- 销毁 diff --git a/src/ServerStorage/Base/Character.luau b/src/ServerStorage/Base/Character.luau index f474012..8a10815 100644 --- a/src/ServerStorage/Base/Character.luau +++ b/src/ServerStorage/Base/Character.luau @@ -20,6 +20,7 @@ function Character.new(Player: Player, CharacterModel: Model, CharacterData: tab self.Root = HumanoidRootPart self.Humanoid = mobHumanoid self.Origin = HumanoidRootPart:GetPivot() + self.Player = Player self.TargetPlayerUserID = Player.UserId self.Connections = {} self.Stats = {} diff --git a/src/ServerStorage/Modules/Behaviours/Move.luau b/src/ServerStorage/Modules/Behaviours/Move.luau index 8e67214..e30f196 100644 --- a/src/ServerStorage/Modules/Behaviours/Move.luau +++ b/src/ServerStorage/Modules/Behaviours/Move.luau @@ -12,6 +12,7 @@ local MobsProxy = require(ServerStorage.Proxy.MobsProxy) local Move = {} Move.__index = Move +setmetatable(Move, {__index = Behaviour}) function Move:Init(PlayerAI, Character: TypeList.Character, Player: Player) local self = Behaviour:Init(PlayerAI, Character) @@ -24,7 +25,7 @@ function Move:Check(CheckInfo: table) if Behaviour.CheckStat(self) then return -1, self.CheckData end local PlayerMobs = MobsProxy:GetPlayerMobs(self.Player) - if not PlayerMobs then warn("PlayerMobs not found") return end + if not PlayerMobs then return end local closestMob, minDistance = nil, math.huge for _, Mob in PlayerMobs do @@ -50,7 +51,7 @@ end function Move:Execute() self.ExeTask = task.spawn(function () self:ChangeExecutingState(true) - self.Character.Humanoid.WalkToPart.CFrame = self.CheckData["ClosestCharacter"].Instance.PrimaryPart.CFrame + self.Character.Humanoid:MoveTo(self.CheckData["ClosestCharacter"].Instance:GetPivot().Position) task.wait(0.5) self:ChangeExecutingState(false) end) diff --git a/src/ServerStorage/Proxy/ArchiveProxy.luau b/src/ServerStorage/Proxy/ArchiveProxy.luau index 3b170d0..9a89920 100644 --- a/src/ServerStorage/Proxy/ArchiveProxy.luau +++ b/src/ServerStorage/Proxy/ArchiveProxy.luau @@ -31,6 +31,12 @@ function ArchiveProxy:IsPlayerDataLoaded(Player: Player) return true -- 成功加载 end +function ArchiveProxy:CleanPlayerData(Player: Player) + if not ArchiveProxy.pData[Player.UserId] then warn('CleanPlayerData: ', Player.Name, '数据不存在') return end + ArchiveProxy.pData[Player.UserId] = {} + print("清除数据成功") +end + -------------------------------------------------------------------------------- local PlayerData = Instance.new("Configuration") diff --git a/src/ServerStorage/Proxy/DamageProxy.luau b/src/ServerStorage/Proxy/DamageProxy.luau index 7c8bf0e..98e0c6c 100644 --- a/src/ServerStorage/Proxy/DamageProxy.luau +++ b/src/ServerStorage/Proxy/DamageProxy.luau @@ -57,6 +57,7 @@ function DamageProxy:TakeDamage(Caster: TypeList.Character, Victim: TypeList.Cha -- 伤害计算 local VictimHealth = Victim:GetAttributeValue("hp") Victim:ChangeAttributeValue("hp", math.max(0, VictimHealth - Damage)) + print("伤害数据打印", Damage, VictimHealth) end end diff --git a/src/ServerStorage/Proxy/HelpProxy.luau b/src/ServerStorage/Proxy/HelpProxy.luau new file mode 100644 index 0000000..8ee0dfa --- /dev/null +++ b/src/ServerStorage/Proxy/HelpProxy.luau @@ -0,0 +1,24 @@ +local HelpProxy = {} + +--> Server +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Events +local RE_PlayerHelper = ReplicatedStorage.Events.RE_PlayerHelper + +function HelpProxy:CleanPlayerData(Player: Player) + local ArchiveProxy = require(script.Parent.ArchiveProxy) + ArchiveProxy:CleanPlayerData(Player) +end + +RE_PlayerHelper.OnServerEvent:Connect(function(Player: Player, EventName: string, EventData: any) + if EventName == "CleanPlayerData" then + HelpProxy:CleanPlayerData(Player) + elseif EventName == "AddItem" then + local PlayerInfoProxy = require(script.Parent.PlayerInfoProxy) + PlayerInfoProxy:ChangeItemCount(Player, EventData[1], EventData[2]) + print("添加物品成功", PlayerInfoProxy:GetItemCount(Player, EventData[1])) + end +end) + +return HelpProxy \ No newline at end of file diff --git a/src/ServerStorage/Proxy/LevelProxy.luau b/src/ServerStorage/Proxy/LevelProxy.luau index 78bb243..c0e96e0 100644 --- a/src/ServerStorage/Proxy/LevelProxy.luau +++ b/src/ServerStorage/Proxy/LevelProxy.luau @@ -15,6 +15,9 @@ local TypeList = require(ServerStorage.Base.TypeList) --> Json local JsonLevel = require(ReplicatedStorage.Json.Level) +--> Events +local BD_ChallengeEnd = ReplicatedStorage.Events.BD_ChallengeEnd + --> Constants local STORE_NAME = "Level" local ENUM_LEVEL_TYPE = { @@ -84,7 +87,7 @@ end local function OnMobDied(Player: Player, Mob: TypeList.Character) for _, mob in LevelProxy.pData[Player.UserId].Mobs do if mob ~= Mob then continue end - table.remove(LevelProxy.pData[Player.UserId].Mobs, mob) + table.remove(LevelProxy.pData[Player.UserId].Mobs, table.find(LevelProxy.pData[Player.UserId].Mobs, mob)) -- 怪物清除判断 local LevelData = Utils:GetJsonData(JsonLevel, LevelProxy.pData[Player.UserId].LevelId) @@ -149,8 +152,6 @@ function LevelProxy:InitPlayer(Player: Player) if key == "Task" or key == "Mobs" then continue end CreateLevelInstance(Player, ChallengeFolder, key, value) end - - -- self:ChallengeLevel(Player, 1) end -- 挑战关卡(挑战副本用另一个函数) @@ -165,7 +166,7 @@ function LevelProxy:ChallengeLevel(Player: Player, LevelId: number) local LevelFolder = GetPlayerLevelWorkspaceFolder(Player.UserId) local ChallengeFolder = LevelFolder:FindFirstChild("Challenge") if not ChallengeFolder then warn("ChallengeFolder not found") return end - local levelTask = task.defer(function() + local levelTask = task.spawn(function() ChangeValue(Player, ChallengeFolder, "IsBoss", LevelData.type == 2 and true or false) ChangeValue(Player, ChallengeFolder, "LevelId", LevelId) ChangeValue(Player, ChallengeFolder, "Time", 0) @@ -218,7 +219,7 @@ function LevelProxy:ChallengeLevel(Player: Player, LevelId: number) end end end) - ChangeValue(Player, ChallengeFolder, "Task", levelTask) + LevelProxy.pData[Player.UserId].Task = levelTask end -- 挑战结束 @@ -226,8 +227,15 @@ function LevelProxy:ChallengeEnd(Player: Player, result: boolean) local pData = Utils:GetPlayerDataFolder(Player) local LevelFolder = Utils:CreateFolder(STORE_NAME, pData) local ProgressFolder = Utils:CreateFolder("Progress", LevelFolder) + + -- 停止关卡循环 + if LevelProxy.pData[Player.UserId].Task then + task.cancel(LevelProxy.pData[Player.UserId].Task) + LevelProxy.pData[Player.UserId].Task = nil + end + -- 清除剩余怪物 - for _, mob in LevelProxy.pData[Player.UserId].Mobs do mob:Died() end + for _, mob in LevelProxy.pData[Player.UserId].Mobs do mob:Died(true) end LevelProxy.pData[Player.UserId].Mobs = {} -- 判断玩家是否通关 @@ -239,6 +247,7 @@ function LevelProxy:ChallengeEnd(Player: Player, result: boolean) ChangeValue(Player, ProgressFolder, "BossFail", LevelProxy.pData[Player.UserId].LevelId) end end + BD_ChallengeEnd:Fire(Player, LevelProxy.pData[Player.UserId].LevelId, result) end function LevelProxy:OnPlayerRemoving(Player: Player) @@ -249,7 +258,7 @@ function LevelProxy:OnPlayerRemoving(Player: Player) end -- 关卡存储数据清除 if LevelProxy.pData[Player.UserId].Task then - LevelProxy.pData[Player.UserId].Task:Cancel() + task.cancel(LevelProxy.pData[Player.UserId].Task) end LevelProxy.pData[Player.UserId] = nil end diff --git a/src/ServerStorage/Proxy/MobsProxy/AI.luau b/src/ServerStorage/Proxy/MobsProxy/AI.luau index 35e4c1a..12fb314 100644 --- a/src/ServerStorage/Proxy/MobsProxy/AI.luau +++ b/src/ServerStorage/Proxy/MobsProxy/AI.luau @@ -20,33 +20,27 @@ function AI:GetModelDistance(Unit1: Model, Unit2: Model): number end function AI:GetClosestPlayer(Mob: TypeList.Character): (Player?, number?) - local Closest = {Player = nil, Magnitude = math.huge} + local Closest = {PlayerRole = nil, Magnitude = math.huge, Player = nil} - local ActivePlayer -- We retain a reference to this, so they have to get further away from the mob to stop following, instead of the usual distance. - if Mob.Humanoid.WalkToPart then - local Player = Players:GetPlayerFromCharacter(Mob.Humanoid.WalkToPart.Parent) - if Player then - ActivePlayer = Player - end - end - - -- 临时的 + local PlayerRole = Mob.PlayerRole + local Character = PlayerRole.Instance + if Character == nil then warn("AI:GetClosestPlayer Character not found", Mob.Name) return end + for _, Player in Players:GetPlayers() do if Mob.TargetPlayerUserID == Player.UserId then - local Character = Player.Character - if not Character then continue end - - local Magnitude = (Character:GetPivot().Position - Mob.Instance:GetPivot().Position).Magnitude - local MaxDistance = (ActivePlayer == Player and (Mob.Config.FollowDistance or 32) * 2) or Mob.Config.FollowDistance or 32 - - if Magnitude <= MaxDistance and Magnitude < Closest.Magnitude then - Closest.Player = Player - Closest.Magnitude = Magnitude - end + Closest.Player = Player end end + + local Magnitude = (Character:GetPivot().Position - Mob.Instance:GetPivot().Position).Magnitude + -- 最大距离暂时设置大值 + local MaxDistance = Mob.Config.FollowDistance or 10000 + if Magnitude <= MaxDistance and Magnitude < Closest.Magnitude then + Closest.PlayerRole = PlayerRole + Closest.Magnitude = Magnitude + end - return Closest.Player, Closest.Player and Closest.Magnitude + return Closest.Player, Closest.PlayerRole, Closest.PlayerRole and Closest.Magnitude end -- Adds the mob to the ActiveMobs table. This table runs a few times per second and updates follow & jump code for active mobs. @@ -66,7 +60,10 @@ task.defer(function() for MobInstance, Mob in ActiveMobs do task.spawn(function() if not Mob.Stats.Died then - local Player, distance = AI:GetClosestPlayer(Mob) + -- 执行其他内容就停止 + if Mob.ExecutingState then return end + + local Player, PlayerRole, distance = AI:GetClosestPlayer(Mob) local Enemy = Mob.Humanoid -- Simulation @@ -79,16 +76,22 @@ task.defer(function() end -- Tracking - if Player and Enemy then + if Player and Enemy and PlayerRole then + if PlayerRole.Stats.Died then return end if distance > 5 then Enemy:MoveTo(Player.Character:GetPivot().Position, Player.Character.PrimaryPart) else + Mob.ExecutingState = true -- 停止移动 Enemy:MoveTo(MobInstance:GetPivot().Position) -- 触发攻击逻辑 task.wait(Mob.Config.attackSpeed) + + -- 攻击间隔后再次判断状态 if Mob.Stats.Died then return end if not Player then return end + if PlayerRole.Stats.Died then return end + if AI:GetModelDistance(MobInstance, Player.Character) <= 5 then -- 调用伤害模块 DamageProxy:TakeDamage(Mob, Mob.PlayerRole, { @@ -99,6 +102,7 @@ task.defer(function() } }) end + Mob.ExecutingState = false end end else diff --git a/src/ServerStorage/Proxy/MobsProxy/init.luau b/src/ServerStorage/Proxy/MobsProxy/init.luau index 37d2899..c1b834a 100644 --- a/src/ServerStorage/Proxy/MobsProxy/init.luau +++ b/src/ServerStorage/Proxy/MobsProxy/init.luau @@ -62,6 +62,7 @@ function Mob.new(Player: Player, MobId: number, OnMobDied: ((Player: Player, Mob setmetatable(self, Mob) -- 继承Mob方法 local PlayerFightProxy = require(ServerStorage.Proxy.PlayerFightProxy) self.PlayerRole = PlayerFightProxy:GetPlayerRole(Player) + self.ExecutingState = false -- 放入关卡中 newMobModel.Parent = playerMobsFolder @@ -80,9 +81,11 @@ function Mob.new(Player: Player, MobId: number, OnMobDied: ((Player: Player, Mob return self end -function Mob:Died() +function Mob:Died(IsSkinOnDied: boolean?) MobsProxy:RemoveMob(self.Player, self.Instance) - if self.OnDied then self.OnDied(self.Player, self) end + if not IsSkinOnDied then + if self.OnDied then self.OnDied(self.Player, self) end + end Character.Died(self) end @@ -93,8 +96,8 @@ function MobsProxy:CreateMob(Player: Player, MobId: number, AtkBonus: number?, H local Mob = Mob.new(Player, MobId, OnMobDied) AI:StartTracking(Mob) -- 关卡系数 - -- if AtkBonus then Mob:ChangeAttributeValue("attack", math.floor(Mob.Config.attack * (AtkBonus / 1000))) end - -- if HpBonus then Mob:ChangeAttributeValue("hp", math.floor(Mob.Config.hp * (HpBonus / 1000))) end + if AtkBonus then Mob:ChangeAttributeValue("attack", math.floor(Mob.Config.attack * (AtkBonus / 1000))) end + if HpBonus then Mob:ChangeAttributeValue("hp", math.floor(Mob.Config.hp * (HpBonus / 1000))) end MobsProxy.pData[Player.UserId][Mob.Instance] = Mob return Mob end diff --git a/src/ServerStorage/Proxy/PlayerFightProxy/LevelLoop.luau b/src/ServerStorage/Proxy/PlayerFightProxy/LevelLoop.luau index 2542b06..2d739a5 100644 --- a/src/ServerStorage/Proxy/PlayerFightProxy/LevelLoop.luau +++ b/src/ServerStorage/Proxy/PlayerFightProxy/LevelLoop.luau @@ -20,12 +20,12 @@ local JsonLevel = require(ReplicatedStorage.Json.Level) local LevelLoop = {} LevelLoop.__index = LevelLoop -function LevelLoop.new(Player: Player, Character: TypeList.Character) +function LevelLoop.new(Player: Player, PlayerRole: TypeList.Character) print("LevelLoop:Init") local self = {} setmetatable(self, LevelLoop) self.Player = Player - self.Character = Character + self.PlayerRole = PlayerRole self.TaskAutoChallenge = nil self.ConChallengeEnd = BD_ChallengeEnd.Event:Connect(function(Player: Player, LevelId: number) @@ -38,7 +38,9 @@ function LevelLoop.new(Player: Player, Character: TypeList.Character) end function LevelLoop:AutoChallenge() - print("AutoChallenge") + -- 重置玩家状态(先临时调用角色复活,之后复杂的内容再说) + self.PlayerRole:Respawn() + local LevelFolder = game.Workspace:WaitForChild("Level"):WaitForChild(self.Player.UserId) local ProgressFolder = LevelFolder:FindFirstChild("Progress") @@ -51,7 +53,7 @@ function LevelLoop:AutoChallenge() LevelProxy:ChallengeLevel(self.Player, LevelId) end -function LevelLoop:OnChallengeEnd(Player: Player, LevelId: number) +function LevelLoop:OnChallengeEnd(Player: Player, LevelId: number, result: boolean) self.TaskAutoChallenge = task.defer(function() task.wait(3) self:AutoChallenge() diff --git a/src/ServerStorage/Proxy/PlayerFightProxy/PlayerAI.luau b/src/ServerStorage/Proxy/PlayerFightProxy/PlayerAI.luau index ba08f4c..1389610 100644 --- a/src/ServerStorage/Proxy/PlayerFightProxy/PlayerAI.luau +++ b/src/ServerStorage/Proxy/PlayerFightProxy/PlayerAI.luau @@ -5,10 +5,14 @@ PlayerAI.__index = PlayerAI --> Services local Players = game:GetService("Players") local ServerStorage = game:GetService("ServerStorage") +local ReplicatedStorage = game:GetService("ReplicatedStorage") --> Dependencies local TypeList = require(ServerStorage.Base.TypeList) +--> Events +local RE_PlayerAI = ReplicatedStorage.Events.RE_PlayerAI + --> Variables local DamageProxy = require(ServerStorage.Proxy.DamageProxy) local ActivePlayers = {} @@ -42,14 +46,21 @@ function PlayerAI.new(Player: Player, PlayerRole: TypeList.Character) self.Character = PlayerRole self.Player = Player self.ExecutingState = false + self.PlayerControling = false self.BehaviourList = {} self.LoopTask = task.spawn(function() while task.wait(0.25) do + if self.Character.Stats.Died then continue end + if self.PlayerControling then continue end self:Update() end end) + self.PlayerControlCon = RE_PlayerAI.OnServerEvent:Connect(function(Player: Player, ControlState: boolean) + if Player ~= self.Player then return end + self.PlayerControling = ControlState + end) return self end diff --git a/src/ServerStorage/Proxy/PlayerFightProxy/init.luau b/src/ServerStorage/Proxy/PlayerFightProxy/init.luau index 87a78aa..3be8a28 100644 --- a/src/ServerStorage/Proxy/PlayerFightProxy/init.luau +++ b/src/ServerStorage/Proxy/PlayerFightProxy/init.luau @@ -48,11 +48,13 @@ end function PlayerRole:Died() self:ChangeState("Died", true) + self.Humanoid.WalkSpeed = 0 LevelProxy:ChallengeEnd(self.Player, false) end function PlayerRole:Respawn() self:ChangeState("Died", false) + self.Humanoid.WalkSpeed = self.Config.walkSpeed self:ChangeAttributeValue("hp", self.Config.maxhp) -- 重置玩家位置 diff --git a/src/ServerStorage/Proxy/PlayerInfoProxy.luau b/src/ServerStorage/Proxy/PlayerInfoProxy.luau index 0489abe..7118d54 100644 --- a/src/ServerStorage/Proxy/PlayerInfoProxy.luau +++ b/src/ServerStorage/Proxy/PlayerInfoProxy.luau @@ -12,6 +12,11 @@ local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy) --> Json local JsonPlayerLv = require(ReplicatedStorage.Json.PlayerLv) local JsonItem = require(ReplicatedStorage.Json.ItemProp) +local JsonAttributesUpgrade = require(ReplicatedStorage.Json.AttributesUpgrade) + +--> Events +local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip +local RE_UpgradeAttributes = ReplicatedStorage.Events.RE_UpgradeAttributes --> Constants local STORE_NAME = "PlayerInfo" @@ -34,7 +39,7 @@ local function GetPlayerInfoFolder(Player: Player) end -- 创建玩家信息实例 -local function CreateInfoInstance(Player: Player, Folder: any, StateKey: string, StateType: string, StateValue: any) +local function CreateInfoInstance(Player: Player, Folder: any, StateKey: string, StateType: string, StateValue: any?) if not Player and not Folder and not StateKey and not StateType then warn('创建玩家信息实例失败: ' , Player.Name, Folder.Name, StateKey, StateType, StateValue) return @@ -81,21 +86,83 @@ function PlayerInfoProxy:InitPlayer(Player: Player) local PlayerInfoFolder = Utils:CreateFolder("PlayerInfo", pData) local StatsFolder = Utils:CreateFolder("Stats", PlayerInfoFolder) local ItemsFolder = Utils:CreateFolder("Items", PlayerInfoFolder) + local AttributesUpgradeFolder = Utils:CreateFolder("AttributesUpgrade", PlayerInfoFolder) -- 新玩家数据初始化 if not ArchiveProxy.pData[Player.UserId][STORE_NAME] then ArchiveProxy.pData[Player.UserId][STORE_NAME] = {} ArchiveProxy.pData[Player.UserId][STORE_NAME].Stats = {} ArchiveProxy.pData[Player.UserId][STORE_NAME].Items = {} + ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade = {} end -- 放在外面是为了以后系统新增内容方便(同时不用在初始化数据是做写入了) ExtraAddPlayerStats(Player, ArchiveProxy.pData[Player.UserId][STORE_NAME].Stats) -- 创建玩家信息实例 + for ItemId, ItemValue in ArchiveProxy.pData[Player.UserId][STORE_NAME].Items do + CreateInfoInstance(Player, ItemsFolder, ItemId, ENUM_STATE_TYPE.Number, ItemValue) + end for StateKey, StateData in ArchiveProxy.pData[Player.UserId][STORE_NAME].Stats do CreateInfoInstance(Player, StatsFolder, StateKey, StateData.type, StateData.value) end + for AttributeId, AttributeLv in ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade do + CreateInfoInstance(Player, AttributesUpgradeFolder, AttributeId, "NumberValue", AttributeLv) + end +end + +-- 玩家属性升级 +function PlayerInfoProxy:UpgradeAttribute(Player: Player, AttributeId: number) + if not Player or not AttributeId then warn('升级属性失败: ', Player.Name, AttributeId) return end + + local AttributesUpgradeFolder = GetPlayerInfoFolder(Player):FindFirstChild("AttributesUpgrade") + + local upgradeTable = ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade + local nowLv = upgradeTable[AttributeId] + if nowLv == nil then nowLv = 0 end + + local attributeData = Utils:GetIdDataFromJson(JsonAttributesUpgrade, AttributeId) + local requireBattleValue, requireMoney + + if nowLv == 0 then + requireMoney = attributeData["cost"][2] + requireBattleValue = attributeData["battleValueLimit"][1] + else + requireMoney = attributeData["cost"][2] + (nowLv - 1) * attributeData["cost"][3] + requireBattleValue = attributeData["battleValueLimit"][1] + (nowLv - 1) * attributeData["battleValueLimit"][2] + end + + -- TODO 判断战力是否足够(暂无战力计算) + + -- 判断是否到达等级上限 + print(nowLv, attributeData["maxLv"]) + if attributeData["maxLv"] ~= nil then + if nowLv >= attributeData["maxLv"] then + local tip = '升级属性失败: ' .. AttributeId .. ' 已到达等级上限' + RE_PlayerTip:FireClient(Player, tip) + return + end + end + + -- 判断钱是否足够 + if not self:HasEnoughItem(Player, attributeData["cost"][1], requireMoney) then + local tip = '升级属性失败: ' .. AttributeId .. ' 钱不够' + RE_PlayerTip:FireClient(Player, tip) + return + end + -- 扣钱 + self:ChangeItemCount(Player, 1, -requireMoney) + + -- 升级 + if nowLv == 0 then + -- 首次生成属性 + upgradeTable[AttributeId] = 1 + CreateInfoInstance(Player, AttributesUpgradeFolder, AttributeId, "NumberValue", upgradeTable[AttributeId]) + else + -- 更新属性显示 + upgradeTable[AttributeId] = nowLv + 1 + ChangeInfoInstance(Player, AttributesUpgradeFolder, AttributeId, upgradeTable[AttributeId]) + end end -- 添加经验 @@ -161,6 +228,29 @@ function PlayerInfoProxy:GetItemCount(Player: Player, ItemId: number) return playerInfoData[ItemId] end +-------------------------------------------------------------------------------- + +-- 获取升级加点属性 +function PlayerInfoProxy:GetPlayerUpgradeAttributes(Player: Player) + if not Player then warn('获取玩家属性失败: ', Player.Name) return end + local playerInfoData = ArchiveProxy.pData[Player.UserId][STORE_NAME] + local attributes = {} + for AttributeId, AttributeLv in playerInfoData.AttributesUpgrade do + local attributeData = Utils:GetIdDataFromJson(JsonAttributesUpgrade, AttributeId) + attributes[attributeData["effectAttribute"]] = attributeData["lvAdd"][1] + (AttributeLv - 1) * attributeData["lvAdd"][2] + end + return attributes +end + +-- 获取玩家属性 +function PlayerInfoProxy:GetPlayerAttributes(Player: Player) + local attributesList = {} + attributesList.UpgradeAttributes = self:GetPlayerUpgradeAttributes(Player) + return attributesList +end + +-------------------------------------------------------------------------------- + function PlayerInfoProxy:OnPlayerRemoving(Player: Player) end @@ -169,4 +259,9 @@ ReplicatedStorage.Remotes.PlayerRemoving.Event:Connect(function(Player: Player) PlayerInfoProxy:OnPlayerRemoving(Player) end) +RE_UpgradeAttributes.OnServerEvent:Connect(function(Player: Player, AttributeId: number) + PlayerInfoProxy:UpgradeAttribute(Player, AttributeId) + print(ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade) +end) + return PlayerInfoProxy \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/Helper.luau b/src/StarterPlayerScripts/ClientMain/Helper.luau new file mode 100644 index 0000000..8302612 --- /dev/null +++ b/src/StarterPlayerScripts/ClientMain/Helper.luau @@ -0,0 +1,32 @@ +local Helper = {} + +--> Server +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Events +local RE_PlayerHelper = ReplicatedStorage.Events.RE_PlayerHelper +local RE_UpgradeAttributes = ReplicatedStorage.Events.RE_UpgradeAttributes + +local UserInputService = game:GetService("UserInputService") + +UserInputService.InputBegan:Connect(function(input, gameProcessed) + if gameProcessed then return end + if input.UserInputType == Enum.UserInputType.Keyboard then + if input.KeyCode == Enum.KeyCode.H then + RE_PlayerHelper:FireServer("CleanPlayerData") + elseif input.KeyCode == Enum.KeyCode.J then + print("添加物品") + RE_PlayerHelper:FireServer("AddItem", {1, 100}) + elseif input.KeyCode == Enum.KeyCode.K then + RE_UpgradeAttributes:FireServer(1) + elseif input.KeyCode == Enum.KeyCode.L then + RE_UpgradeAttributes:FireServer(2) + elseif input.KeyCode == Enum.KeyCode.M then + RE_UpgradeAttributes:FireServer(3) + elseif input.KeyCode == Enum.KeyCode.N then + RE_UpgradeAttributes:FireServer(4) + end + end +end) + +return Helper \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/PlayerControl.luau b/src/StarterPlayerScripts/ClientMain/PlayerControl.luau new file mode 100644 index 0000000..42588c4 --- /dev/null +++ b/src/StarterPlayerScripts/ClientMain/PlayerControl.luau @@ -0,0 +1,31 @@ +local UserInputService = game:GetService("UserInputService") + +local PlayerControl = {} + +-- 监听按键按下 +function PlayerControl.ListenMoveKeyDown(onKeyDown) + UserInputService.InputBegan:Connect(function(input, gameProcessed) + if gameProcessed then return end + if input.UserInputType == Enum.UserInputType.Keyboard then + local key = input.KeyCode + if key == Enum.KeyCode.W or key == Enum.KeyCode.A or key == Enum.KeyCode.S or key == Enum.KeyCode.D then + onKeyDown(key) + end + end + end) +end + +-- 监听按键松开 +function PlayerControl.ListenMoveKeyUp(onKeyUp) + UserInputService.InputEnded:Connect(function(input, gameProcessed) + if gameProcessed then return end + if input.UserInputType == Enum.UserInputType.Keyboard then + local key = input.KeyCode + if key == Enum.KeyCode.W or key == Enum.KeyCode.A or key == Enum.KeyCode.S or key == Enum.KeyCode.D then + onKeyUp(key) + end + end + end) +end + +return PlayerControl \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/init.client.luau b/src/StarterPlayerScripts/ClientMain/init.client.luau index fe4edb2..d913bd5 100644 --- a/src/StarterPlayerScripts/ClientMain/init.client.luau +++ b/src/StarterPlayerScripts/ClientMain/init.client.luau @@ -19,6 +19,11 @@ local PlayerGui = Player:WaitForChild("PlayerGui") local FormatNumber = require(ReplicatedStorage.Modules.FormatNumber) local Tween = require(ReplicatedStorage.Modules.Tween) local SFX = require(ReplicatedStorage.Modules.SFX) +local PlayerControl = require(script.PlayerControl) +local Helper = require(script.Helper) + +--> Events +local RE_PlayerAI = ReplicatedStorage.Events.RE_PlayerAI --> Variables local Random = Random.new() @@ -28,6 +33,16 @@ local ClientMainPrefabs = Player.PlayerScripts.ClientMainPrefabs -------------------------------------------------------------------------------- +PlayerControl.ListenMoveKeyDown(function(key) + -- print("按下了: ", key.Name) + RE_PlayerAI:FireServer(true) +end) + +PlayerControl.ListenMoveKeyUp(function(key) + -- print("松开了: ", key.Name) + RE_PlayerAI:FireServer(false) +end) + -- Initially require client-sided modules for _, Item in script:GetChildren() do if Item:IsA("ModuleScript") then