--[[ 作者: 无心 日期: 2025-08-24 功能介绍: 本文件为线路管理(LineManager)模块,主要负责处理与游戏多线路相关的逻辑,包括获取玩家当前线路、地图、线路策略配置等功能。 该模块为游戏服务器提供多线路分流、线路策略、进入条件等相关的辅助方法。 --]] LineManager = {} LineManager.init = function() end --- 获取玩家当前线路ID --- @param actor table 玩家对象 --- @return number 当前线路ID function LineManager.getCurrentLine(actor) return getbaseinfo(actor, "line") end --- 获取玩家当前地图ID --- @param actor table 玩家对象 --- @return number 当前地图ID function LineManager.getCurrentMapId(actor) return getbaseinfo(actor, "mapid") end -- 公共方法:根据actor和字段名获取线路策略配置表中的字段值 function LineManager.getLinePolicyField(actor, fieldName) local lineId = LineManager.getCurrentLine(actor) local mapId = LineManager.getCurrentMapId(actor) local linePolicyConfig = ConfigDataManager.getTableValue("cfg_map_line", "line_policy_config", "id", mapId) -- info(string.format("MS LineManager.getLinePolicyField: 获取线路策略配置信息=%s", linePolicyConfig)) if not linePolicyConfig or linePolicyConfig == "" then return nil end local foundPolicyId = nil for _, mapping in ipairs(string.split(linePolicyConfig, "|")) do local parts = string.split(mapping, "#") if #parts == 2 then local configLineId = tonumber(parts[1]) local policyId = tonumber(parts[2]) if configLineId == lineId then foundPolicyId = policyId break end end end -- info(string.format("MS LineManager.getLinePolicyField: 获取线路策略配置id = %s", foundPolicyId)) if not foundPolicyId then return nil end local value = ConfigDataManager.getTableValue("cfg_line_policy", fieldName, "id", foundPolicyId) -- info(string.format("MS LineManager.getLinePolicyField: 获取线路策略配置字段[%s]=%s", fieldName, value)) return value end -- 通过公共方法获取经验倍率 function LineManager.GetLineExpRate(actor) local expRate = LineManager.getLinePolicyField(actor, "expRate") return tonumber(expRate) or 100 end -- 通过公共方法获取掉落倍率 function LineManager.getDropRate(actor) local dropRate = LineManager.getLinePolicyField(actor, "dropRate") -- info(string.format("MS LineManager >>> 配置文件 -> 获取地图基础爆率加成完成 线路爆率=%s", tostring(dropRate))) return tonumber(dropRate) or 100 end --- 获取线路经验倍率 --- @param actor table 玩家对象 --- @return number 经验倍率 function LineManager.getExpRate(actor) local expRate = LineManager.getLinePolicyField(actor, "expRate") return tonumber(expRate) or 100 end --- 检查线路是否允许PK --- @param actor table 玩家对象 --- @return boolean function LineManager.isPvpEnabled(actor) local pvpEnabled = LineManager.getLinePolicyField(actor, "pvpEnabled") return tonumber(pvpEnabled) == 1 end --- 检查线路是否允许交易 --- @param actor table 玩家对象 --- @return boolean function LineManager.isTradeEnabled(actor) local tradeEnabled = LineManager.getLinePolicyField(actor, "tradeEnabled") return tonumber(tradeEnabled) == 1 end --- 检查线路是否开放古战场 --- @param actor table 玩家对象 --- @return boolean function LineManager.isAncientBattleEnabled(actor) local ancientBattleEnabled = LineManager.getLinePolicyField(actor, "ancientBattleEnabled") return tonumber(ancientBattleEnabled) == 1 end --- 检查线路是否开放活动 --- @param actor table 玩家对象 --- @return boolean function LineManager.isActivityEnabled(actor) local activityEnabled = LineManager.getLinePolicyField(actor, "activityEnabled") return tonumber(activityEnabled) == 1 end --- 检查线路是否允许怪物 --- @param actor table 玩家对象 --- @return boolean function LineManager.isMonsterEnabled(actor) local monsterEnabled = LineManager.getLinePolicyField(actor, "monsterEnabled") return tonumber(monsterEnabled) == 1 end function LineManager.takeoffequip(actor) local mapId = getbaseinfo(actor, "map") local wear_conditions = ConfigDataManager.getTableValue("cfg_map_line", "wear_conditions", "id", mapId) if string.isNullOrEmpty(wear_conditions) then return end local checkResult, tip = LineManager.CheckCanEnterLineMap(actor, mapId, 1) if checkResult ~= nil and checkResult == false then APISetInt(actor, "IS_TAKEOFF_EQUIP_TRANSFET", 1) tipinfo(actor, tip) maptransfer(actor, 135, 128 , 1001, 1, 0) end end --- 检查玩家是否可以进入指定线路地图 --- @param actor table 玩家对象 --- @param targetLine number 目标线路ID --- @param targetMap number 目标地图ID --- @return boolean, string 是否可以进入,原因 function LineManager.CheckCanEnterLineMap(actor, targetMapId, targetLine) -- 获取目标地图和线路的线路策略配置字段 local function getLinePolicyFieldForTarget(mapId, lineId, fieldName) local linePolicyConfig = ConfigDataManager.getTableValue("cfg_map_line", "line_policy_config", "id", mapId) if not linePolicyConfig or linePolicyConfig == "" then return nil end local foundPolicyId = nil for _, mapping in ipairs(string.split(linePolicyConfig, "|")) do local parts = string.split(mapping, "#") if #parts == 2 then local configLineId = tonumber(parts[1]) local policyId = tonumber(parts[2]) if configLineId == lineId then foundPolicyId = policyId break end end end if not foundPolicyId then return nil end local value = ConfigDataManager.getTableValue("cfg_line_policy", fieldName, "id", foundPolicyId) return value end local wear_conditions = ConfigDataManager.getTableValue("cfg_map_line", "wear_conditions", "id", targetMapId) if not string.isNullOrEmpty(wear_conditions) then local equips = getputonequipinfo(actor) local conditions = string.split(wear_conditions, "|") local isPass = table.count(conditions) <= 0 local strTip = "" local notNecessaryMax = 0 local notNecessaryPass = 0 for _, v in ipairs(conditions) do local condition = string.split(v, "#") local type = condition[1] local equip = condition[2] local isNecessary = tonumber(condition[3]) local tip = condition[4] local isPassTmp = false if type == "1" then local allposs = string.split(equip, "&") local isWear = nil for _, vpos in ipairs(allposs) do local hasWear, v = table.findByCondi(equips, function(a) local pos = gameequip.pos(a.equipindex) if a.equipindex > 70000 and tonumber(vpos) >= 10000 then pos = pos + 9984 end return pos == tonumber(vpos); end) if tonumber(vpos) == 10003 then local allmount = getallmount(actor) local isWear2 = table.findByCondi(allmount, function(a) return a.wear == 1 or a.auto == 1 end) hasWear = isWear2 end if hasWear == nil then isWear = nil break else isWear = hasWear end end isPassTmp = isWear ~= nil elseif type == "2" then local hasWear, v = table.findByCondi(equips, function(a) return a.cfgid == tonumber(equip); end) isPassTmp = hasWear ~= nil elseif type == "3" then local hasWear, v = table.findByCondi(equips, function(a) return a.cfgid == tonumber(equip); end) local count = getbagitemcountbyid(actor, tonumber(equip)) isPassTmp = not (hasWear == nil and count == 0) elseif type == "4" then local totalLv = 0 for kk, vv in pairs(equips) do local lv = EquipFunc.getEquipStrengthLevel(actor, vv.id) totalLv = totalLv + lv end isPassTmp = not (totalLv < tonumber(equip)) end if isNecessary == 1 then if isPassTmp ~= true then strTip = tip isPass = false break else isPass = isPassTmp end end if isNecessary == 0 then notNecessaryMax = notNecessaryMax + 1 if isPassTmp == true then isPass = true notNecessaryPass = notNecessaryPass + 1 else strTip = tip end end end if isPass ~= true then -- tipinfo(actor, strTip) return false, strTip elseif notNecessaryMax > 0 and notNecessaryPass <= 0 then -- tipinfo(actor, strTip) return false, strTip end end local tradeCardRequired = tonumber(getLinePolicyFieldForTarget(targetMapId, targetLine, "TradeCard")) or 0 local enjoyPrivilegeRequired = tonumber(getLinePolicyFieldForTarget(targetMapId, targetLine, "EnjoyPrivilege")) or 0 local unionLevelRequired = tonumber(getLinePolicyFieldForTarget(targetMapId, targetLine, "UnionLevel")) or 0 local vipLevelRequired = tonumber(getLinePolicyFieldForTarget(targetMapId, targetLine, "VipLevel")) or 0 -- info("MS LineManager.CheckCanEnterLineMap-> ", targetMapId, targetLine, tradeCardRequired, enjoyPrivilegeRequired, -- unionLevelRequired, vipLevelRequired) -- 1. 检查是否需要交易卡 if tradeCardRequired > 0 then if not LineManager.hasTradeCard(actor) then tipinfo(actor, "需要交易卡") return false, "需要交易卡" end end -- 2. 检查是否需要畅玩特权 if enjoyPrivilegeRequired > 0 then if not PrivilegeMonth.hasEnjoyPrivilege(actor) then tipinfo(actor, "需要畅玩特权") return false, "需要畅玩特权" end end -- 3. 检查战盟等级 if unionLevelRequired > 0 then if not LineManager.checkUnionLevel(actor, unionLevelRequired) then tipinfo(actor, string.format("战盟等级不足,需要%d级", unionLevelRequired)) return false, string.format("战盟等级不足,需要%d级", unionLevelRequired) end end -- 4. 检查VIP等级 if vipLevelRequired > 0 then if not LineManager.checkVipLevel(actor, vipLevelRequired) then tipinfo(actor, string.format("VIP等级不足,需要%d级", vipLevelRequired)) return false, string.format("VIP等级不足,需要%d级", vipLevelRequired) end end -- 所有条件都满足 return true, "可以进入" end --- 检查玩家进入指定线路地图所需道具 --- @param actor table 玩家对象 --- @param itemsNeedIndex number 所需道具idx --- @param targetMapId number 目标地图ID --- @return boolean, string 是否可以进入,原因 function LineManager.CheckEnterLineMapItemsNeed(actor, targetMapId, itemsNeedIndex) local mapId = tonumber(getbaseinfo(actor, "mapid")) if mapId == targetMapId then return true, "" end local joinMapNeedSelect = {} -- 选择需要道具 local joinMapNeed = {} -- 必须需要道具 local strTip = "" local items_need = ConfigDataManager.getTableValue("cfg_map_line", "items_need", "id", targetMapId) if not string.isNullOrEmpty(items_need) then local conditionArr = string.split(items_need, "|") for _, conditionData in ipairs(conditionArr) do local conditionStr = string.split(conditionData, "#") strTip = conditionStr[3] if tonumber(conditionStr[2]) == 0 then local itemArr = string.split(conditionStr[1], "&") if table.count(itemArr) > 1 then table.insert(joinMapNeedSelect, {itemId = tonumber(itemArr[1]), itemNum = tonumber(itemArr[2])}) end else local itemArr = string.split(conditionStr[1], "&") if table.count(itemArr) > 1 then table.insert(joinMapNeed, {itemId = tonumber(itemArr[1]), itemNum = tonumber(itemArr[2])}) end end end end local itemNeed = joinMapNeedSelect[itemsNeedIndex] if table.count(joinMapNeedSelect) > 0 then if itemNeed == nil then tipinfo(actor, "材料扣除失败") return false, strTip end else return true, "" end -- 整合所需道具 local itemsNeed = {} if itemNeed ~= nil then table.insert(itemsNeed, {itemId = itemNeed.itemId, itemNum = itemNeed.itemNum}) end for _,item in ipairs(joinMapNeed) do table.insert(itemsNeed, {itemId = item.itemId, itemNum = item.itemNum}) end -- 传送至地图所需道具扣除 for _, item in ipairs(itemsNeed) do local result = removeitemfrombag(actor, item.itemId, item.itemNum, 0, 9999, "传送古战场消耗") if not result then tipinfo(actor, "扣除道具失败") return false, strTip end end return true, "" end --- 检查是否有交易卡(优化版本) --- @param actor table 玩家对象 --- @return boolean function LineManager.hasTradeCard(actor) -- 这里需要根据实际的交易卡道具ID进行判断 local tradeCardId = 70700001 -- 假设的交易卡道具ID,需要根据实际配置调整 return Bag.hasItem(actor, tradeCardId, 1) end --- 检查VIP等级(优化版本) --- @param actor table 玩家对象 --- @param requiredLevel number 要求的VIP等级 --- @return boolean function LineManager.checkVipLevel(actor, requiredLevel) -- 这里需要根据实际的VIP系统进行判断 -- local vipLevel = getplaydef(actor, "VIP_LEVEL") or 0 -- return tonumber(vipLevel) >= requiredLevel return true end --- 检查战盟等级(优化版本) --- @param actor table 玩家对象 --- @param requiredLevel number 要求的战盟等级 --- @return boolean function LineManager.checkUnionLevel(actor, requiredLevel) -- 这里需要根据实际的战盟系统进行判断 -- local unionLevel = getplaydef(actor, "UNION_LEVEL") or 0 -- return tonumber(unionLevel) >= requiredLevel return true end --- 应用掉落倍率 --- @param actor table 玩家对象 --- @param baseDropRate number 基础掉落率 --- @return number 实际掉落率 function LineManager.applyDropRate(actor, baseDropRate) -- 获取线路爆率 local lineDropRate = LineManager.getDropRate(actor) -- info(string.format("MS LineManager >>> 开始获取地图基础爆率加成 基础掉落率=%s", tostring(baseDropRate))) -- info(string.format("MS LineManager >>> 获取地图基础爆率加成完成 线路爆率=%s", tostring(lineDropRate))) -- 计算实际掉落率 local actualDropRate = baseDropRate * (lineDropRate / 100) -- info(string.format("MS LineManager >>> 玩家掉落倍率调整:倍率=%s, 基础掉落率=%s, 实际掉落率=%s", tostring(lineDropRate), tostring(baseDropRate), tostring(actualDropRate))) return actualDropRate end --- 应用经验倍率 --- @param actor table 玩家对象 --- @param baseExp number 基础经验 --- @return number 实际经验 function LineManager.applyExpRate(actor, baseExp) local lineExpRate = LineManager.GetLineExpRate(actor) if not lineExpRate then -- info(string.format("MS LineManager.applyExpRate 检测没有线路策略: actor=%s, currentLine=%d, lineExpRate=nil", actor:toString(), currentLine)) return baseExp end -- 计算实际经验 local actualExp = baseExp * (tonumber(lineExpRate) / 100) return actualExp end