4255 lines
144 KiB
Lua
4255 lines
144 KiB
Lua
GUIFunction = {}
|
||
|
||
local AttTypeTable = GUIDefine.AttTypeTable
|
||
local ExAttType = GUIDefine.ExAttType
|
||
|
||
-- 获取基础属性
|
||
function GUIFunction:PShowAttType()
|
||
return AttTypeTable
|
||
end
|
||
|
||
function GUIFunction:GetExAttType()
|
||
return ExAttType
|
||
end
|
||
|
||
-- 获取职业名
|
||
function GUIFunction:GetJobNameByID(jobID)
|
||
if not jobID then return "" end
|
||
if jobID == 4 then
|
||
return SL:GetValue("I18N_STRING", 1100)
|
||
elseif jobID >= 5 and jobID <= 15 then
|
||
local jobData = SL:GetValue("GAME_DATA", "MultipleJobSetMap")[jobID]
|
||
local isOpen = jobData and jobData.isOpen
|
||
local str = isOpen and jobData.name or string.format("%s%s", SL:GetValue("I18N_STRING", 1101), jobID)
|
||
return str
|
||
end
|
||
return SL:GetValue("I18N_STRING", 1067+jobID)
|
||
end
|
||
|
||
-- 触发 与身上装备比较 [背包提升箭头使用]
|
||
function GUIFunction:CompareEquipOnBody(equipData, from)
|
||
-- 装备数据
|
||
if not equipData then
|
||
return false
|
||
end
|
||
|
||
if not from then
|
||
from = GUIDefine.ItemFrom.BAG
|
||
end
|
||
|
||
-- M2开关自动穿戴
|
||
local autoDress = SL:GetValue("SERVER_OPTION", SW_KEY_AUTO_DRESS)
|
||
if not autoDress or autoDress == 0 then
|
||
return false
|
||
end
|
||
|
||
-- equip表 配置对比参数 -1不进行比较(非穿戴物品)
|
||
local myComparison, myJob = SL:GetValue("EQUIP_COMPARISON", equipData.Index)
|
||
if myComparison then
|
||
if tonumber(myComparison) == -1 then
|
||
return false
|
||
elseif tonumber(equipData.comparison) == -2 and from == GUIDefine.ItemFrom.BAG then
|
||
return false
|
||
elseif tonumber(equipData.comparison) == -3 and from == GUIDefine.ItemFrom.HERO_BAG then
|
||
return false
|
||
end
|
||
end
|
||
|
||
local isHero = from == GUIDefine.ItemFrom.HERO_BAG
|
||
-- 职业判断
|
||
local job = isHero and SL:GetValue("H.JOB") or SL:GetValue("JOB")
|
||
if myJob and myJob ~= 3 and myJob ~= job then
|
||
return false
|
||
end
|
||
|
||
-- 通过stdmode 获取装备位
|
||
local posList = GUIDefine.EquipPosByStdMode[equipData.StdMode]
|
||
if not posList or next(posList) == nil then
|
||
return false
|
||
end
|
||
|
||
-- 是否是该性别装备
|
||
local sexOk = SL:GetValue("IS_SAMESEX_EQUIP", equipData, isHero)
|
||
if not sexOk then
|
||
return false
|
||
end
|
||
|
||
-- 药粉 护身符 不对比
|
||
if equipData.StdMode == 25 then
|
||
return false
|
||
end
|
||
|
||
local myParam = {jobPower = true}
|
||
local myPower, powerSortIndex = GUIFunction:GetEquipPower(equipData, myParam, isHero) -- 当前装备战力
|
||
|
||
-- 比较身上装备
|
||
local targetInfo = nil
|
||
local targetParam = {jobPower = true, power = myPower, comparison = myComparison, powerSortIndex = powerSortIndex}
|
||
local targetMinPower = 0 -- 身上穿戴最小战力
|
||
for i, pos in ipairs(posList) do
|
||
if isHero then
|
||
targetInfo = SL:GetValue("H.EQUIP_DATA", pos)
|
||
else
|
||
targetInfo = SL:GetValue("EQUIP_DATA", pos)
|
||
end
|
||
if not targetInfo then
|
||
return true
|
||
end
|
||
|
||
local targetPower = GUIFunction:GetEquipPower(targetInfo, targetParam, isHero) -- 身上装备战力
|
||
if targetMinPower == 0 or targetPower < targetMinPower then -- 拿到身上穿戴最小战力
|
||
targetMinPower = targetPower
|
||
end
|
||
end
|
||
|
||
if targetMinPower < myPower then
|
||
return true
|
||
end
|
||
|
||
return false
|
||
end
|
||
|
||
-- 获取战力
|
||
function GUIFunction:GetEquipPower(item, param, isHero)
|
||
if not item or next(item) == nil then
|
||
return 0
|
||
end
|
||
|
||
local param = param or {}
|
||
|
||
-- 基础属性 对比
|
||
local itemCfg = SL:GetValue("ITEM_DATA", item.Index)
|
||
if not itemCfg or not itemCfg.Attribute then
|
||
return 0
|
||
end
|
||
|
||
local attList = {} -- 属性列表
|
||
local tAttribute = string.split(itemCfg.Attribute or "", "|")
|
||
for i, v in ipairs(tAttribute) do
|
||
if v and v ~= "" and string.len(v) > 0 then
|
||
local tAttribute2 = string.split(v or "", "#")
|
||
table.insert(attList, {id = tonumber(tAttribute2[2]) or 3, value = tonumber(tAttribute2[3]) or 0})
|
||
end
|
||
end
|
||
|
||
local powerValue, powerSortIndex = GUIFunction:CalculateAttPower(attList, param.jobPower, param.powerSortIndex, isHero)
|
||
local comparisonValue = SL:GetValue("EQUIP_COMPARISON", item.Index)
|
||
|
||
local targetPower = param.power or 0 -- 选中装备 属性战力
|
||
local targetComparison = param.comparison or comparisonValue -- 选中装备 优先级
|
||
if comparisonValue > targetComparison or (param.powerSortIndex and param.powerSortIndex < powerSortIndex) then
|
||
powerValue = math.abs(powerValue) + targetPower + 1 -- 比选中装备战力高
|
||
elseif comparisonValue < targetComparison then
|
||
powerValue = math.min(math.abs(powerValue), targetPower - 1) -- 比选中装备战力低
|
||
end
|
||
|
||
return powerValue, powerSortIndex
|
||
end
|
||
|
||
-- 计算战力
|
||
-- attList: 属性 isJobPower:对比本职业 sortIndex:对比的属性下标(先比较职业属性 再比较物防 最后比较魔防 都是上限属性)
|
||
function GUIFunction:CalculateAttPower(attList, isJobPower, sortIndex, isHero)
|
||
local power = -1
|
||
local myJob = isHero and SL:GetValue("H.JOB") or SL:GetValue("JOB")
|
||
local jobPowerAttIds = {
|
||
[AttTypeTable.Max_DEF] = 2,
|
||
[AttTypeTable.Max_MDF] = 1
|
||
}
|
||
|
||
if isJobPower then
|
||
if myJob == 0 then --战士
|
||
jobPowerAttIds[AttTypeTable.Max_ATK] = 3
|
||
elseif myJob == 1 then --法师
|
||
jobPowerAttIds[AttTypeTable.Max_MAT] = 3
|
||
elseif myJob == 2 then --道士
|
||
jobPowerAttIds[AttTypeTable.Max_Daoshu] = 3
|
||
end
|
||
end
|
||
|
||
local powers = {}
|
||
local powerSortIndex = 0
|
||
|
||
for k, v in pairs(attList) do
|
||
if jobPowerAttIds[v.id] then
|
||
local score = v.value
|
||
powers[jobPowerAttIds[v.id]] = score
|
||
if jobPowerAttIds[v.id] > powerSortIndex and score > 0 then
|
||
powerSortIndex = jobPowerAttIds[v.id]
|
||
end
|
||
end
|
||
end
|
||
|
||
if sortIndex and powerSortIndex <= sortIndex then
|
||
powerSortIndex = sortIndex
|
||
end
|
||
|
||
power = powers[powerSortIndex] or -1
|
||
return power, powerSortIndex
|
||
end
|
||
|
||
-- 获取对应战力最小装备位、战力、是否穿戴,通过StdMode
|
||
-- checkPosData:指定部位数据战力对比({[1]={data = data, pos = pos}})
|
||
function GUIFunction:GetMinPowerPosByStdMode(stdMode, param, checkPosData, isHero, excludePos)
|
||
local stdMode = stdMode or 0
|
||
local onEquipMinPower = 0
|
||
local minPowerPos = -1
|
||
local hasEquip = true
|
||
local pos = checkPosData or SL:CopyData(GUIDefine.EquipPosByStdMode[stdMode])
|
||
if not pos or next(pos) == nil then
|
||
SL:Print("this StdMode is not a equip")
|
||
return minPowerPos, onEquipMinPower, false
|
||
end
|
||
|
||
if param.checkPos then
|
||
local index = table.indexof(pos, param.checkPos)
|
||
if index then
|
||
local firstPos = pos[1]
|
||
pos[1] = param.checkPos
|
||
pos[index] = firstPos
|
||
end
|
||
end
|
||
|
||
local isCheckPosData = checkPosData and true or false
|
||
|
||
if excludePos then
|
||
for i, v in ipairs(pos) do
|
||
if (isCheckPosData and v.pos == excludePos) or (not isCheckPosData and v == excludePos) then
|
||
table.remove(pos, i)
|
||
end
|
||
end
|
||
end
|
||
for k, v in ipairs(pos) do
|
||
local equipData = isCheckPosData and v.data
|
||
if not equipData then
|
||
if isHero then
|
||
equipData = SL:GetValue("H.EQUIP_DATA", v)
|
||
else
|
||
equipData = SL:GetValue("EQUIP_DATA", v)
|
||
end
|
||
end
|
||
if not equipData then
|
||
minPowerPos = isCheckPosData and v.pos or v
|
||
onEquipMinPower = 0
|
||
hasEquip = false
|
||
break
|
||
end
|
||
local equipPower = GUIFunction:GetEquipPower(equipData, param, isHero)
|
||
if onEquipMinPower == 0 or equipPower < onEquipMinPower then
|
||
onEquipMinPower = equipPower
|
||
minPowerPos = isCheckPosData and v.pos or v
|
||
if stdMode == 25 then
|
||
break
|
||
end
|
||
end
|
||
end
|
||
return minPowerPos, onEquipMinPower, hasEquip
|
||
end
|
||
|
||
-- 检查装备禁止装戴位置
|
||
function GUIFunction:CheckEquipExcludePos(item)
|
||
if not item.Article or item.Article == "" then
|
||
return nil
|
||
end
|
||
|
||
local itemArticle = nil
|
||
local parseArticle = string.split(item.Article, "|")
|
||
for k, v in pairs(parseArticle) do
|
||
local articleV = tonumber(v)
|
||
if articleV == GUIDefine.ItemArticleType.TYPE_TAKE_ARMRINGL then
|
||
return GUIDefine.EquipPosUI.Equip_Type_ArmRingL
|
||
end
|
||
end
|
||
|
||
return nil
|
||
end
|
||
|
||
-- 检测显示自动使用Tips
|
||
-- checkItem: 检测装备数据 pos: 要穿戴的装备位置 playerType: 人物类型(1: 人物; 2: 英雄)
|
||
function GUIFunction:CheckAutoUseTips(checkItem, pos, playerType)
|
||
playerType = playerType or 1
|
||
local checkEquipIntoPos = pos
|
||
local isHero = playerType == 2
|
||
if checkItem and checkItem.StdMode then
|
||
local function checkMinPower(item, checkPosData)
|
||
local comparison = SL:GetValue("EQUIP_COMPARISON", item.Index)
|
||
-- 是否有找到合适的位置 战力对比
|
||
local myPower = 0
|
||
local powerSortIndex = nil
|
||
myPower, powerSortIndex = GUIFunction:GetEquipPower(item, {jobPower = true}, isHero)
|
||
|
||
local param = {jobPower = true, power = myPower, comparison = comparison, powerSortIndex = powerSortIndex}
|
||
local excludePos = GUIFunction:CheckEquipExcludePos(item)
|
||
local minPowerPos, onEquipMinPower, hasEquip = GUIFunction:GetMinPowerPosByStdMode(item.StdMode, param, checkPosData, isHero, excludePos)
|
||
local equipIntoPos = -1
|
||
|
||
if minPowerPos >= 0 and (not hasEquip or onEquipMinPower < myPower) then
|
||
equipIntoPos = minPowerPos
|
||
end
|
||
|
||
if equipIntoPos < 0 then
|
||
return -1
|
||
end
|
||
return equipIntoPos
|
||
end
|
||
|
||
local posList = GUIDefine.EquipPosByStdMode[checkItem.StdMode]
|
||
local isBreak = true
|
||
for k, equipPos in ipairs(posList) do
|
||
isBreak = true
|
||
local excludePos = GUIFunction:CheckEquipExcludePos(checkItem)
|
||
if not excludePos or excludePos ~= equipPos then
|
||
-- 已有自动使用装备
|
||
local tipsMakeIndex = AutoUseItemData.GetMakeIndexByPos(playerType, equipPos)
|
||
if tipsMakeIndex then
|
||
|
||
local equipData = nil
|
||
if isHero then
|
||
equipData = HeroBagData.GetItemDataByMakeIndex(tipsMakeIndex) or BagData.GetItemDataByMakeIndex(tipsMakeIndex)
|
||
else
|
||
equipData = BagData.GetItemDataByMakeIndex(tipsMakeIndex)
|
||
end
|
||
checkEquipIntoPos = checkMinPower(checkItem, {{data = equipData, pos = equipPos}})
|
||
else
|
||
local equipData = nil
|
||
if isHero then
|
||
equipData = SL:GetValue("H.EQUIP_DATA", equipPos)
|
||
else
|
||
equipData = SL:GetValue("EQUIP_DATA", equipPos)
|
||
end
|
||
if not equipData then
|
||
checkEquipIntoPos = equipPos
|
||
else
|
||
checkEquipIntoPos = checkMinPower(checkItem, {{data = equipData, pos = equipPos}})
|
||
end
|
||
end
|
||
|
||
if isBreak and checkEquipIntoPos >= 0 then
|
||
break
|
||
end
|
||
end
|
||
end
|
||
end
|
||
return checkEquipIntoPos
|
||
end
|
||
|
||
-- 自动使用比对物品 (人物)
|
||
function GUIFunction:OnAutoUseCheckItem(item)
|
||
if not item then
|
||
return
|
||
end
|
||
|
||
-- 配置对比参数 -1、-2不进行比较
|
||
if item.comparison and (tonumber(item.comparison) == -1 or tonumber(item.comparison) == -2) then
|
||
return
|
||
end
|
||
|
||
-- 服务端自动使用开关
|
||
local autoDress = SL:GetValue("SERVER_OPTION", SW_KEY_AUTO_DRESS)
|
||
if not autoDress or autoDress ~= 1 then
|
||
return
|
||
end
|
||
|
||
-- 禁止使用物品buff
|
||
local ret, buffID = SL:GetValue("CHECK_USE_ITEM_BUFF", item.Index)
|
||
if not ret then
|
||
if buffID then
|
||
local config = SL:GetValue("BUFF_CONFIG", buffID)
|
||
if config and config.bufftitle then
|
||
SL:ShowSystemTips(config.bufftitle)
|
||
end
|
||
end
|
||
return
|
||
end
|
||
|
||
local isCanAutoUse = SL:GetValue("ITEM_CAN_AUTOUSE", item)
|
||
local isSkillBook = SL:GetValue("ITEMTYPE", item) == SL:GetValue("ITEMTYPE_ENUM").SkillBook
|
||
local pos = GUIDefine.EquipPosByStdMode[item.StdMode]
|
||
if not isCanAutoUse and not isSkillBook and (not pos or not next(pos)) then
|
||
return
|
||
end
|
||
|
||
local type = 1 -- 人物
|
||
local isOk = false
|
||
repeat
|
||
-- 穿戴条件是否满足
|
||
local canUse = SL:CheckItemUseNeed(item).canUse
|
||
if not canUse then
|
||
break
|
||
end
|
||
|
||
local equipIntoPos = nil
|
||
-- 技能书
|
||
if isSkillBook then
|
||
if not SL:GetValue("SKILLBOOK_CAN_USE", item.Name) then
|
||
break
|
||
end
|
||
-- 装备
|
||
elseif pos and next(pos) then
|
||
-- 性别判断
|
||
if not SL:GetValue("IS_SAMESEX_EQUIP", item) and SL:GetValue("PLAYER_INITED") then
|
||
break
|
||
end
|
||
|
||
-- 职业判断
|
||
local comparison, job = SL:GetValue("EQUIP_COMPARISON", item.Index)
|
||
if job and job ~= 3 and job ~= SL:GetValue("JOB") then
|
||
break
|
||
end
|
||
|
||
-- 战力对比
|
||
local myParam = {jobPower = true}
|
||
-- 当前装备战力
|
||
local myPower, powerSortIndex = GUIFunction:GetEquipPower(item, myParam)
|
||
local param = {jobPower = true, power = myPower, comparison = comparison, powerSortIndex = powerSortIndex}
|
||
-- 最小战力装备位
|
||
local excludePos = GUIFunction:CheckEquipExcludePos(item)
|
||
local minPowerPos, onEquipMinPower, hasEquip = GUIFunction:GetMinPowerPosByStdMode(item.StdMode, param, nil, false, excludePos)
|
||
|
||
equipIntoPos = -1
|
||
|
||
if minPowerPos >= 0 and (not hasEquip or onEquipMinPower < myPower) then
|
||
equipIntoPos = minPowerPos
|
||
end
|
||
|
||
if equipIntoPos < 0 then
|
||
break
|
||
else
|
||
-- 检测显示Tips
|
||
equipIntoPos = GUIFunction:CheckAutoUseTips(item, equipIntoPos, type)
|
||
if not equipIntoPos or equipIntoPos < 0 then
|
||
break
|
||
end
|
||
end
|
||
end
|
||
if equipIntoPos then
|
||
-- 已有自动使用装备
|
||
local tipsMakeIndex = AutoUseItemData.GetMakeIndexByPos(type, equipIntoPos)
|
||
UIOperator:CloseAutoUsePopUI(tipsMakeIndex, equipIntoPos)
|
||
AutoUseItemData.SetMakeIndexByPos(type, equipIntoPos, item.MakeIndex)
|
||
end
|
||
|
||
isOk = true
|
||
|
||
UIOperator:OpenAutoUsePopUI({item = item, targetPos = equipIntoPos, isSkillBook = isSkillBook})
|
||
|
||
until true
|
||
|
||
return isOk
|
||
end
|
||
|
||
-- 自动使用比对物品 (英雄)
|
||
function GUIFunction:OnAutoUseCheckItem_Hero(item)
|
||
if not item then
|
||
return
|
||
end
|
||
|
||
-- 配置对比参数 -1、-3不进行比较
|
||
if item.comparison and (tonumber(item.comparison) == -1 or tonumber(item.comparison) == -3) then
|
||
return
|
||
end
|
||
|
||
-- 英雄是否召唤
|
||
if not SL:GetValue("HERO_IS_ALIVE") then
|
||
return
|
||
end
|
||
|
||
-- 服务端自动使用开关
|
||
local autoDress = SL:GetValue("SERVER_OPTION", SW_KEY_AUTO_DRESS)
|
||
if not autoDress or autoDress ~= 1 then
|
||
return
|
||
end
|
||
|
||
local isCanAutoUse = SL:GetValue("ITEM_CAN_AUTOUSE", item)
|
||
local isSkillBook = SL:GetValue("ITEMTYPE", item) == SL:GetValue("ITEMTYPE_ENUM").SkillBook
|
||
local pos = GUIDefine.EquipPosByStdMode[item.StdMode]
|
||
if not isCanAutoUse and not isSkillBook and (not pos or not next(pos)) then
|
||
return
|
||
end
|
||
|
||
local type = 2 -- 英雄
|
||
local isOk = false
|
||
repeat
|
||
-- 穿戴条件是否满足
|
||
local canUse = SL:CheckItemUseNeed_Hero(item).canUse
|
||
if not canUse then
|
||
break
|
||
end
|
||
|
||
local equipIntoPos = nil
|
||
-- 技能书
|
||
if isSkillBook then
|
||
local isFromHero = SL:GetValue("ITEM_BELONG_BY_MAKEINDEX", item.MakeIndex) == GUIDefine.ItemBelong.HEROBAG
|
||
if not isFromHero then
|
||
break
|
||
end
|
||
if not SL:GetValue("SKILLBOOK_CAN_USE", item.Name, true) then
|
||
break
|
||
end
|
||
-- 装备
|
||
elseif pos and next(pos) then
|
||
-- 性别判断
|
||
if not SL:GetValue("IS_SAMESEX_EQUIP", item, true) and SL:GetValue("HERO_INITED") then
|
||
break
|
||
end
|
||
|
||
-- 职业判断
|
||
local comparison, job = SL:GetValue("EQUIP_COMPARISON", item.Index)
|
||
if job and job ~= 3 and job ~= SL:GetValue("H.JOB") then
|
||
break
|
||
end
|
||
|
||
-- 战力对比
|
||
local myParam = {jobPower = true}
|
||
-- 当前装备战力
|
||
local myPower, powerSortIndex = GUIFunction:GetEquipPower(item, myParam, true)
|
||
local param = {jobPower = true, power = myPower, comparison = comparison, powerSortIndex = powerSortIndex}
|
||
-- 最小战力装备位
|
||
local excludePos = GUIFunction:CheckEquipExcludePos(item)
|
||
local minPowerPos, onEquipMinPower, hasEquip = GUIFunction:GetMinPowerPosByStdMode(item.StdMode, param, nil, true, excludePos)
|
||
|
||
equipIntoPos = -1
|
||
|
||
if minPowerPos >= 0 and (not hasEquip or onEquipMinPower < myPower) then
|
||
equipIntoPos = minPowerPos
|
||
end
|
||
|
||
if equipIntoPos < 0 then
|
||
break
|
||
else
|
||
-- 检测显示Tips
|
||
equipIntoPos = GUIFunction:CheckAutoUseTips(item, equipIntoPos, type)
|
||
if not equipIntoPos or equipIntoPos < 0 then
|
||
break
|
||
end
|
||
end
|
||
end
|
||
if equipIntoPos then
|
||
-- 已有自动使用装备
|
||
local tipsMakeIndex = AutoUseItemData.GetMakeIndexByPos(type, equipIntoPos)
|
||
UIOperator:CloseAutoUsePopUI(tipsMakeIndex, equipIntoPos, true)
|
||
AutoUseItemData.SetMakeIndexByPos(type, equipIntoPos, item.MakeIndex)
|
||
end
|
||
|
||
isOk = true
|
||
|
||
UIOperator:OpenAutoUsePopUI({item = item, targetPos = equipIntoPos, isSkillBook = isSkillBook, isHero = true})
|
||
|
||
until true
|
||
|
||
return isOk
|
||
end
|
||
|
||
-- 是否能挖肉
|
||
-- Race 51 52 53 60 90 105 106 82 84 85 可以挖的
|
||
local DIG_RACE_SERVER_LST = {
|
||
[51] = 1,
|
||
[52] = 1,
|
||
[53] = 1,
|
||
[60] = 1,
|
||
[82] = 1,
|
||
[84] = 1,
|
||
[85] = 1,
|
||
[90] = 1,
|
||
[105] = 1,
|
||
[106] = 1,
|
||
}
|
||
function GUIFunction:CheckTargetDigAble(targetID)
|
||
-- 必须是死亡的
|
||
if not SL:GetValue("ACTOR_IS_DIE", targetID) then
|
||
return false
|
||
end
|
||
|
||
-- 怪物和人形怪才可以挖
|
||
if not SL:GetValue("ACTOR_IS_MONSTER", targetID) and not SL:GetValue("ACTOR_IS_HUMAN", targetID) then
|
||
return false
|
||
end
|
||
|
||
-- 是人形怪,但是有主人,可能是分身
|
||
if SL:GetValue("ACTOR_IS_HUMAN", targetID) and SL:GetValue("ACTOR_HAVE_MASTER", targetID) then
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("ACTOR_IS_MONSTER", targetID) then
|
||
local raceServer = SL:GetValue("ACTOR_RACE_SERVER", targetID)
|
||
if DIG_RACE_SERVER_LST[raceServer] == nil then
|
||
return false
|
||
end
|
||
end
|
||
|
||
if SL:GetValue("ACTOR_IS_MONSTER", targetID) or SL:GetValue("ACTOR_IS_HUMAN", targetID) then
|
||
-- 配置不可以挖
|
||
local typeIndex = SL:GetValue("ACTOR_TYPE_INDEX", targetID)
|
||
if GUIDefineEx.NoDigMonsterTypeMap and GUIDefineEx.NoDigMonsterTypeMap[typeIndex] then
|
||
return false
|
||
end
|
||
end
|
||
|
||
return true
|
||
end
|
||
|
||
-- ItemTips 相关
|
||
-- 组合属性ID
|
||
local function GetMergeAttID(min, max)
|
||
if min and max then
|
||
return min * 10000 + max
|
||
else
|
||
return min or max or 0
|
||
end
|
||
end
|
||
|
||
local function MergeAtts(list)
|
||
local newList = {}
|
||
for i, v in pairs(list) do
|
||
local merges = GUIDefine.MergeAttrConfig[v.id]
|
||
if merges then
|
||
local mergedId = GetMergeAttID(merges[1], merges[2])
|
||
if not newList[mergedId] then
|
||
newList[mergedId] = {
|
||
id = mergedId,
|
||
min = 0,
|
||
max = 0,
|
||
}
|
||
if merges[1] and merges[1] >= GUIFunction:PShowAttType().Min_CustJobAttr_5 and merges[1] <= GUIFunction:PShowAttType().Max_CustJobAttr_15 then
|
||
newList[mergedId].maxID = merges[2]
|
||
end
|
||
end
|
||
|
||
if v.id == merges[2] then
|
||
newList[mergedId].max = v.value or 0
|
||
else
|
||
newList[mergedId].min = v.value or 0
|
||
end
|
||
elseif GUIDefine.ExMergeAttrID and GUIDefine.ExMergeAttrID[v.id] then
|
||
local mergedId = GetMergeAttID(v.id, v.id + 1)
|
||
if not newList[mergedId] then
|
||
newList[mergedId] = {
|
||
id = mergedId,
|
||
min = v.min or 0,
|
||
max = v.max or 0,
|
||
}
|
||
end
|
||
else
|
||
table.insert(newList, v)
|
||
end
|
||
end
|
||
return newList
|
||
end
|
||
|
||
-- 获取属性展示方式
|
||
local function GetAttValueShowType(id, maxID)
|
||
local list = {
|
||
[30004] = 2,
|
||
[50006] = 2,
|
||
[70008] = 2,
|
||
[90010] = 2,
|
||
[110012] = 2,
|
||
[940095] = 3,
|
||
[960097] = 3,
|
||
[980099] = 3
|
||
}
|
||
if maxID and maxID >= GUIFunction:PShowAttType().Min_CustJobAttr_5 and maxID <= GUIFunction:PShowAttType().Max_CustJobAttr_15 then
|
||
return 2
|
||
end
|
||
return list[id] or 1
|
||
end
|
||
|
||
-- 获取特殊属性名
|
||
local function GetSpecialAttrName(id)
|
||
local strList = {
|
||
[100000092] = "强度",
|
||
[100000093] = "诅咒",
|
||
[100030004] = "攻击",
|
||
[100050006] = "魔法",
|
||
[100070008] = "道术",
|
||
[100090010] = "防御",
|
||
[100110012] = "魔防",
|
||
[100940095] = "背包负重",
|
||
[100960097] = "装备负重",
|
||
[100980099] = "手持负重"
|
||
}
|
||
return strList[id]
|
||
end
|
||
|
||
-- 0: 十分比 / 1: 百分比
|
||
local function GetAttScaleType(id)
|
||
-- 始终显示百分比
|
||
local list = {
|
||
[AttTypeTable.Health_Recover] = 1,
|
||
[AttTypeTable.Spell_Recover] = 1
|
||
}
|
||
|
||
-- 未开启属性万分比显示十分比
|
||
if id == AttTypeTable.Anti_Magic and not SL:GetValue("SERVER_OPTION", SW_KEY_MAGIC_MISS_TYPE) then
|
||
return 0
|
||
end
|
||
|
||
-- 未开启属性万分比显示百分比
|
||
if (id == AttTypeTable.Anti_Posion or id == AttTypeTable.Posion_Recover) and not SL:GetValue("SERVER_OPTION", SW_KEY_ANTI_POISON_TYPE) then
|
||
return 1
|
||
end
|
||
|
||
return list[id]
|
||
end
|
||
|
||
local function GetAttOriginId(id)
|
||
return id >= 10000 and math.floor(id / 10000) or id
|
||
end
|
||
|
||
-- Tips获取不同装备对比
|
||
function GUIFunction:GetDiffEquip(itemData, isHero)
|
||
local posList = itemData and SL:GetValue("TIP_POSLIST_BY_STDMODE", itemData.StdMode, isHero)
|
||
local equipList = {}
|
||
if posList then
|
||
local myPower = nil
|
||
for _, pos in pairs(posList) do
|
||
local equip = nil
|
||
if isHero then
|
||
equip = SL:GetValue("H.EQUIP_DATA", pos)
|
||
else
|
||
equip = SL:GetValue("EQUIP_DATA", pos)
|
||
end
|
||
if equip and next(equip) then
|
||
table.insert(equipList, equip)
|
||
end
|
||
end
|
||
end
|
||
return equipList
|
||
end
|
||
|
||
-- Tips获取属性数据显示
|
||
local custTypeMap = {[0] = 1, [1] = 3, [2] = 2}
|
||
|
||
local function GetAttNumShow(id, min, max, maxID, stars)
|
||
local name = ""
|
||
local valueStr = ""
|
||
min = tonumber(min) or 0
|
||
max = tonumber(max) or 0
|
||
if id > 10000 then
|
||
name = GetSpecialAttrName(100000000 + id)
|
||
if maxID then
|
||
local config = SL:GetValue("ATTR_CONFIG", maxID) or {}
|
||
name = config.name or ""
|
||
end
|
||
local type = GetAttValueShowType(id, maxID)
|
||
local strWay = type == 2 and "%s-%s" or "%s/%s"
|
||
valueStr = string.format(strWay, SL:HPUnit(min), SL:HPUnit(max))
|
||
if stars then
|
||
valueStr = min > 0 and valueStr or "+" .. SL:HPUnit(max)
|
||
end
|
||
else
|
||
local config = SL:GetValue("ATTR_CONFIG", id) or {}
|
||
local attNumType = config.type or 1
|
||
--[[
|
||
type == 1 正常值 == 2 万分比 == 3 百分比
|
||
目前服务器发送过来的万分比的数值 基本是 10% 中的 10/10
|
||
]]
|
||
local changeName = nil
|
||
local custMap = SL:GetValue("CUST_ABIL_MAP")
|
||
if custMap[id] and next(custMap[id]) then
|
||
local type = custMap[id].type or 0
|
||
if custMap[id].showCustomName then
|
||
changeName = config.name
|
||
end
|
||
id = custMap[id].id
|
||
config = SL:GetValue("ATTR_CONFIG", id) or {}
|
||
attNumType = custTypeMap[type] or 1
|
||
end
|
||
|
||
if id == AttTypeTable.Lucky then
|
||
if min < 0 then
|
||
changeName = GetSpecialAttrName(100000000 + AttTypeTable.Curse)
|
||
min = math.abs(min)
|
||
end
|
||
end
|
||
valueStr = min .. ""
|
||
valueStr = stars and "+" .. valueStr or valueStr
|
||
|
||
if attNumType == 2 or attNumType == 3 then
|
||
local percent = attNumType == 2 and 100 or 1
|
||
local showValue = min / percent
|
||
if GetAttScaleType(id) == 0 then -- 显示十分比
|
||
showValue = showValue * 10
|
||
end
|
||
if attNumType == 2 then --万分比都支持小数点后两位
|
||
showValue = string.format("%.2f", showValue) * 100 / 100
|
||
valueStr = string.format("%s%%", showValue)
|
||
else
|
||
valueStr = string.format("%d%%", showValue)
|
||
end
|
||
else
|
||
if GUIDefine.HPUnitAttrs[id] then
|
||
valueStr = SL:HPUnit(min) .. ""
|
||
if stars then
|
||
valueStr = "+" .. valueStr
|
||
end
|
||
end
|
||
end
|
||
|
||
local showName = config.name
|
||
if changeName then
|
||
name = changeName
|
||
elseif id == AttTypeTable.Strength or id == AttTypeTable.Curse then
|
||
name = GetSpecialAttrName(100000000 + id)
|
||
else
|
||
name = showName
|
||
end
|
||
end
|
||
|
||
name = name or ""
|
||
local lens = string.len(name)
|
||
if lens == 6 then
|
||
local addStr = " "
|
||
local str1 = string.sub(name, 1, 3)
|
||
local str2 = string.sub(name, 4, 6)
|
||
local newStr = str1 .. addStr .. str2
|
||
name = newStr
|
||
elseif lens == 9 then
|
||
local addStr = SL:GetValue("IS_PC_OPER_MODE") and " " or " "
|
||
local addStr2 = SL:GetValue("IS_PC_OPER_MODE") and " " or " "
|
||
local str1 = string.sub(name, 1, 3)
|
||
local str2 = string.sub(name, 4, 6)
|
||
local str3 = string.sub(name, 7, 9)
|
||
local newStr = str1 .. addStr .. str2 .. addStr2 .. str3
|
||
name = newStr
|
||
end
|
||
|
||
name = name .. ":"
|
||
return name, valueStr
|
||
end
|
||
|
||
function GUIFunction:GetAttDataShow(att, stars, tipsShow)
|
||
if not att or not next(att) then
|
||
return {}
|
||
end
|
||
local attList = {}
|
||
if att.id then -- 单条
|
||
table.insert(attList, att)
|
||
else
|
||
attList = att
|
||
end
|
||
|
||
attList = MergeAtts(attList)
|
||
|
||
local attStrs = {}
|
||
|
||
for k, v in pairs(attList) do
|
||
local attId = v.id
|
||
local custMap = SL:GetValue("CUST_ABIL_MAP")
|
||
if custMap[attId] and next(custMap[attId]) then
|
||
attId = custMap[attId].id or attId
|
||
end
|
||
local config = SL:GetValue("ATTR_CONFIG", attId)
|
||
local configShow = config
|
||
if tipsShow and configShow then
|
||
configShow = config.noshowtips ~= 1
|
||
end
|
||
if v.id > 10000 or configShow then
|
||
local min = tonumber(v.min or v.value) or 0
|
||
local name, value = GetAttNumShow(v.id, min, v.max, v.maxID, stars)
|
||
attStrs[v.id] = {
|
||
name = name,
|
||
value = value,
|
||
id = v.id,
|
||
color = config and config.color or nil,
|
||
isCurse = v.id == GUIDefine.AttTypeTable.Lucky and min < 0
|
||
}
|
||
end
|
||
end
|
||
|
||
return attStrs
|
||
end
|
||
|
||
function GUIFunction:GetAttShowOrder(att, stars, tipsShow)
|
||
local showList = GUIFunction:GetAttDataShow(att, stars, tipsShow)
|
||
if not att or next(att) == nil then
|
||
return {}
|
||
end
|
||
local orderList = {}
|
||
for k, v in pairs(showList) do
|
||
table.insert(orderList, v)
|
||
end
|
||
|
||
table.sort(
|
||
orderList,
|
||
function(a, b)
|
||
if a.id <= AttTypeTable.Speed_Point and b.id <= AttTypeTable.Speed_Point then
|
||
return a.id < b.id
|
||
elseif a.id > 10000 and b.id > 10000 then
|
||
return a.id < b.id
|
||
elseif a.id > 10000 and b.id <= AttTypeTable.Speed_Point then
|
||
return false
|
||
elseif a.id <= AttTypeTable.Speed_Point and b.id > 10000 then
|
||
return true
|
||
elseif a.id > 10000 then
|
||
return true
|
||
elseif b.id > 10000 then
|
||
return false
|
||
else
|
||
return a.id < b.id
|
||
end
|
||
end
|
||
)
|
||
return orderList
|
||
end
|
||
|
||
function GUIFunction:GetSeqAttDataShow(att, stars, tipsShow)
|
||
if not att or not next(att) then
|
||
return {}
|
||
end
|
||
local attList = {}
|
||
if att.id then -- 单条
|
||
table.insert(attList, att)
|
||
else
|
||
attList = att
|
||
end
|
||
|
||
local newList = {}
|
||
for i, v in ipairs(attList) do
|
||
local merges = GUIDefine.MergeAttrConfig[v.id]
|
||
if merges then
|
||
local mergedId = GetMergeAttID(merges[1], merges[2])
|
||
local data = {}
|
||
local isFind = false
|
||
for _, att in ipairs(newList) do
|
||
if att.id == mergedId then
|
||
if v.id == merges[2] then
|
||
att.max = v.value or 0
|
||
else
|
||
att.min = v.value or 0
|
||
end
|
||
isFind = true
|
||
break
|
||
end
|
||
end
|
||
|
||
if not isFind then
|
||
local data = {
|
||
id = mergedId,
|
||
min = 0,
|
||
max = 0,
|
||
}
|
||
if merges[1] and merges[1] >= GUIFunction:PShowAttType().Min_CustJobAttr_5 and merges[1] <= GUIFunction:PShowAttType().Max_CustJobAttr_15 then
|
||
data.maxID = merges[2]
|
||
end
|
||
if v.id == merges[2] then
|
||
data.max = v.value or 0
|
||
else
|
||
data.min = v.value or 0
|
||
end
|
||
table.insert(newList, data)
|
||
end
|
||
else
|
||
table.insert(newList, v)
|
||
end
|
||
end
|
||
|
||
attList = newList
|
||
|
||
local attStrs = {}
|
||
for k, v in pairs(attList) do
|
||
local attId = v.id
|
||
local custMap = SL:GetValue("CUST_ABIL_MAP")
|
||
if custMap[attId] and next(custMap[attId]) then
|
||
attId = custMap[attId].id or attId
|
||
end
|
||
local config = SL:GetValue("ATTR_CONFIG", attId)
|
||
local configShow = config
|
||
if tipsShow and configShow then
|
||
configShow = config.noshowtips ~= 1
|
||
end
|
||
if v.id > 10000 or configShow then
|
||
local min = tonumber(v.min or v.value) or 0
|
||
local name, value = GetAttNumShow(v.id, min, v.max, v.maxID, stars)
|
||
local originId = GetAttOriginId(v.id)
|
||
local attConfig = SL:GetValue("ATTR_CONFIG", originId)
|
||
table.insert(attStrs, {
|
||
name = name,
|
||
value = value,
|
||
id = v.id,
|
||
color = config and config.color or nil,
|
||
isCurse = v.id == GUIDefine.AttTypeTable.Lucky and min < 0,
|
||
sort = attConfig and attConfig.sort or originId + 1000,
|
||
excolor = attConfig.excolor
|
||
})
|
||
end
|
||
end
|
||
|
||
return attStrs
|
||
end
|
||
|
||
function GUIFunction:GetDuraStr(dura, maxdura, one)
|
||
local txt
|
||
if not one then
|
||
txt = string.format("%s/%s", math.round(dura / 1000), math.round(maxdura / 1000))
|
||
else
|
||
txt = tostring(math.round(dura / 1000))
|
||
end
|
||
return txt
|
||
end
|
||
|
||
function GUIFunction:GetDura100Str(dura, maxdura, one)
|
||
local txt
|
||
if not one then
|
||
txt = string.format("%s/%s", math.round(dura), math.round(maxdura))
|
||
else
|
||
txt = tostring(math.round(dura))
|
||
end
|
||
return txt
|
||
end
|
||
|
||
function GUIFunction:ItemUseConditionColor(bEnable)
|
||
if bEnable then
|
||
return "#ffffff"
|
||
end
|
||
return "#ff0000"
|
||
end
|
||
|
||
-- 装备基础属性
|
||
function GUIFunction:ParseItemBaseAtt(att, job)
|
||
local attList = {}
|
||
if not att or att == "" or att == "0" or att == 0 then
|
||
return attList
|
||
end
|
||
local attArray = string.split(att, "|")
|
||
local myJob = job or SL:GetValue("JOB")
|
||
for k, v in ipairs(attArray) do
|
||
local attData = string.split(v, "#")
|
||
local needJob = tonumber(attData[1])
|
||
local attId = tonumber(attData[2])
|
||
local attValue = tonumber(attData[3])
|
||
if (myJob == 3 or needJob == 3 or needJob == myJob) then
|
||
table.insert(
|
||
attList,
|
||
{
|
||
id = attId,
|
||
value = attValue
|
||
}
|
||
)
|
||
end
|
||
end
|
||
return attList
|
||
end
|
||
|
||
-- 装备极品属性
|
||
function GUIFunction:GetItemQualityAttr(itemData)
|
||
local attList = {}
|
||
if not itemData or not itemData.Quality or not next(itemData.Quality) then
|
||
return attList
|
||
end
|
||
for _, att in ipairs(itemData.Quality) do
|
||
if att.Idx and att.Idx > 0 and att.Value and att.Value ~= 0 then
|
||
table.insert(attList, {
|
||
id = att.Idx,
|
||
value = att.Value
|
||
})
|
||
end
|
||
end
|
||
return attList
|
||
end
|
||
|
||
-- 解析自定义属性标题 (带装备变量)
|
||
function GUIFunction:ParseTitleHasCustomVar(itemMakeIndex, titleName)
|
||
local source = titleName
|
||
local results = {}
|
||
while true do
|
||
local sIdx, eIdx, oriStr, param = string.find(source, "(<$ITEMVAR%((.-)%)>)")
|
||
if not (oriStr and param) then
|
||
break
|
||
end
|
||
results[oriStr] = SL:GetValue("ITEM_CUSTOM_VAR_BY_VNAME", itemMakeIndex, param) or ""
|
||
local s1 = string.sub(source, 1, sIdx - 1)
|
||
local s2 = string.sub(source, eIdx + 1, string.len(source))
|
||
source = s1 .. s2
|
||
end
|
||
|
||
for key, result in pairs(results) do
|
||
local sIdx, eIdx = string.find(titleName, key, 1, true)
|
||
titleName = string.sub(titleName, 1, sIdx - 1) .. tostring(result) .. string.sub(titleName, eIdx + 1, string.len(titleName))
|
||
end
|
||
|
||
return titleName
|
||
end
|
||
|
||
-- 装备自定义属性
|
||
function GUIFunction:GetItemDiyAttr(itemData)
|
||
local attList = {}
|
||
if not itemData or not itemData.DiyAdv or not next(itemData.DiyAdv) then
|
||
return attList
|
||
end
|
||
for _, att in ipairs(itemData.DiyAdv) do
|
||
if att.Idx and att.Idx > 0 and att.Value and att.Value ~= 0 and att.Type then
|
||
if not attList[att.Type] then
|
||
attList[att.Type] = {}
|
||
end
|
||
table.insert(attList[att.Type], {
|
||
id = att.Idx,
|
||
value = att.Value
|
||
})
|
||
end
|
||
end
|
||
return attList
|
||
end
|
||
|
||
function GUIFunction:CombineAttList(list1, list2)
|
||
local newList = {}
|
||
local attList = {}
|
||
for k, v in pairs(list1) do
|
||
if not newList[v.id] then
|
||
newList[v.id] = v.value
|
||
else
|
||
newList[v.id] = newList[v.id] + v.value
|
||
end
|
||
end
|
||
for k, v in pairs(list2) do
|
||
if not newList[v.id] then
|
||
newList[v.id] = v.value
|
||
else
|
||
newList[v.id] = newList[v.id] + v.value
|
||
end
|
||
end
|
||
for k, v in pairs(newList) do
|
||
table.insert(
|
||
attList,
|
||
{
|
||
id = k,
|
||
value = v or 0
|
||
}
|
||
)
|
||
end
|
||
return attList
|
||
end
|
||
|
||
-- 道具属性描述
|
||
function GUIFunction:GetItemAttDesc(item, job)
|
||
local sFormat = string.format
|
||
local equipMap = GUIDefine.EquipMapByStdMode
|
||
local showLasting = SL:GetValue("EX_SHOWLAST_MAP")
|
||
local line1 = {}
|
||
local line2 = {}
|
||
local line3 = {}
|
||
if item.Name ~= "" and item.StdMode then
|
||
-- 显示重量
|
||
if item.Weight and item.Weight > 0 then
|
||
table.insert(line1, sFormat("重量:%s", item.Weight))
|
||
end
|
||
if equipMap[item.StdMode] or showLasting[item.StdMode] then
|
||
table.insert(line1, sFormat("持久:%s", GUIFunction:GetDuraStr(item.Dura, item.DuraMax)))
|
||
elseif item.StdMode == 25 then --护身符及毒药
|
||
line2 = {}
|
||
table.insert(line2, sFormat("数量:%s", GUIFunction:GetDura100Str(item.Dura / 100, item.DuraMax / 100)))
|
||
elseif item.StdMode == 40 then --肉
|
||
table.insert(line1, sFormat("品质:%s", GUIFunction:GetDuraStr(item.Dura, item.DuraMax)))
|
||
elseif item.StdMode == 43 then --矿石
|
||
table.insert(line1, sFormat("纯度:%s", math.round(item.Dura / 1000)))
|
||
elseif item.StdMode == 2 and item.Dura > 0 then --使用次数
|
||
table.insert(line1, sFormat("使用次数:%s", GUIFunction:GetDura100Str(item.Dura / 1000, item.DuraMax / 1000)))
|
||
elseif item.StdMode == 49 then --聚灵珠经验
|
||
if item.Dura >= item.DuraMax then
|
||
table.insert(line1, sFormat("经验值已储蓄满(%s)万 双击释放", math.round(item.DuraMax / 10000)))
|
||
else
|
||
table.insert(line1, sFormat("积累经验:%s万", GUIFunction:GetDura100Str(item.Dura / 10000, item.DuraMax / 10000)))
|
||
end
|
||
end
|
||
local pos = GUIFunction:GetEmptyPosByStdMode(item.StdMode)
|
||
if pos then
|
||
-- 基础属性
|
||
local attList = GUIFunction:ParseItemBaseAtt(item.Attribute, job)
|
||
|
||
-- 极品属性
|
||
local qualityAttrs = GUIFunction:GetItemQualityAttr(item)
|
||
-- 合并极品属性
|
||
if qualityAttrs and next(qualityAttrs) then
|
||
attList = GUIFunction:CombineAttList(attList, qualityAttrs)
|
||
end
|
||
|
||
-- 属性显示队列
|
||
local stringAtt = GUIFunction:GetAttDataShow(attList)
|
||
-- 重新排序
|
||
local ipairList = {}
|
||
for k, v in pairs(stringAtt) do
|
||
v.id = k
|
||
local attOne = v
|
||
attOne.id = k
|
||
table.insert(ipairList, attOne)
|
||
end
|
||
|
||
table.sort(
|
||
ipairList,
|
||
function(a, b)
|
||
local aid = a.id or 0
|
||
local bid = b.id or 0
|
||
if (aid > 10000 and bid > 10000) or (aid < 10000 and bid < 10000) then
|
||
return a.id < b.id
|
||
elseif aid > 10000 then
|
||
return true
|
||
elseif bid > 10000 then
|
||
return false
|
||
end
|
||
end
|
||
)
|
||
-- 按序加入队列
|
||
for k, v in ipairs(ipairList) do
|
||
table.insert(line2, v.name .. v.value)
|
||
end
|
||
end
|
||
|
||
local strList = SL:CheckItemUseNeed(item).conditionStr
|
||
|
||
if strList and next(strList) then
|
||
for i, v in ipairs(strList) do
|
||
if not v.can then
|
||
local color = GUIFunction:ItemUseConditionColor(v.can)
|
||
local conditionStr = string.format("<font color = '%s'>%s</font>", color, v.str)
|
||
table.insert(line3, conditionStr)
|
||
end
|
||
end
|
||
end
|
||
|
||
local strTable = {}
|
||
table.insert(strTable, line1)
|
||
table.insert(strTable, line2)
|
||
table.insert(strTable, line3)
|
||
return strTable
|
||
end
|
||
return nil
|
||
end
|
||
|
||
----------------- 物品自定义描述 ----------------------
|
||
local function parseDescEffect(value)
|
||
local tParams = SL:Split(value or "", "|")
|
||
local params = SL:Split(tParams[1] or "", "#")
|
||
local effectId = tonumber(params[1])
|
||
if not effectId then
|
||
return
|
||
end
|
||
|
||
local effectTab = {}
|
||
effectTab.effectId = effectId
|
||
effectTab.type = tonumber(params[2]) or 0 -- 0:顶部 1:底部
|
||
effectTab.mode = tonumber(params[3]) or 1 -- 1:前面 2:后面
|
||
local pcParams = {}
|
||
if SL:GetValue("IS_PC_OPER_MODE") and string.len(tParams[2] or "") > 0 then
|
||
pcParams = SL:Split(tParams[2] or "", "#")
|
||
end
|
||
effectTab.x = tonumber(pcParams[1]) or tonumber(params[4]) or 0
|
||
effectTab.y = tonumber(pcParams[2]) or tonumber(params[5]) or 0
|
||
effectTab.scaleX = tonumber(pcParams[3]) or tonumber(params[6])
|
||
effectTab.scaleY = tonumber(pcParams[4]) or tonumber(params[7])
|
||
|
||
return effectTab
|
||
end
|
||
|
||
function GUIFunction:GetItemDescList(itemData)
|
||
local desc = itemData.Desc
|
||
local descList = {}
|
||
local effectList = {}
|
||
if not desc or string.len(desc) == 0 then
|
||
return nil
|
||
end
|
||
local function parse(desc)
|
||
if tonumber(desc) then
|
||
local config = GUIDefineEx.ItemDescConfig[tonumber(desc)]
|
||
if not config or not next(config) then
|
||
return
|
||
end
|
||
if config.type == 1 then
|
||
if config.str and string.len(config.str) > 0 then
|
||
if not descList[config.group_id] then
|
||
descList[config.group_id] = {}
|
||
end
|
||
local splitList = SL:Split(config.str, "<LINE>")
|
||
if #splitList > 1 then
|
||
for i = 1, #splitList do
|
||
local str = splitList[i]
|
||
if str and string.len(str) > 0 then
|
||
table.insert(descList[config.group_id], str)
|
||
end
|
||
if i ~= #splitList then
|
||
table.insert(descList[config.group_id], "line")
|
||
end
|
||
end
|
||
else
|
||
table.insert(descList[config.group_id], config.str)
|
||
end
|
||
end
|
||
else
|
||
local effect = parseDescEffect(config.str)
|
||
if effect then
|
||
table.insert(effectList, effect)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
for i, v in ipairs(SL:Split(tostring(desc), "#")) do
|
||
parse(v)
|
||
end
|
||
|
||
return descList, effectList
|
||
end
|
||
|
||
function GUIFunction:GetItemDescStrByGroup(list, groupId)
|
||
if not groupId or not list or not list[groupId] then
|
||
return
|
||
end
|
||
|
||
local strList = list[groupId]
|
||
local str = ""
|
||
for i = 1, #strList do
|
||
if strList[i] == "line" then
|
||
return nil, strList
|
||
end
|
||
str = string.format("%s%s%s", str, SL:ParseMetaValueStr(strList[i]), i ~= #strList and "<br>" or "")
|
||
end
|
||
return str
|
||
end
|
||
---------------------------------------------------
|
||
|
||
-- 物品是否显示拍卖行物品栏
|
||
function GUIFunction:CheckItemIsShowAuction(itemData)
|
||
return true
|
||
end
|
||
|
||
|
||
--------------------------- 聊天解析 begin-------------------------------
|
||
-- check 是否私聊频道
|
||
local function checkIsPrivateChannel(channelId)
|
||
return channelId == GUIDefine.ChatChannel.PRIVATE
|
||
end
|
||
|
||
-- fix chat Name
|
||
-- 处理发送者名字
|
||
function GUIFunction:ChatFixName(data)
|
||
local sendName = data.SendName or ""
|
||
local receiveName = data.ReceiveName or ""
|
||
local name = sendName
|
||
-- 私聊处理
|
||
if checkIsPrivateChannel(data.ChannelId) then
|
||
if data.SendId and SL:GetValue("ACTOR_IS_MAINPLAYER", data.SendId) then
|
||
name = "你对" .. "[" .. receiveName .. "]" .. "说"
|
||
else
|
||
if SL:GetValue("IS_PC_OPER_MODE") then
|
||
local levelStr = string.format(data.Suffix or "", data.Level or "")
|
||
name = string.format("[%s]%s", sendName, levelStr) .. "对你说"
|
||
else
|
||
name = "[" .. sendName .. "]" .. "对你说"
|
||
end
|
||
end
|
||
end
|
||
|
||
if name and string.len(name) > 0 then
|
||
return name .. ":"
|
||
end
|
||
return name
|
||
end
|
||
|
||
-- fix chat private time
|
||
-- 私聊时间格式化
|
||
function GUIFunction:ChatFixPrivateTime(data)
|
||
if checkIsPrivateChannel(data.ChannelId) then
|
||
local date = os.date("*t", data.SendTime or SL:GetValue("SERVER_TIME"))
|
||
return string.format("%d-%02d-%02d %02d:%02d:%02d", date.year, date.month, date.day, date.hour, date.min, date.sec)
|
||
end
|
||
return ""
|
||
end
|
||
|
||
-- fix chat msg
|
||
-- 使用类型:系统通知消息,需使用特定的富文本解析; 行会通知
|
||
function GUIFunction:ChatFixMsg(data, isPrivateTime)
|
||
local prefix = data.Prefix or ""
|
||
local name = self:ChatFixName(data)
|
||
local str = string.format("<outline size='0'>%s%s%s</outline>", prefix, name, data.Msg or "")
|
||
if isPrivateTime then
|
||
return string.format("<outline size='0'>%s%s</outline>", self:ChatFixPrivateTime(data), str)
|
||
end
|
||
return str
|
||
end
|
||
|
||
-- fix chat msg outline
|
||
-- 使用类型:系统通知消息,需使用FColor富文本解析; 系统通知消息,需使用SRText富文本解析
|
||
function GUIFunction:ChatFixMsgWithoutOutline(data, isPrivateTime)
|
||
local prefix = data.Prefix or ""
|
||
local name = self:ChatFixName(data)
|
||
local str = string.format("%s%s%s", prefix, name, data.Msg or "")
|
||
if isPrivateTime then
|
||
return string.format("%s%s", self:ChatFixPrivateTime(data), str)
|
||
end
|
||
return str
|
||
end
|
||
|
||
-- chat width
|
||
--- 获取单条聊天item宽度
|
||
---@param isMini boolean 是否是主界面的聊天item
|
||
---@param miniChatWidth integer 主界面的聊天item宽度
|
||
---@param isPCPrivate boolean 是否PC私聊页的聊天item
|
||
---@param isPCGuild boolean 是否PC行会聊天页的聊天item
|
||
function GUIFunction:ChatGetWidth(isMini, miniChatWidth, isPCPrivate, isPCGuild)
|
||
if isMini then
|
||
if SL:GetValue("IS_PC_OPER_MODE") then
|
||
return miniChatWidth or 722
|
||
else
|
||
return miniChatWidth or 310
|
||
end
|
||
elseif isPCPrivate then
|
||
return 345
|
||
elseif isPCGuild then
|
||
return 606
|
||
end
|
||
return 310
|
||
end
|
||
|
||
-- 获取聊天的通知类型的字体配置 -- isMini:是否主界面
|
||
function GUIFunction:ChatGetNoticeMsgFont(isMini, data)
|
||
local color = nil -- 字体颜色 0-255
|
||
local fontPath = nil -- 字体文件路径
|
||
local fontSize = nil -- 字体大小
|
||
return {color = color, fontPath = fontPath, fontSize = fontSize}
|
||
end
|
||
|
||
-- 查找表情
|
||
local emojiFindParam = {
|
||
replaceStr = nil, --表情字符串
|
||
findReplaceLen = {} --表情字符串的长度
|
||
}
|
||
-- 查找表情的数据解析
|
||
local function GetEmojiFindParam()
|
||
if not emojiFindParam.replaceStr then
|
||
emojiFindParam.replaceStr = ""
|
||
local emojiConfig = ChatData.GetEmoji()
|
||
for _, v in pairs(emojiConfig) do
|
||
emojiFindParam.replaceStr = emojiFindParam.replaceStr .. string.format("<%s&%d>", v.replace, v.ID)
|
||
if not emojiFindParam.findReplaceLen[string.len(v.replace)] then
|
||
emojiFindParam.findReplaceLen[string.len(v.replace)] = true
|
||
end
|
||
end
|
||
end
|
||
return emojiFindParam.replaceStr, emojiFindParam.findReplaceLen
|
||
end
|
||
|
||
-- chat parse
|
||
-- 解析普通类型的聊天数据
|
||
function GUIFunction:ChatParseNormal(msg)
|
||
msg = string.gsub(msg or "", "\n", " ")
|
||
local emojiConfig = ChatData.GetEmoji()
|
||
|
||
local color = nil -- 字体颜色 0-255
|
||
local opacity = nil -- 不透明度
|
||
local fontPath = nil -- 字体文件路径
|
||
local fontSize = nil -- 字体大小
|
||
local outColor = nil -- 字体描边颜色
|
||
local outlineSize = nil -- 字体描边大小
|
||
|
||
local chatParseT = {}
|
||
while string.len(msg) > 0 do
|
||
local fStar,fEnd = string.find(msg, "#")
|
||
if not fStar and not fEnd then
|
||
table.insert(chatParseT, {
|
||
text = msg,
|
||
color = color,
|
||
opacity = opacity,
|
||
fontPath = fontPath,
|
||
fontSize = fontSize,
|
||
outColor = outColor,
|
||
outlineSize = outlineSize
|
||
})
|
||
break
|
||
end
|
||
|
||
if fStar > 1 then
|
||
local prefixEmoJi = string.sub(msg, 1, fStar - 1) --截取表情前部分
|
||
msg = string.sub(msg, fStar)
|
||
table.insert(chatParseT, {
|
||
text = prefixEmoJi,
|
||
color = color,
|
||
opacity = opacity,
|
||
fontPath = fontPath,
|
||
fontSize = fontSize,
|
||
outColor = outColor,
|
||
outlineSize = outlineSize
|
||
})
|
||
end
|
||
|
||
-- 查找表情
|
||
local findEmoji = nil
|
||
local str, finLen = GetEmojiFindParam()
|
||
for _len, v in pairs(finLen) do
|
||
local emojiStr = string.sub(msg, 1, _len)
|
||
local regexS = string.format("(<%s&%%d+>)", emojiStr)
|
||
local matchS = string.match(str, regexS)
|
||
if emojiStr and matchS then
|
||
msg = string.sub(msg, _len + 1)
|
||
local mathcArray = string.split(matchS, "&")
|
||
local emojiID = tonumber(string.sub(mathcArray[2] or "", 1, -2))
|
||
if emojiID and emojiConfig[emojiID] then
|
||
findEmoji = emojiStr
|
||
table.insert(chatParseT, {sfxID = emojiConfig[emojiID].sfxid})
|
||
end
|
||
break
|
||
end
|
||
end
|
||
|
||
-- 没找到表情, 截取出"#"
|
||
if not findEmoji then
|
||
msg = string.sub(msg, fStar + 1)
|
||
table.insert(chatParseT, {
|
||
text = "#",
|
||
color = color,
|
||
opacity = opacity,
|
||
fontPath = fontPath,
|
||
fontSize = fontSize,
|
||
outColor = outColor,
|
||
outlineSize = outlineSize
|
||
})
|
||
end
|
||
end
|
||
|
||
return chatParseT
|
||
end
|
||
|
||
-- 解析坐标类型聊天数据
|
||
function GUIFunction:ChatParseEPosition(jsonData)
|
||
if nil == jsonData then
|
||
return {}
|
||
end
|
||
|
||
local color = nil -- 字体颜色 0-255
|
||
local opacity = nil -- 不透明度
|
||
local fontPath = nil -- 字体文件路径
|
||
local fontSize = nil -- 字体大小
|
||
local outColor = nil -- 字体描边颜色
|
||
local outlineSize = nil -- 字体描边大小
|
||
|
||
local str = string.format("[%s %s,%s]", jsonData.mapName, jsonData.mapX, jsonData.mapY)
|
||
local posLink = string.format("position#%s#%s#%s", jsonData.mapID, jsonData.mapX, jsonData.mapY)
|
||
local data = {}
|
||
table.insert(data, {
|
||
text = str,
|
||
link = posLink,
|
||
color = color,
|
||
opacity = opacity,
|
||
fontPath = fontPath,
|
||
fontSize = fontSize,
|
||
outColor = outColor,
|
||
outlineSize = outlineSize
|
||
})
|
||
return data
|
||
end
|
||
|
||
-- 解析装备类型聊天数据
|
||
function GUIFunction:ChatParseEItem(jsonData)
|
||
if nil == jsonData then
|
||
return {}
|
||
end
|
||
local color = nil -- 字体颜色 0-255
|
||
local opacity = nil -- 不透明度
|
||
-- 支持添加文本
|
||
|
||
local chatParseT = {}
|
||
table.insert(chatParseT, {equip = jsonData, color = color, opacity = opacity})
|
||
return chatParseT
|
||
end
|
||
|
||
-- 获取聊天富文本默认大小
|
||
function GUIFunction:GetChatRichFontSize()
|
||
return SL:GetValue("GAME_DATA", "DEFAULT_FONT_SIZE")
|
||
end
|
||
|
||
-- 触发私聊
|
||
function GUIFunction:PrivateChat(data, richText)
|
||
if data.SendId and data.SendName then
|
||
local mainPlayerID = SL:GetValue("USER_ID")
|
||
if data.SendId == mainPlayerID then
|
||
return
|
||
end
|
||
|
||
SL:onLUAEvent(LUA_EVENT_CHAT_PRIVATE_TARGET, {name = data.SendName, uid = data.SendId})
|
||
end
|
||
end
|
||
|
||
-- 聊天item添加右键点击事件
|
||
function GUIFunction:ChatItemOnMouseRightEvent(data, richText)
|
||
local mainPlayerID = SL:GetValue("USER_ID")
|
||
local targetID = data.SendId
|
||
if SL:GetValue("IS_PC_OPER_MODE") and targetID and targetID ~= mainPlayerID then
|
||
local function OpenFuncDock(touchPos)
|
||
if not SL:GetValue("ACTOR_IS_VALID", targetID) then
|
||
return 0
|
||
end
|
||
|
||
local dockType = FuncDockData.FuncDockType
|
||
if SL:GetValue("ACTOR_IS_PLAYER", targetID) and GUI:isClippingParentContainsPoint(richText, touchPos) then
|
||
UIOperator:OpenFuncDockTips({
|
||
type = SL:GetValue("ACTOR_IS_HUMAN", targetID) and dockType.Func_Monster_Head or dockType.Func_Player_Head,
|
||
targetId = targetID,
|
||
targetName = SL:GetValue("ACTOR_NAME", targetID) or "",
|
||
pos = {x = touchPos.x + 15, y = touchPos.y}
|
||
})
|
||
return
|
||
end
|
||
return 0
|
||
end
|
||
GUI:addMouseButtonEvent(richText, {
|
||
onSpecialRFunc = function()
|
||
return -1
|
||
end,
|
||
onRightDownFunc = OpenFuncDock,
|
||
needTouchPos = true,
|
||
})
|
||
end
|
||
end
|
||
|
||
-- 生成主界面聊天item
|
||
function GUIFunction:GenerateChatMiniItem(data)
|
||
local CHANNEL = GUIDefine.ChatChannel
|
||
local MSG_TYPE = GUIDefine.ChatTextType
|
||
local isWinMode = SL:GetValue("IS_PC_OPER_MODE")
|
||
|
||
data.FColor = data.FColor or 0
|
||
data.BColor = data.BColor or 255
|
||
local FColorHEX = SL:GetHexColorByStyleId(data.FColor)
|
||
local BColorEnable = data.BColor ~= -1
|
||
local BColorHEX = SL:GetHexColorByStyleId(data.BColor)
|
||
|
||
-- 默认字体字号
|
||
local defaultSize = GUIFunction:GetChatRichFontSize()
|
||
local defaultfontPath = GUIDefineEx.ChatRichFontPath
|
||
|
||
local miniWid = MainProperty and MainProperty.GetChatWidth()
|
||
local width = math.max(GUIFunction:ChatGetWidth(true, miniWid), 20)
|
||
local richText = nil
|
||
|
||
local cell = GUI:Widget_Create(-1, "cell", 0, 0, 0, 0)
|
||
|
||
local msgFont = GUIFunction:ChatGetNoticeMsgFont(true, data) or {}
|
||
local fontSize = msgFont.fontSize or defaultSize
|
||
local fontColor = msgFont.color and SL:GetHexColorByStyleId(msgFont.color) or FColorHEX
|
||
local fontPath = msgFont.fontPath or defaultfontPath
|
||
local space = GUIDefineEx.ChatContentInterval.richVspace
|
||
|
||
if (data.textType and data.textType == MSG_TYPE.SYSTEMTIPS) or (data.ChannelId == CHANNEL.GUILDTIPS) then
|
||
local str = GUIFunction:ChatFixMsg(data)
|
||
local hexColor = msgFont.color and SL:GetHexColorByStyleId(msgFont.color)
|
||
richText = GUI:RichText_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath)
|
||
|
||
elseif data.textType and data.textType == MSG_TYPE.FCTEXT then
|
||
local str = GUIFunction:ChatFixMsgWithoutOutline(data)
|
||
richText = GUI:RichTextFCOLOR_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath, {outlineSize = 0})
|
||
|
||
elseif data.textType and data.textType == MSG_TYPE.SRTEXT then
|
||
local str = GUIFunction:ChatFixMsgWithoutOutline(data)
|
||
richText = GUI:RichTextSR_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath)
|
||
|
||
else
|
||
local elements = {}
|
||
|
||
-- prefix
|
||
if data.Prefix and data.Prefix ~= "" then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "prefix_show", 0, 0, "TEXT", {
|
||
str = data.Prefix,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- vip label
|
||
if data.viplabel and data.viplabel ~= "" and data.vipcolor then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "vip_show", 0, 0, "TEXT", {
|
||
str = data.viplabel,
|
||
color = SL:GetHexColorByStyleId(data.vipcolor),
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- name
|
||
local str = GUIFunction:ChatFixName(data)
|
||
local element = GUI:RichTextCombineCell_Create(-1, "name_show", 0, 0, "TEXT", {
|
||
str = str,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
|
||
-- msg
|
||
local telements = GUIFunction:CreateChatRichElements(data)
|
||
for _, v in ipairs(telements) do
|
||
table.insert(elements, v)
|
||
end
|
||
|
||
-- 填充
|
||
richText = GUI:RichTextCombine_Create(cell, "RichText", 0, 0, width, space)
|
||
GUI:RichTextCombine_pushBackElements(richText, elements)
|
||
|
||
--
|
||
GUI:RichText_setOpenUrlEvent(richText, function(sender, str)
|
||
local slices = string.split(str, "#")
|
||
local command = slices[1]
|
||
if command == "position" then
|
||
local originScale = GUI:getScale(sender)
|
||
GUI:setScale(sender, originScale + 0.2)
|
||
local function reback()
|
||
GUI:setScale(sender, originScale)
|
||
end
|
||
SL:scheduleOnce(sender, reback, 0.03)
|
||
|
||
-- find position
|
||
local mapID = slices[2]
|
||
local x = tonumber(slices[3])
|
||
local y = tonumber(slices[4])
|
||
local moveType = GUIDefine.AutoMoveType.CHAT
|
||
SL:SetValue("BATTLE_MOVE_BEGIN", mapID, x, y, nil, moveType)
|
||
|
||
return nil
|
||
end
|
||
end)
|
||
|
||
GUI:RichTextCombine_format(richText)
|
||
end
|
||
if BColorEnable then
|
||
GUI:RichText_setBackgroundColor(richText, BColorHEX)
|
||
end
|
||
|
||
-- 与发送者私聊
|
||
if isWinMode then
|
||
local needFillInput = data.textType == MSG_TYPE.NORMAL
|
||
GUI:setTouchEnabled(richText, true)
|
||
GUI:setSwallowTouches(richText, false)
|
||
GUI:addOnClickEvent(richText, function()
|
||
local mainPlayerID = SL:GetValue("USER_ID")
|
||
if data.SendId and data.SendName and data.SendId ~= mainPlayerID then
|
||
GUIFunction:PrivateChat(data, richText)
|
||
elseif needFillInput then
|
||
SL:onLUAEvent(LUA_EVENT_PC_FILL_CHAT_INPUT, data.Msg)
|
||
end
|
||
end)
|
||
end
|
||
|
||
local richSize = GUI:getContentSize(richText)
|
||
GUI:setContentSize(cell, width, richSize.height)
|
||
-- 右键展示功能栏
|
||
if isWinMode then
|
||
if data.SendId and data.SendName then
|
||
GUIFunction:ChatItemOnMouseRightEvent(data, cell)
|
||
end
|
||
end
|
||
|
||
return cell
|
||
end
|
||
|
||
-- 生成聊天页聊天item
|
||
function GUIFunction:GenerateChatItem(data)
|
||
local CHANNEL = GUIDefine.ChatChannel
|
||
local MSG_TYPE = GUIDefine.ChatTextType
|
||
|
||
data.FColor = data.FColor or 0
|
||
data.BColor = data.BColor or 255
|
||
local FColorHEX = SL:GetHexColorByStyleId(data.FColor)
|
||
local BColorEnable = data.BColor ~= -1
|
||
local BColorHEX = SL:GetHexColorByStyleId(data.BColor)
|
||
|
||
-- 默认字体字号
|
||
local defaultSize = GUIFunction:GetChatRichFontSize()
|
||
local defaultfontPath = GUIDefineEx.ChatRichFontPath
|
||
|
||
local width = GUIFunction:ChatGetWidth(false)
|
||
local richText = nil
|
||
|
||
local cell = GUI:Widget_Create(-1, "cell", 0, 0, 0, 0)
|
||
|
||
local msgFont = GUIFunction:ChatGetNoticeMsgFont(false, data) or {}
|
||
local fontSize = msgFont.fontSize or defaultSize
|
||
local fontColor = msgFont.color and SL:GetHexColorByStyleId(msgFont.color) or FColorHEX
|
||
local fontPath = msgFont.fontPath or defaultfontPath
|
||
local space = GUIDefineEx.ChatContentInterval.richVspace
|
||
|
||
if (data.textType and data.textType == MSG_TYPE.SYSTEMTIPS) or (data.ChannelId == CHANNEL.GUILDTIPS) then
|
||
local str = GUIFunction:ChatFixMsg(data)
|
||
local hexColor = msgFont.color and SL:GetHexColorByStyleId(msgFont.color)
|
||
richText = GUI:RichText_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath)
|
||
|
||
elseif data.textType and data.textType == MSG_TYPE.FCTEXT then
|
||
local str = GUIFunction:ChatFixMsgWithoutOutline(data)
|
||
richText = GUI:RichTextFCOLOR_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath, {outlineSize = 0})
|
||
|
||
elseif data.textType and data.textType == MSG_TYPE.SRTEXT then
|
||
local str = GUIFunction:ChatFixMsgWithoutOutline(data)
|
||
richText = GUI:RichTextSR_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath)
|
||
|
||
else
|
||
local elements = {}
|
||
|
||
-- prefix
|
||
if data.Prefix and data.Prefix ~= "" then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "prefix_show", 0, 0, "TEXT", {
|
||
str = data.Prefix,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- vip label
|
||
if data.viplabel and data.viplabel ~= "" and data.vipcolor then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "vip_show", 0, 0, "TEXT", {
|
||
str = data.viplabel,
|
||
color = SL:GetHexColorByStyleId(data.vipcolor),
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- name
|
||
local str = GUIFunction:ChatFixName(data)
|
||
local element = GUI:RichTextCombineCell_Create(-1, "name_show", 0, 0, "TEXT", {
|
||
str = str,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
|
||
-- msg
|
||
local telements = GUIFunction:CreateChatRichElements(data)
|
||
for _, v in ipairs(telements) do
|
||
table.insert(elements, v)
|
||
end
|
||
|
||
-- 填充
|
||
richText = GUI:RichTextCombine_Create(cell, "RichText", 0, 0, width, space)
|
||
GUI:RichTextCombine_pushBackElements(richText, elements)
|
||
|
||
--
|
||
GUI:RichText_setOpenUrlEvent(richText, function(sender, str)
|
||
local slices = string.split(str, "#")
|
||
local command = slices[1]
|
||
if command == "position" then
|
||
local originScale = GUI:getScale(sender)
|
||
GUI:setScale(sender, originScale + 0.2)
|
||
local function reback()
|
||
GUI:setScale(sender, originScale)
|
||
end
|
||
SL:scheduleOnce(sender, reback, 0.03)
|
||
|
||
-- find position
|
||
local mapID = slices[2]
|
||
local x = tonumber(slices[3])
|
||
local y = tonumber(slices[4])
|
||
local moveType = GUIDefine.AutoMoveType.CHAT
|
||
SL:SetValue("BATTLE_MOVE_BEGIN", mapID, x, y, nil, moveType)
|
||
|
||
return nil
|
||
end
|
||
end)
|
||
|
||
GUI:RichTextCombine_format(richText)
|
||
end
|
||
if BColorEnable then
|
||
GUI:RichText_setBackgroundColor(richText, BColorHEX)
|
||
end
|
||
|
||
-- 与发送者私聊
|
||
GUI:setTouchEnabled(richText, true)
|
||
GUI:setSwallowTouches(richText, false)
|
||
GUI:addOnClickEvent(richText, function()
|
||
local mainPlayerID = SL:GetValue("USER_ID")
|
||
if data.SendId and data.SendName and data.SendId ~= mainPlayerID then
|
||
GUIFunction:PrivateChat(data, richText)
|
||
end
|
||
end)
|
||
|
||
local richSize = GUI:getContentSize(richText)
|
||
GUI:setAnchorPoint(richText, 0, 1)
|
||
GUI:setPosition(richText, 0, richSize.height)
|
||
|
||
GUI:setContentSize(cell, width, richSize.height)
|
||
GUI:setAnchorPoint(cell, 0, 0)
|
||
GUI:setPosition(cell, 40, 0)
|
||
|
||
if cell then
|
||
SL:onLUAEvent(LUA_EVENT_CHAT_ITEM_ADD, {item = cell, channel = data.ChannelId})
|
||
end
|
||
|
||
return cell
|
||
end
|
||
|
||
-- 生成PC私聊页聊天item
|
||
function GUIFunction:GenerateChatPCPrivateItem(data)
|
||
local CHANNEL = GUIDefine.ChatChannel
|
||
local MSG_TYPE = GUIDefine.ChatTextType
|
||
local isWinMode = SL:GetValue("IS_PC_OPER_MODE")
|
||
|
||
data.FColor = data.FColor or 0
|
||
data.BColor = data.BColor or 255
|
||
local FColorHEX = SL:GetHexColorByStyleId(data.FColor)
|
||
local BColorEnable = data.BColor ~= -1
|
||
local BColorHEX = SL:GetHexColorByStyleId(data.BColor)
|
||
|
||
-- 默认字体字号
|
||
local defaultSize = GUIFunction:GetChatRichFontSize()
|
||
local defaultfontPath = GUIDefineEx.ChatRichFontPath
|
||
|
||
local width = GUIFunction:ChatGetWidth(false, nil, true)
|
||
local richText = nil
|
||
|
||
local cell = GUI:Widget_Create(-1, "cell", 0, 0, 0, 0)
|
||
|
||
local msgFont = GUIFunction:ChatGetNoticeMsgFont() or {}
|
||
local fontSize = msgFont.fontSize or defaultSize
|
||
local fontColor = msgFont.color and SL:GetHexColorByStyleId(msgFont.color) or FColorHEX
|
||
local fontPath = msgFont.fontPath or defaultfontPath
|
||
local space = GUIDefineEx.ChatContentInterval.richVspace
|
||
|
||
if (data.textType and data.textType == MSG_TYPE.SYSTEMTIPS) or (data.ChannelId == CHANNEL.GUILDTIPS) then
|
||
local str = GUIFunction:ChatFixMsg(data, true)
|
||
local hexColor = msgFont.color and SL:GetHexColorByStyleId(msgFont.color)
|
||
richText = GUI:RichText_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath)
|
||
|
||
elseif data.textType and data.textType == MSG_TYPE.FCTEXT then
|
||
local str = GUIFunction:ChatFixMsgWithoutOutline(data, true)
|
||
richText = GUI:RichTextFCOLOR_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath, {outlineSize = 0})
|
||
|
||
elseif data.textType and data.textType == MSG_TYPE.SRTEXT then
|
||
local str = GUIFunction:ChatFixMsgWithoutOutline(data, true)
|
||
richText = GUI:RichTextSR_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath)
|
||
|
||
else
|
||
local elements = {}
|
||
|
||
-- 时间
|
||
local timeStr = GUIFunction:ChatFixPrivateTime(data)
|
||
if timeStr and timeStr ~= "" then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "private_time", 0, 0, "TEXT", {
|
||
str = timeStr,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- prefix
|
||
if data.Prefix and data.Prefix ~= "" then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "prefix_show", 0, 0, "TEXT", {
|
||
str = data.Prefix,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- vip label
|
||
if data.viplabel and data.viplabel ~= "" and data.vipcolor then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "vip_show", 0, 0, "TEXT", {
|
||
str = data.viplabel,
|
||
color = SL:GetHexColorByStyleId(data.vipcolor),
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- name
|
||
local str = GUIFunction:ChatFixName(data)
|
||
local element = GUI:RichTextCombineCell_Create(-1, "name_show", 0, 0, "TEXT", {
|
||
str = str,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
|
||
-- msg
|
||
local telements = GUIFunction:CreateChatRichElements(data)
|
||
for _, v in ipairs(telements) do
|
||
table.insert(elements, v)
|
||
end
|
||
|
||
-- 填充
|
||
richText = GUI:RichTextCombine_Create(cell, "RichText", 0, 0, width, space)
|
||
GUI:RichTextCombine_pushBackElements(richText, elements)
|
||
|
||
--
|
||
GUI:RichText_setOpenUrlEvent(richText, function(sender, str)
|
||
local slices = string.split(str, "#")
|
||
local command = slices[1]
|
||
if command == "position" then
|
||
local originScale = GUI:getScale(sender)
|
||
GUI:setScale(sender, originScale + 0.2)
|
||
local function reback()
|
||
GUI:setScale(sender, originScale)
|
||
end
|
||
SL:scheduleOnce(sender, reback, 0.03)
|
||
|
||
-- find position
|
||
local mapID = slices[2]
|
||
local x = tonumber(slices[3])
|
||
local y = tonumber(slices[4])
|
||
local moveType = GUIDefine.AutoMoveType.CHAT
|
||
SL:SetValue("BATTLE_MOVE_BEGIN", mapID, x, y, nil, moveType)
|
||
|
||
return nil
|
||
end
|
||
end)
|
||
|
||
GUI:RichTextCombine_format(richText)
|
||
end
|
||
if BColorEnable then
|
||
GUI:RichText_setBackgroundColor(richText, BColorHEX)
|
||
end
|
||
|
||
-- 与发送者私聊
|
||
if isWinMode then
|
||
GUI:setTouchEnabled(richText, true)
|
||
GUI:setSwallowTouches(richText, false)
|
||
GUI:addOnClickEvent(richText, function()
|
||
local mainPlayerID = SL:GetValue("USER_ID")
|
||
if data.SendId and data.SendName and data.SendId ~= mainPlayerID then
|
||
GUIFunction:PrivateChat(data, richText)
|
||
end
|
||
end)
|
||
end
|
||
|
||
local richSize = GUI:getContentSize(richText)
|
||
GUI:setAnchorPoint(richText, 0, 1)
|
||
GUI:setPosition(richText, 0, richSize.height)
|
||
|
||
GUI:setContentSize(cell, width, richSize.height)
|
||
GUI:setAnchorPoint(cell, 0, 0)
|
||
GUI:setPosition(cell, 40, 0)
|
||
-- 右键展示功能栏
|
||
if isWinMode then
|
||
if data.SendId and data.SendName then
|
||
GUIFunction:ChatItemOnMouseRightEvent(data, cell)
|
||
end
|
||
end
|
||
|
||
return cell
|
||
end
|
||
|
||
-- 生成PC行会聊天页聊天item
|
||
function GUIFunction:GenerateChatPCGuildItem(data)
|
||
local CHANNEL = GUIDefine.ChatChannel
|
||
local MSG_TYPE = GUIDefine.ChatTextType
|
||
local isWinMode = SL:GetValue("IS_PC_OPER_MODE")
|
||
|
||
data.FColor = data.FColor or 0
|
||
data.BColor = data.BColor or 255
|
||
local FColorHEX = SL:GetHexColorByStyleId(data.FColor)
|
||
local BColorEnable = data.BColor ~= -1
|
||
local BColorHEX = SL:GetHexColorByStyleId(data.BColor)
|
||
|
||
-- 默认字体字号
|
||
local defaultSize = GUIFunction:GetChatRichFontSize()
|
||
local defaultfontPath = GUIDefineEx.ChatRichFontPath
|
||
|
||
local width = GUIFunction:ChatGetWidth(false, nil, false, true)
|
||
local richText = nil
|
||
|
||
local cell = GUI:Widget_Create(-1, "cell", 0, 0, 0, 0)
|
||
|
||
local msgFont = GUIFunction:ChatGetNoticeMsgFont() or {}
|
||
local fontSize = msgFont.fontSize or defaultSize
|
||
local fontColor = msgFont.color and SL:GetHexColorByStyleId(msgFont.color) or FColorHEX
|
||
local fontPath = msgFont.fontPath or defaultfontPath
|
||
local space = GUIDefineEx.ChatContentInterval.richVspace
|
||
|
||
if (data.textType and data.textType == MSG_TYPE.SYSTEMTIPS) or (data.ChannelId == CHANNEL.GUILDTIPS) then
|
||
local str = GUIFunction:ChatFixMsg(data, true)
|
||
local hexColor = msgFont.color and SL:GetHexColorByStyleId(msgFont.color)
|
||
richText = GUI:RichText_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath)
|
||
|
||
elseif data.textType and data.textType == MSG_TYPE.FCTEXT then
|
||
local str = GUIFunction:ChatFixMsgWithoutOutline(data, true)
|
||
richText = GUI:RichTextFCOLOR_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath, {outlineSize = 0})
|
||
|
||
elseif data.textType and data.textType == MSG_TYPE.SRTEXT then
|
||
local str = GUIFunction:ChatFixMsgWithoutOutline(data, true)
|
||
richText = GUI:RichTextSR_Create(cell, "RichText", 0, 0, str, width, fontSize, fontColor, space, nil, fontPath)
|
||
|
||
else
|
||
local elements = {}
|
||
|
||
-- prefix
|
||
if data.Prefix and data.Prefix ~= "" then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "prefix_show", 0, 0, "TEXT", {
|
||
str = data.Prefix,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- vip label
|
||
if data.viplabel and data.viplabel ~= "" and data.vipcolor then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "vip_show", 0, 0, "TEXT", {
|
||
str = data.viplabel,
|
||
color = SL:GetHexColorByStyleId(data.vipcolor),
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
|
||
-- name
|
||
local str = GUIFunction:ChatFixName(data)
|
||
local element = GUI:RichTextCombineCell_Create(-1, "name_show", 0, 0, "TEXT", {
|
||
str = str,
|
||
color = FColorHEX,
|
||
fontPath = defaultfontPath,
|
||
fontSize = defaultSize
|
||
})
|
||
table.insert(elements, element)
|
||
|
||
-- msg
|
||
local telements = GUIFunction:CreateChatRichElements(data)
|
||
for _, v in ipairs(telements) do
|
||
table.insert(elements, v)
|
||
end
|
||
|
||
-- 填充
|
||
richText = GUI:RichTextCombine_Create(cell, "RichText", 0, 0, width, space)
|
||
GUI:RichTextCombine_pushBackElements(richText, elements)
|
||
|
||
--
|
||
GUI:RichText_setOpenUrlEvent(richText, function(sender, str)
|
||
local slices = string.split(str, "#")
|
||
local command = slices[1]
|
||
if command == "position" then
|
||
local originScale = GUI:getScale(sender)
|
||
GUI:setScale(sender, originScale + 0.2)
|
||
local function reback()
|
||
GUI:setScale(sender, originScale)
|
||
end
|
||
SL:scheduleOnce(sender, reback, 0.03)
|
||
|
||
-- find position
|
||
local mapID = slices[2]
|
||
local x = tonumber(slices[3])
|
||
local y = tonumber(slices[4])
|
||
local moveType = GUIDefine.AutoMoveType.CHAT
|
||
SL:SetValue("BATTLE_MOVE_BEGIN", mapID, x, y, nil, moveType)
|
||
|
||
return nil
|
||
end
|
||
end)
|
||
|
||
GUI:RichTextCombine_format(richText)
|
||
end
|
||
if BColorEnable then
|
||
GUI:RichText_setBackgroundColor(richText, BColorHEX)
|
||
end
|
||
|
||
-- 与发送者私聊
|
||
if isWinMode then
|
||
GUI:setTouchEnabled(richText, true)
|
||
GUI:setSwallowTouches(richText, false)
|
||
GUI:addOnClickEvent(richText, function()
|
||
local mainPlayerID = SL:GetValue("USER_ID")
|
||
if data.SendId and data.SendName and data.SendId ~= mainPlayerID then
|
||
GUIFunction:PrivateChat(data, richText)
|
||
end
|
||
end)
|
||
end
|
||
|
||
local richSize = GUI:getContentSize(richText)
|
||
GUI:setAnchorPoint(richText, 0, 1)
|
||
GUI:setPosition(richText, 0, richSize.height)
|
||
|
||
GUI:setContentSize(cell, width, richSize.height)
|
||
GUI:setAnchorPoint(cell, 0, 0)
|
||
GUI:setPosition(cell, 40, 0)
|
||
-- 右键展示功能栏
|
||
if isWinMode then
|
||
if data.SendId and data.SendName then
|
||
GUIFunction:ChatItemOnMouseRightEvent(data, cell)
|
||
end
|
||
end
|
||
|
||
return cell
|
||
end
|
||
|
||
-------- 解析消息元素
|
||
-- 普通
|
||
local function createNormalElements(msg, defaultfontPath, defaultSize, color, outlineColor, outlineSize, isActorSay)
|
||
local elements = {}
|
||
local defaultOutlineColor = outlineColor or "#000000"
|
||
local defaultOutlineSize = outlineSize or 0
|
||
local emojiOffSetY = isActorSay and -4 or 0
|
||
local parseT = GUIFunction:ChatParseNormal(msg)
|
||
for i, v in ipairs(parseT) do
|
||
if v.text then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "normal_text", 0, 0, "TEXT", {
|
||
str = v.text,
|
||
color = v.color and SL:GetHexColorByStyleId(v.color) or color,
|
||
opacity = v.opacity,
|
||
fontPath = v.fontPath or defaultfontPath,
|
||
fontSize = v.fontSize or defaultSize,
|
||
outlineColor = v.outColor and SL:GetHexColorByStyleId(v.outColor) or defaultOutlineColor,
|
||
outlineSize = v.outlineSize or defaultOutlineSize
|
||
})
|
||
table.insert(elements, element)
|
||
elseif v.sfxID then
|
||
-- 创建一个表情
|
||
local layout = GUI:Layout_Create(-1, "emoji_panel", 0, 0, 36, 36)
|
||
GUI:addStateEvent(layout, function(state)
|
||
if state == "enter" then
|
||
GUI:removeAllChildren(layout)
|
||
local size = GUI:getContentSize(layout)
|
||
local emojiSfx = GUI:Effect_Create(layout, "emoji_sfx", size.width / 2, size.height / 2 + emojiOffSetY, 0, v.sfxID)
|
||
GUI:setScale(emojiSfx, 0.7)
|
||
end
|
||
end)
|
||
local element = GUI:RichTextCombineCell_Create(-1, "emoji_element", 0, 0, "NODE", {node = layout})
|
||
table.insert(elements, element)
|
||
end
|
||
end
|
||
return elements
|
||
end
|
||
|
||
-- 坐标
|
||
local function parseEPosition(msg, defaultfontPath, defaultSize)
|
||
local elements = {}
|
||
local jsonData = SL:JsonDecode(msg)
|
||
local parseT = GUIFunction:ChatParseEPosition(jsonData)
|
||
local color = "#00cb52" -- 默认色值
|
||
for i, v in ipairs(parseT) do
|
||
if v.text then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "position_text", 0, 0, "TEXT", {
|
||
str = v.text,
|
||
color = v.color and SL:GetHexColorByStyleId(v.color) or color,
|
||
opacity = v.opacity,
|
||
fontPath = v.fontPath or defaultfontPath,
|
||
fontSize = v.fontSize or defaultSize,
|
||
link = v.link or "",
|
||
outlineColor = v.outColor and SL:GetHexColorByStyleId(v.outColor) or "#000000",
|
||
outlineSize = v.outlineSize or 0
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
end
|
||
return elements
|
||
end
|
||
|
||
-- 装备
|
||
local function parseEItem(msg, defaultfontPath, defaultSize, color)
|
||
local jsonData = SL:JsonDecode(msg)
|
||
if type(jsonData.ExtendInfo) == "string" then
|
||
jsonData.ExtendInfo = SL:JsonDecode(jsonData.ExtendInfo)
|
||
end
|
||
jsonData = SL:TransItemDataIntoChatShow(jsonData)
|
||
|
||
local elements = {}
|
||
local parseT = GUIFunction:ChatParseEItem(jsonData)
|
||
local isPc = SL:GetValue("IS_PC_OPER_MODE")
|
||
local size = isPc and {width = 40, height = 40} or {width = 66, height = 66}
|
||
for i, v in ipairs(parseT) do
|
||
if v.text then
|
||
local element = GUI:RichTextCombineCell_Create(-1, "equip_text", 0, 0, "TEXT", {
|
||
str = v.text,
|
||
color = v.color and SL:GetHexColorByStyleId(v.color) or color,
|
||
opacity = v.opacity,
|
||
fontPath = v.fontPath or defaultfontPath,
|
||
fontSize = v.fontSize or defaultSize,
|
||
link = v.link or "",
|
||
outlineColor = v.outColor and SL:GetHexColorByStyleId(v.outColor) or "#000000",
|
||
outlineSize = v.outlineSize or 0
|
||
})
|
||
table.insert(elements, element)
|
||
elseif v.equip then
|
||
-- 创建道具item
|
||
local layout = GUI:Layout_Create(-1, "item_panel", 0, 0, size.width, size.height)
|
||
GUI:addStateEvent(layout, function(state)
|
||
if state == "enter" then
|
||
GUI:removeAllChildren(layout)
|
||
local item = GUI:ItemShow_Create(layout, "item", size.width / 2, size.height / 2, {
|
||
index = v.equip.Index,
|
||
itemData = v.equip,
|
||
look = true,
|
||
bgVisible = true,
|
||
checkPower = true
|
||
})
|
||
GUI:setAnchorPoint(item, 0.5, 0.5)
|
||
end
|
||
end)
|
||
local element = GUI:RichTextCombineCell_Create(-1, "equip_element", 0, 0, "NODE", {
|
||
node = layout,
|
||
color = v.color and SL:GetHexColorByStyleId(v.color) or "#FFFFFF",
|
||
opacity = v.opacity or 255
|
||
})
|
||
table.insert(elements, element)
|
||
end
|
||
end
|
||
return elements
|
||
end
|
||
|
||
-- 创建不同类型聊天富文本元素
|
||
function GUIFunction:CreateChatRichElements(data)
|
||
data.FColor = data.FColor or 0
|
||
data.BColor = data.BColor or 255
|
||
local FColorHEX = SL:GetHexColorByStyleId(data.FColor)
|
||
local BColorHEX = SL:GetHexColorByStyleId(data.BColor)
|
||
|
||
-- 默认字体字号
|
||
local defaultSize = GUIFunction:GetChatRichFontSize()
|
||
local defaultfontPath = GUIDefineEx.ChatRichFontPath
|
||
|
||
local mt = tonumber(data.MT) or 0
|
||
local msg = data.Msg
|
||
|
||
if mt == GUIDefine.ChatMsgType.POSITION then
|
||
return parseEPosition(msg, defaultfontPath, defaultSize)
|
||
|
||
elseif mt == GUIDefine.ChatMsgType.EQUIP then
|
||
return parseEItem(msg, defaultfontPath, defaultSize, FColorHEX)
|
||
end
|
||
|
||
return createNormalElements(msg, defaultfontPath, defaultSize, FColorHEX)
|
||
end
|
||
|
||
-- 处理私聊名字后接空格状况
|
||
function GUIFunction:FixPrivateChatMsgWithSpace(findInfo)
|
||
local name = string.trim(findInfo[3]) or ""
|
||
local fStar, fEnd = string.find(name, " ")
|
||
local content = ""
|
||
if fStar and fEnd then
|
||
content = string.sub(name, fEnd + 1, -1)
|
||
name = string.sub(name, 1, fStar - 1)
|
||
end
|
||
content = content .. (findInfo[4] or "")
|
||
return name, content
|
||
end
|
||
|
||
-- 根据聊天消息内容获取对应频道
|
||
function GUIFunction:GetChannelByChatMsg(msg)
|
||
local channel = nil
|
||
local content = msg
|
||
local targetName = nil
|
||
for _, v in ipairs(GUIDefine.ChatChannelPrefix) do
|
||
local pattern = v.pattern or "^" .. v.prefix .. "(.+)"
|
||
local findInfo = {string.find(msg, pattern)}
|
||
if findInfo[1] and findInfo[2] then
|
||
channel = v.channel
|
||
local rContent = findInfo[3]
|
||
if channel == GUIDefine.ChatChannel.PRIVATE then
|
||
local fName, fContent = GUIFunction:FixPrivateChatMsgWithSpace(findInfo)
|
||
rContent = fContent
|
||
if fName and string.len(fName) > 0 then
|
||
targetName = fName
|
||
end
|
||
end
|
||
content = rContent
|
||
break
|
||
end
|
||
end
|
||
|
||
if not channel then -- 新增 /名字 直接私聊
|
||
local findInfo = {string.find(msg, "^/.+")}
|
||
if findInfo[1] and findInfo[2] then
|
||
channel = GUIDefine.ChatChannel.PRIVATE
|
||
findInfo[3] = string.sub(msg, 2, -1)
|
||
local fName, fContent = GUIFunction:FixPrivateChatMsgWithSpace(findInfo)
|
||
content = fContent .. " "
|
||
if fName and string.len(fName) > 0 then
|
||
targetName = fName
|
||
end
|
||
end
|
||
end
|
||
|
||
return channel, content, targetName
|
||
end
|
||
|
||
-- 根据聊天消息内容获取聊天对象
|
||
function GUIFunction:FindTargetByChatMsg(msg)
|
||
local pattern = nil
|
||
local res = nil
|
||
for _, v in pairs(GUIDefine.ChatChannelPrefix) do
|
||
if v.channel == GUIDefine.ChatChannel.PRIVATE then
|
||
pattern = v.pattern
|
||
break
|
||
end
|
||
end
|
||
|
||
if not pattern then
|
||
return res
|
||
else
|
||
local findInfo = {string.find(msg, pattern)}
|
||
if findInfo[1] and findInfo[2] then
|
||
local rName, rContent = GUIFunction:FixPrivateChatMsgWithSpace(findInfo)
|
||
res = rName
|
||
end
|
||
if not res then
|
||
findInfo = {string.find(msg, "^/(.+)")}
|
||
if findInfo[1] and findInfo[2] then
|
||
res = string.gsub(findInfo[3], " ", "")
|
||
end
|
||
end
|
||
end
|
||
|
||
return res
|
||
end
|
||
|
||
-- 检查频道能否发送聊天
|
||
function GUIFunction:CheckAbleToSayByChannel(channel)
|
||
if GUIDefine.ChatChannel.PRIVATE == channel then
|
||
-- 私聊
|
||
local targets = ChatData.GetTargets()
|
||
if not targets or not targets[1] then
|
||
SL:ShowSystemTips("没有可以发送的目标")
|
||
return false
|
||
end
|
||
|
||
elseif GUIDefine.ChatChannel.SYSTEM == channel then
|
||
-- 系统
|
||
SL:ShowSystemTips("系统频道无法发言")
|
||
return false
|
||
end
|
||
|
||
-- cding
|
||
if ChatData.GetCDTime(channel) > 0 then
|
||
SL:ShowSystemTips(string.format("您还需等待%s秒才能发言", ChatData.GetCDTime(channel)))
|
||
return false
|
||
end
|
||
|
||
local ret, buffID = SL:GetValue("BUFF_CHECK_CHAT_ENABLE")
|
||
if not ret then
|
||
if buffID then
|
||
local config = SL:GetValue("BUFF_CONFIG", buffID) or {}
|
||
if config.bufftitle then
|
||
SL:ShowSystemTips(config.bufftitle)
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
return true
|
||
end
|
||
|
||
-- 处理聊天消息长度限制
|
||
function GUIFunction:HandleLimitChatMsg(data)
|
||
if data and type(data.Msg) == "string" then
|
||
if data and string.utf8len(data.Msg or "") > GUIDefine.ChatConfig.MSG_LIMIT_COUNT then
|
||
data.Msg = SL:GetUTF8SubString(data.Msg, 1, GUIDefine.ChatConfig.MSG_LIMIT_COUNT)
|
||
end
|
||
end
|
||
|
||
if data and type(data.oriMsg) == "string" then
|
||
if data and string.utf8len(data.oriMsg or "") > GUIDefine.ChatConfig.MSG_LIMIT_COUNT then
|
||
data.oriMsg = SL:GetUTF8SubString(data.Msg, 1, GUIDefine.ChatConfig.MSG_LIMIT_COUNT)
|
||
end
|
||
end
|
||
return data
|
||
end
|
||
|
||
-- 获取聊天频道默认CD
|
||
function GUIFunction:GetChatCDParam(channel)
|
||
if not GUIDefine.ChatCDTime then
|
||
GUIDefine.ChatCDTime = {}
|
||
end
|
||
|
||
if not next(GUIDefine.ChatCDTime) then
|
||
local chatCDs = SL:GetValue("GAME_DATA", "CHATCDS")
|
||
if chatCDs and chatCDs ~= "" then
|
||
local cdvec = string.split(chatCDs, "|")
|
||
GUIDefine.ChatCDTime = {
|
||
[GUIDefine.ChatChannel.PRIVATE] = tonumber(cdvec[GUIDefine.ChatChannel.PRIVATE]), -- 私聊
|
||
[GUIDefine.ChatChannel.NEAR] = tonumber(cdvec[GUIDefine.ChatChannel.NEAR]), -- 附近
|
||
[GUIDefine.ChatChannel.SHOUT] = tonumber(cdvec[GUIDefine.ChatChannel.SHOUT]), -- 世界
|
||
[GUIDefine.ChatChannel.TEAM] = tonumber(cdvec[GUIDefine.ChatChannel.TEAM]), -- 组队
|
||
[GUIDefine.ChatChannel.GUILD] = tonumber(cdvec[GUIDefine.ChatChannel.GUILD]), -- 行会
|
||
[GUIDefine.ChatChannel.UNION] = tonumber(cdvec[GUIDefine.ChatChannel.UNION]), -- 联盟
|
||
[GUIDefine.ChatChannel.WORLD] = tonumber(cdvec[GUIDefine.ChatChannel.WORLD]), -- 传音
|
||
[GUIDefine.ChatChannel.NATION] = tonumber(cdvec[GUIDefine.ChatChannel.NATION]), -- 国家
|
||
[GUIDefine.ChatChannel.SYSTEM] = tonumber(cdvec[GUIDefine.ChatChannel.SYSTEM]) or 0, -- 系统
|
||
[GUIDefine.ChatChannel.CROSS] = tonumber(cdvec[GUIDefine.ChatChannel.CROSS]), -- 跨服
|
||
}
|
||
end
|
||
end
|
||
|
||
return GUIDefine.ChatCDTime[channel] or 1
|
||
end
|
||
|
||
-- 发送聊天消息
|
||
function GUIFunction:SendChatMsg(data)
|
||
local CHANNEL = GUIDefine.ChatChannel
|
||
local isPCMode = SL:GetValue("IS_PC_OPER_MODE")
|
||
|
||
if SL:GetValue("M2_FORBID_SAY") then
|
||
-- exclude gm
|
||
if not (type(data.msg) == "string" and string.find(data.msg, "^@.-")) then
|
||
SL:ShowSystemChat("本地图禁止说话聊天", 255, 249)
|
||
return
|
||
end
|
||
end
|
||
|
||
if not data or not data.msg then
|
||
SL:Print("error: function GUIFunction:SendChatMsg(data) 1")
|
||
return nil
|
||
end
|
||
|
||
data.textType = data.textType or GUIDefine.ChatTextType.NORMAL
|
||
data.msg = data.msg
|
||
data.originMsg = data.msg
|
||
|
||
-- PC端指定频道, 但内容为私聊则发送私聊
|
||
if isPCMode and data.channel and type(data.msg) == "string" then
|
||
local channel, content = GUIFunction:GetChannelByChatMsg(data.msg)
|
||
if channel and channel == CHANNEL.PRIVATE then
|
||
data.msg = content
|
||
data.channel = channel
|
||
|
||
local targetName = GUIFunction:FindTargetByChatMsg(data.originMsg)
|
||
if targetName then
|
||
ChatData.AddTarget({name = targetName, uid = data.uid})
|
||
end
|
||
end
|
||
end
|
||
|
||
-- PC端不指定频道,由内容决定
|
||
if isPCMode and nil == data.channel and type(data.msg) == "string" then
|
||
local channel, content = GUIFunction:GetChannelByChatMsg(data.msg)
|
||
channel = channel or CHANNEL.NEAR
|
||
data.msg = content
|
||
data.channel = channel
|
||
|
||
if data.channel == CHANNEL.PRIVATE then
|
||
local targetName = GUIFunction:FindTargetByChatMsg(data.originMsg)
|
||
if targetName then
|
||
ChatData.AddTarget({name = targetName, uid = data.uid})
|
||
end
|
||
end
|
||
end
|
||
|
||
-- 兼容PC端前缀
|
||
if not isPCMode and type(data.msg) == "string" then
|
||
local channel, content = GUIFunction:GetChannelByChatMsg(data.msg)
|
||
if channel and channel ~= CHANNEL.PRIVATE then
|
||
data.msg = content
|
||
data.channel = channel
|
||
end
|
||
end
|
||
|
||
-- 手机端添加 任何频道都能私聊的功能
|
||
if not isPCMode and type(data.msg) == "string" then
|
||
local channel, content = GUIFunction:GetChannelByChatMsg(data.msg)
|
||
if channel and channel == CHANNEL.PRIVATE then
|
||
data.msg = content
|
||
data.channel = channel
|
||
local targetName = GUIFunction:FindTargetByChatMsg(data.originMsg)
|
||
if targetName then
|
||
ChatData.AddTarget({name = targetName})
|
||
end
|
||
end
|
||
end
|
||
|
||
if not data.channel then
|
||
SL:Print("error: function GUIFunction:OnSendChatMsg(data) 2")
|
||
return nil
|
||
end
|
||
|
||
-- 是否可发送
|
||
if not GUIFunction:CheckAbleToSayByChannel(data.channel) then
|
||
local checkMsg = data.originMsg or data.msg or ""
|
||
if not (type(checkMsg) == "string" and string.sub(checkMsg, 1, 1) == "@") then -- 如果是@开头的GM命令,要进行发送
|
||
return nil
|
||
end
|
||
end
|
||
|
||
-- 消息结构
|
||
local item = {}
|
||
item.MT = data.mt
|
||
item.Msg = data.msg
|
||
item.Type = data.channel
|
||
|
||
-- 行会
|
||
if data.channel == CHANNEL.GUILD then
|
||
if not SL:GetValue("GUILD_IS_JOINED") then
|
||
SL:ShowSystemTips("当前无行会,无法发送行会消息,请加入行会")
|
||
return nil
|
||
end
|
||
end
|
||
-- 队伍
|
||
if data.channel == CHANNEL.TEAM then
|
||
if not SL:GetValue("TEAM_IS_MEMBER") then
|
||
SL:ShowSystemTips("当前无队伍,无法发送组队消息")
|
||
return nil
|
||
end
|
||
end
|
||
-- 私聊
|
||
if data.channel == CHANNEL.PRIVATE then
|
||
local target = ChatData.GetTargets()[1]
|
||
if not target then
|
||
SL:ShowSystemTips("请选择私聊对象")
|
||
return nil
|
||
end
|
||
-- 黑名单
|
||
if SL:GetValue("SOCIAL_IS_BLACKLIST", target.name) then
|
||
SL:ShowSystemTips("对方在你的黑名单,无法向其发送信息")
|
||
return nil
|
||
end
|
||
item.Target = target.uid
|
||
item.TargetName = target.name
|
||
end
|
||
|
||
if data.channel == CHANNEL.NATION then
|
||
if not SL:GetValue("NATION_IS_JOINED") then
|
||
SL:ShowSystemTips("当前无国家,无法发送国家消息,请加入国家")
|
||
return
|
||
end
|
||
end
|
||
|
||
-- 风险等级
|
||
item.risk = data.risk
|
||
-- 原始文本
|
||
item.oriMsg = data.oriMsg
|
||
-- 匹配到的敏感词
|
||
item.sensitiveWords = data.sensitiveWords
|
||
-- 敏感词状态 0: 无标记 1: 被隐藏 2: 静默 3: 静默+被隐藏
|
||
item.status = data.status
|
||
|
||
-- send...
|
||
item = GUIFunction:HandleLimitChatMsg(item)
|
||
SL:RequestSendChatMsg(item)
|
||
|
||
-- cd... exclude gm
|
||
if not (type(data.msg) == "string" and string.find(data.msg, "^@.-")) then
|
||
local cd = GUIFunction:GetChatCDParam(data.channel)
|
||
ChatData.SetCDTime(data.channel, cd)
|
||
end
|
||
end
|
||
|
||
--------------------------- 聊天解析 end-------------------------------
|
||
|
||
--------------------------- 拍卖行相关 -------------------------------
|
||
-- 拍卖行价格显示 格式
|
||
function GUIFunction:FixAuctionPrice(price, unit)
|
||
if unit then
|
||
if price >= 100000000 then
|
||
return string.format("%.1f%s", price / 100000000, "亿")
|
||
end
|
||
if price >= 10000 then
|
||
return string.format("%.1f%s", price / 10000, "万")
|
||
end
|
||
return tostring(price)
|
||
end
|
||
return tostring(price)
|
||
end
|
||
|
||
-- 检查寄售cell是否显示在视图内
|
||
function GUIFunction:CheckAuctionCellShowInView(cell, view)
|
||
local posY = GUI:getPositionY(cell)
|
||
local cellH = GUI:getContentSize(cell).height
|
||
local anchorY = GUI:getAnchorPoint(cell).y
|
||
local sizeH = GUI:getContentSize(view).height
|
||
local innerPosY = GUI:ScrollView_getInnerContainerPosition(view).y
|
||
local isShow = (posY + (1 - anchorY) * cellH) >= -innerPosY and posY <= (-innerPosY + sizeH)
|
||
return isShow
|
||
end
|
||
---------------------------------------------------------------------
|
||
|
||
-------------------------------------------------------------------------
|
||
-- 客户端释放技能前是否允许执行
|
||
function GUIFunction:OnCheckAllowLaunchSkillBefore(skillID)
|
||
|
||
-- 是否继续释放技能
|
||
return true
|
||
end
|
||
|
||
-- 判断能否自动拾取该物品 [内部判断可自动拾取后的额外判断]
|
||
-- 参数: itemIndex 道具Index , bySprite: 是否小精灵自动拾取 boolean
|
||
-- 返回值: boolean
|
||
function GUIFunction:CheckAutoPickItemEnable_Extra(itemIndex, bySprite)
|
||
|
||
return true
|
||
end
|
||
|
||
-------------------------------------------------------------------------
|
||
|
||
--是否英雄人物面板合并
|
||
function GUIFunction:IsPlayerHeroMergeMode()
|
||
if not SL:GetValue("IS_PC_OPER_MODE") and tostring(SL:GetValue("GAME_DATA","playerInfoMode")) == "1" and tostring(SL:GetValue("GAME_DATA","syshero")) == "1" then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
-- 是否是自己
|
||
function GUIFunction:IsMe(actorID)
|
||
return actorID == SL:GetValue("USERID")
|
||
end
|
||
|
||
function GUIFunction:KeyMapXY(x, y)
|
||
return y * 65536 + x
|
||
end
|
||
|
||
local MOVE_ACTIONS = {
|
||
[GUIDefine.Action.WALK] = true, -- 走
|
||
[GUIDefine.Action.RUN] = true, -- 跑
|
||
[GUIDefine.Action.RIDE_RUN] = true, -- 坐骑跑
|
||
[GUIDefine.Action.DASH] = true, -- 野蛮
|
||
[GUIDefine.Action.ONPUSH] = true, -- 被野蛮/被推开
|
||
[GUIDefine.Action.TELEPORT] = true, -- 瞬移
|
||
[GUIDefine.Action.ZXC] = true, -- 追心刺
|
||
[GUIDefine.Action.SBYS] = true, -- 十步一杀
|
||
[GUIDefine.Action.ASSASSIN_SNEAK] = true -- 潜行
|
||
}
|
||
|
||
-- actor移动
|
||
function GUIFunction:IsMoveAction(act)
|
||
return MOVE_ACTIONS[act]
|
||
end
|
||
|
||
-- 野蛮互斥动作
|
||
local dashActions = {
|
||
[GUIDefine.Action.DASH] = true, -- 野蛮
|
||
[GUIDefine.Action.ONPUSH] = true, -- 被野蛮
|
||
[GUIDefine.Action.TELEPORT] = true, -- 瞬移
|
||
[GUIDefine.Action.SBYS] = true, -- 十步一杀
|
||
[GUIDefine.Action.DASH_FAIL] = true, -- 野蛮失败
|
||
[GUIDefine.Action.DASH_WAITING] = true, -- 野蛮等待
|
||
}
|
||
|
||
-- 检查能否野蛮冲撞
|
||
function GUIFunction:CheckActionDashAble(act)
|
||
if not act then
|
||
return false
|
||
end
|
||
return dashActions[act] == nil
|
||
end
|
||
|
||
-- 是否是战士
|
||
function GUIFunction:IsFighter(job)
|
||
return GUIDefine.Job.FIGHTER == job
|
||
end
|
||
|
||
-- 是否是法师
|
||
function GUIFunction:IsWizzard(job)
|
||
return GUIDefine.Job.WIZZARD == job
|
||
end
|
||
|
||
-- 是否是道士
|
||
function GUIFunction:IsTaoist(job)
|
||
return GUIDefine.Job.TAOIST == job
|
||
end
|
||
|
||
-------------------------------------------------------------------------
|
||
-- 战斗相关
|
||
local function squLen(x, y)
|
||
return x * x + y * y
|
||
end
|
||
|
||
-- 特殊判定和平模式下列表里敌方显示
|
||
function GUIFunction:CheckActorInPeaceEnemyShow(actorID)
|
||
if not actorID or not SL:GetValue("ACTOR_IS_VALID", actorID) then
|
||
return GUIDefine.ActorRelationType.RS_NO
|
||
end
|
||
|
||
-- oneself
|
||
if not SL:GetValue("MAIN_PLAYER_IS_VALID") or (SL:GetValue("ACTOR_IS_PLAYER", actorID) and SL:GetValue("ACTOR_IS_MAINPLAYER", actorID)) then
|
||
return GUIDefine.ActorRelationType.RS_NO
|
||
end
|
||
|
||
return GUIDefine.ActorRelationType.RS_ENEMY
|
||
end
|
||
|
||
-- 检测Actor能否攻击 actorID inPeaceEnemyShow: 特殊针对和平模式敌人UI列表显示处理
|
||
function GUIFunction:CheckLaunchEnableByID(actorID, inPeaceEnemyShow)
|
||
if not actorID or not SL:GetValue("ACTOR_IS_VALID", actorID) then
|
||
return false
|
||
end
|
||
-- player & monster, only!!!!
|
||
if not SL:GetValue("ACTOR_IS_PLAYER", actorID) and not SL:GetValue("ACTOR_IS_MONSTER", actorID) then
|
||
return false
|
||
end
|
||
|
||
if not SL:GetValue("MAIN_PLAYER_IS_VALID") then
|
||
return false
|
||
end
|
||
|
||
local actorMasterID = SL:GetValue("ACTOR_HAVE_MASTER", actorID) and SL:GetValue("ACTOR_MASTER_ID", actorID)
|
||
|
||
if SL:GetValue("BATTLE_IS_AUTO_FIGHT_STATE") then
|
||
---- hero player / master is main hero
|
||
local heroID = SL:GetValue("HERO_ID")
|
||
local mainPlayerID = SL:GetValue("USER_ID")
|
||
if heroID and (actorID == heroID or actorMasterID == heroID) then
|
||
return false
|
||
end
|
||
|
||
-- main player / master is main player
|
||
if (SL:GetValue("ACTOR_IS_PLAYER", actorID) and SL:GetValue("ACTOR_IS_MAINPLAYER", actorID)) or actorMasterID == mainPlayerID then
|
||
return false
|
||
end
|
||
end
|
||
|
||
-- dead & born
|
||
if SL:GetValue("ACTOR_IS_DIE", actorID) or SL:GetValue("ACTOR_IS_DEATH", actorID) or SL:GetValue("ACTOR_IS_BORN", actorID) or SL:GetValue("ACTOR_IS_CAVE", actorID) then
|
||
return false
|
||
end
|
||
|
||
-- hp 0
|
||
if SL:GetValue("ACTOR_HP", actorID) <= 0 then
|
||
return false
|
||
end
|
||
|
||
-- 和平模式用于显示敌方列表时
|
||
if SL:GetValue("PKMODE") == GUIDefine.PKModeType.HAM_PEACE and inPeaceEnemyShow then
|
||
-- humanoid
|
||
if SL:GetValue("ACTOR_IS_PLAYER", actorID) and SL:GetValue("ACTOR_IS_HUMAN", actorID) then
|
||
if actorMasterID and GUIFunction:CheckActorInPeaceEnemyShow(actorMasterID) ~= 1 then -- 人形怪如果有MasterID, 要判断Master是否是敌友
|
||
return false
|
||
end
|
||
return true
|
||
end
|
||
|
||
-- player, check is enmey
|
||
if SL:GetValue("ACTOR_IS_PLAYER", actorID) and GUIFunction:CheckActorInPeaceEnemyShow(actorID) ~= 1 then
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("ACTOR_IS_HERO", actorID) and GUIFunction:CheckActorInPeaceEnemyShow(actorID) ~= 1 then
|
||
return false
|
||
end
|
||
else
|
||
-- humanoid
|
||
if SL:GetValue("ACTOR_IS_PLAYER", actorID) and SL:GetValue("ACTOR_IS_HUMAN", actorID) then
|
||
if actorMasterID and SL:GetValue("ACTOR_RELATION_TAG", actorMasterID) ~= 1 then -- 人形怪如果有MasterID, 要判断Master是否是敌友
|
||
return false
|
||
end
|
||
return true
|
||
end
|
||
|
||
-- player, check is enmey
|
||
if SL:GetValue("ACTOR_IS_PLAYER", actorID) and SL:GetValue("ACTOR_RELATION_TAG", actorID) ~= 1 then
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("ACTOR_IS_HERO", actorID) and SL:GetValue("ACTOR_RELATION_TAG", actorID) ~= 1 then
|
||
return false
|
||
end
|
||
end
|
||
|
||
-- 采集物
|
||
if SL:GetValue("ACTOR_IS_COLLECTION", actorID) then
|
||
return false
|
||
end
|
||
|
||
-- 石化怪
|
||
if SL:GetValue("ACTOR_STOME_MODE", actorID) then
|
||
return false
|
||
end
|
||
|
||
return true
|
||
end
|
||
|
||
-- 检查Actor能否作为自动战斗目标
|
||
function GUIFunction.CheckAutoTargetEnableByID(actorID)
|
||
if not actorID or not SL:GetValue("ACTOR_IS_VALID", actorID) then
|
||
return false
|
||
end
|
||
|
||
-- 被忽略
|
||
if SL:GetValue("ACTOR_IS_IGNORED", actorID) then
|
||
return false
|
||
end
|
||
|
||
-- 1.可攻击
|
||
if false == GUIFunction:CheckLaunchEnableByID(actorID) then
|
||
return false
|
||
end
|
||
|
||
-- 2.守卫/宝宝 -- 有主人的人型怪也不打,分身等
|
||
if not SL:GetValue("ACTOR_IS_HERO", actorID) and (SL:GetValue("ACTOR_IS_DEFENDER", actorID) or SL:GetValue("ACTOR_HAVE_MASTER", actorID)) then
|
||
return false
|
||
end
|
||
|
||
-- 3.归属不是自己的
|
||
local ownerID = SL:GetValue("ACTOR_OWNER_ID", actorID)
|
||
if SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_NO_ATTACK_HAVE_BELONG) == 1 and ownerID and ownerID ~= SL:GetValue("USER_ID") then
|
||
return false
|
||
end
|
||
|
||
-- 4. 过滤弓箭手、卫士、练功师
|
||
if SL:GetValue("ACTOR_RACE_SERVER", actorID) == 112 and SL:GetValue("ACTOR_RACE_IMG", actorID) == 45 then -- 弓箭手
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("ACTOR_RACE_SERVER", actorID) == 11 and SL:GetValue("ACTOR_RACE_IMG", actorID) == 12 then -- 卫士
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("ACTOR_RACE_SERVER", actorID) == 55 and SL:GetValue("ACTOR_RACE_IMG", actorID) == 19 then -- 练功师
|
||
return false
|
||
end
|
||
|
||
-- 内挂忽略的怪
|
||
local ignoreNames = SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_IGNORE_MONSTER)
|
||
local name = SL:GetValue("ACTOR_NAME", actorID)
|
||
if not ignoreNames or (type(ignoreNames) ~= "table") then
|
||
ignoreNames = {}
|
||
end
|
||
if name and ignoreNames[name] then
|
||
return false
|
||
end
|
||
|
||
return true
|
||
end
|
||
|
||
-- 查找最近怪物
|
||
function GUIFunction:FindNearestMonster(monsterVec, monsterVecNum, ignoreActorID)
|
||
-- 不自动选: 守卫/石化状态下祖玛卫士
|
||
local target = nil
|
||
local cost = GUIDefine.MAX_COST
|
||
local pMapX = SL:GetValue("X")
|
||
local pMapY = SL:GetValue("Y")
|
||
local mX = 0
|
||
local mY = 0
|
||
|
||
for i = 1, monsterVecNum do
|
||
local monsterID = monsterVec[i]
|
||
if SL:GetValue("ACTOR_IS_VALID", monsterID) then
|
||
mX = SL:GetValue("ACTOR_MAP_X", monsterID)
|
||
mY = SL:GetValue("ACTOR_MAP_Y", monsterID)
|
||
if not (mX == pMapX and mY == pMapY) and GUIFunction.CheckAutoTargetEnableByID(monsterID) and monsterID ~= ignoreActorID then
|
||
local len = squLen(mX - pMapX, mY - pMapY)
|
||
if len < cost then
|
||
target = monsterID
|
||
cost = len
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
return target
|
||
end
|
||
|
||
function GUIFunction:GetMonsterVec(monsters, ncount)
|
||
local monsterVec = {}
|
||
local num = 0
|
||
|
||
for i = 1, ncount do
|
||
local monsterID = monsters[i]
|
||
if GUIFunction.CheckAutoTargetEnableByID(monsterID) then
|
||
num = num + 1
|
||
monsterVec[num] = monsterID
|
||
end
|
||
end
|
||
|
||
return monsterVec, num
|
||
end
|
||
|
||
-- 自动找怪, 设定目标
|
||
function GUIFunction:OnAutoFindMonsterFunc()
|
||
if not SL:GetValue("MAIN_PLAYER_IS_VALID") then
|
||
return nil
|
||
end
|
||
|
||
local autoTarget = SL:GetValue("AUTO_TARGET")
|
||
local targetIndex = autoTarget.targetIndex
|
||
local targetType = autoTarget.targetType
|
||
|
||
local monsterVec = {}
|
||
local monsterVecNum = 0
|
||
|
||
if targetType ~= GUIDefine.ActorType.MONSTER or not targetIndex or GUIDefine.AUTO_FIND_TARGET_NONE == targetIndex or 0 == targetIndex then -- not target index,find nearst monster
|
||
local monsters, ncount = SL:GetValue("FIND_IN_VIEW_MONSTER_LIST", true, true)
|
||
monsterVec, monsterVecNum = GUIFunction:GetMonsterVec(monsters, ncount)
|
||
else
|
||
local monsters, ncount = SL:GetValue("FIND_IN_VIEW_MONSTER_LIST_BY_TYPEINDEX", targetIndex, true, true)
|
||
monsterVec, monsterVecNum = GUIFunction:GetMonsterVec(monsters, ncount)
|
||
|
||
if monsterVecNum < 1 then
|
||
local monsters, ncount = SL:GetValue("FIND_IN_VIEW_MONSTER_LIST")
|
||
monsterVec, monsterVecNum = GUIFunction:GetMonsterVec(monsters, ncount)
|
||
end
|
||
end
|
||
|
||
if monsterVecNum < 1 then
|
||
return false
|
||
end
|
||
|
||
-- find nearest monster
|
||
local targetID = GUIFunction:FindNearestMonster(monsterVec, monsterVecNum)
|
||
if SL:GetValue("ACTOR_IS_VALID", targetID) then
|
||
SL:SetValue("SELECT_TARGET_ID", targetID)
|
||
end
|
||
end
|
||
|
||
-- 自动找人形怪/怪, 设定目标
|
||
function GUIFunction:OnAutoFindHumanoidFunc()
|
||
if not SL:GetValue("MAIN_PLAYER_IS_VALID") then
|
||
return nil
|
||
end
|
||
|
||
local targetID = nil
|
||
local cost = GUIDefine.MAX_COST
|
||
local pMapX = SL:GetValue("X")
|
||
local pMapY = SL:GetValue("Y")
|
||
local aX = 0
|
||
local aY = 0
|
||
|
||
local playerVec, playerVecNum = SL:GetValue("FIND_IN_VIEW_PLAYER_LIST")
|
||
for i = 1, playerVecNum do
|
||
local playerID = playerVec[i]
|
||
if SL:GetValue("ACTOR_IS_VALID", playerID) and SL:GetValue("ACTOR_IS_HUMAN", playerID) then
|
||
aX = SL:GetValue("ACTOR_MAP_X", playerID)
|
||
aY = SL:GetValue("ACTOR_MAP_Y", playerID)
|
||
if not (aX == pMapX and aY == pMapY) and GUIFunction.CheckAutoTargetEnableByID(playerID) then
|
||
local len = squLen(aX - pMapX, aY - pMapY)
|
||
if len < cost then
|
||
targetID = playerID
|
||
cost = len
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
if targetID and SL:GetValue("ACTOR_IS_VALID", targetID) then
|
||
SL:SetValue("SELECT_TARGET_ID", targetID)
|
||
else
|
||
-- 没找到, 找其他怪
|
||
GUIFunction:OnAutoFindMonsterFunc()
|
||
end
|
||
end
|
||
|
||
-- 标识视野内可攻击目标检查距离 ignoreActorID: 忽略的actorID
|
||
function GUIFunction:SetInViewTargetCheckFlag(ignoreActorID)
|
||
if not SL:GetValue("MAIN_PLAYER_IS_VALID") then
|
||
return nil
|
||
end
|
||
|
||
local targetID = nil
|
||
local cost = GUIDefine.MAX_COST
|
||
local pMapX = SL:GetValue("X")
|
||
local pMapY = SL:GetValue("Y")
|
||
local aX = 0
|
||
local aY = 0
|
||
|
||
local playerVec, playerVecNum = SL:GetValue("FIND_IN_VIEW_PLAYER_LIST")
|
||
for i = 1, playerVecNum do
|
||
local playerID = playerVec[i]
|
||
if SL:GetValue("ACTOR_IS_VALID", playerID) and SL:GetValue("ACTOR_IS_HUMAN", playerID) then
|
||
aX = SL:GetValue("ACTOR_MAP_X", playerID)
|
||
aY = SL:GetValue("ACTOR_MAP_Y", playerID)
|
||
if not (aX == pMapX and aY == pMapY) and GUIFunction.CheckAutoTargetEnableByID(playerID) and playerID ~= ignoreActorID then
|
||
local len = squLen(aX - pMapX, aY - pMapY)
|
||
if len < cost then
|
||
SL:SetValue("ACTOR_NEED_CHECK_TO_AUTO_FIGHT", playerID, true)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
local autoTarget = SL:GetValue("AUTO_TARGET")
|
||
local targetIndex = autoTarget.targetIndex
|
||
local targetType = autoTarget.targetType
|
||
|
||
local monsterVec = {}
|
||
local monsterVecNum = 0
|
||
|
||
if targetType ~= GUIDefine.ActorType.MONSTER or not targetIndex or GUIDefine.AUTO_FIND_TARGET_NONE == targetIndex or 0 == targetIndex then -- not target index,find nearst monster
|
||
local monsters, ncount = SL:GetValue("FIND_IN_VIEW_MONSTER_LIST", true, true)
|
||
monsterVec, monsterVecNum = GUIFunction:GetMonsterVec(monsters, ncount)
|
||
else
|
||
local monsters, ncount = SL:GetValue("FIND_IN_VIEW_MONSTER_LIST_BY_TYPEINDEX", targetIndex, true, true)
|
||
monsterVec, monsterVecNum = GUIFunction:GetMonsterVec(monsters, ncount)
|
||
|
||
if monsterVecNum < 1 then
|
||
local monsters, ncount = SL:GetValue("FIND_IN_VIEW_MONSTER_LIST")
|
||
monsterVec, monsterVecNum = GUIFunction:GetMonsterVec(monsters, ncount)
|
||
end
|
||
end
|
||
|
||
if monsterVecNum < 1 then
|
||
return nil
|
||
end
|
||
|
||
for i = 1, monsterVecNum do
|
||
local monsterID = monsterVec[i]
|
||
if SL:GetValue("ACTOR_IS_VALID", monsterID) then
|
||
aX = SL:GetValue("ACTOR_MAP_X", monsterID)
|
||
aY = SL:GetValue("ACTOR_MAP_Y", monsterID)
|
||
if not (aX == pMapX and aY == pMapY) and GUIFunction.CheckAutoTargetEnableByID(monsterID) and monsterID ~= ignoreActorID then
|
||
local len = squLen(aX - pMapX, aY - pMapY)
|
||
if len < cost then
|
||
SL:SetValue("ACTOR_NEED_CHECK_TO_AUTO_FIGHT", monsterID, true)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
end
|
||
|
||
-- 受攻击后自动反击
|
||
function GUIFunction:OnAutoFightBackFunc(attackActorID, actorID)
|
||
|
||
actorID = actorID or SL:GetValue("USER_ID")
|
||
|
||
local setValues = SL:GetValue("SETTING_VALUE", SLDefine.SETTINGID.SETTING_IDX_BEDAMAGED_PLAYER) -- 被玩家攻击 1不处理 2反击 3逃跑
|
||
if not setValues or not setValues[1] or not (setValues[1] == 2 or setValues[1] == 3) then
|
||
return
|
||
end
|
||
|
||
if not attackActorID or not SL:GetValue("ACTOR_IS_VALID", attackActorID) then -- 没有攻击者
|
||
return
|
||
end
|
||
|
||
local attackMasterID = SL:GetValue("ACTOR_MASTER_ID", attackActorID)
|
||
if (SL:GetValue("ACTOR_IS_HUMAN", attackActorID) or SL:GetValue("ACTOR_IS_MONSTER", attackActorID)) and not SL:GetValue("ACTOR_HAVE_MASTER", attackActorID) then
|
||
return
|
||
end
|
||
|
||
if not SL:GetValue("ACTOR_IS_VALID", actorID) then
|
||
return
|
||
end
|
||
|
||
local mainPlayerID = SL:GetValue("USER_ID")
|
||
local heroActorID = SL:GetValue("HERO_ID")
|
||
local masterID = SL:GetValue("ACTOR_MASTER_ID", actorID)
|
||
|
||
-- 攻击 我的宠物/元神/主角
|
||
if not (masterID == mainPlayerID or actorID == heroActorID or actorID == mainPlayerID) then
|
||
return
|
||
end
|
||
|
||
if not SL:GetValue("MAIN_PLAYER_IS_VALID") then
|
||
return
|
||
end
|
||
|
||
-- 挂机
|
||
if not SL:GetValue("BATTLE_IS_AFK") and not SL:GetValue("BATTLE_IS_AUTO_FIGHT_STATE") then
|
||
return
|
||
end
|
||
|
||
if setValues[1] == 2 then
|
||
local attackBackID = nil -- 要反击的对象id
|
||
if attackMasterID and attackMasterID ~= "0" and SL:GetValue("ACTOR_IS_VALID", attackMasterID) then
|
||
local value = SL:GetValue("SETTING_VALUE", SLDefine.SETTINGID.SETTING_IDX_FIRST_ATTACK_MASTER) -- 优先打主人
|
||
if value[1] == 1 and SL:GetValue("ACTOR_IS_PLAYER", attackMasterID) and not SL:GetValue("ACTOR_IS_HUMAN", attackMasterID) then
|
||
attackBackID = attackMasterID
|
||
end
|
||
end
|
||
|
||
if not attackBackID then
|
||
attackBackID = attackActorID
|
||
end
|
||
|
||
local hateID = SL:GetValue("HATE_ID")
|
||
if hateID and SL:GetValue("ACTOR_IS_VALID", hateID) then
|
||
return
|
||
end
|
||
|
||
-- 没仇恨对象
|
||
SL:SetValue("SELECT_SHIFT_ATTACK_ID", nil)
|
||
SL:SetValue("SELECT_TARGET_ID", nil)
|
||
SL:SetValue("CLEAR_CUR_MOVE")
|
||
SL:SetValue("SELECT_TARGET_ID", attackBackID)
|
||
SL:SetValue("HATE_ID", attackBackID)
|
||
|
||
-- 攻击者必须是玩家 不是我的宠物/元神/主角
|
||
elseif setValues[1] == 3 and not SL:GetValue("ACTOR_IS_MAINPLAYER", attackActorID) and attackMasterID ~= mainPlayerID then
|
||
SL:SetValue("SELECT_SHIFT_ATTACK_ID", nil)
|
||
SL:SetValue("SELECT_TARGET_ID", nil)
|
||
SL:SetValue("AFK_CHECK_AIMLESS_MOVE")
|
||
end
|
||
end
|
||
-------------------------------------------------------------------------
|
||
-- 检查NPC气泡显示
|
||
local npcTalkNode = nil
|
||
function GUIFunction:CheckNpcTalkTips()
|
||
if not SL:GetValue("MAIN_PLAYER_IS_VALID") or SL:GetValue("IS_PC_OPER_MODE") then
|
||
return
|
||
end
|
||
|
||
local x = SL:GetValue("X")
|
||
local y = SL:GetValue("Y")
|
||
|
||
local targetNpcID = nil
|
||
|
||
local npcVec, nCount = SL:GetValue("FIND_IN_VIEW_NPC_LIST")
|
||
for i = 1, nCount do
|
||
local npcID = npcVec[i]
|
||
local npcMapX = SL:GetValue("ACTOR_MAP_X", npcID)
|
||
local npcMapY = SL:GetValue("ACTOR_MAP_Y", npcID)
|
||
if SL:GetValue("ACTOR_IS_VALID", npcID) and math.abs(x - npcMapX) <= 2 and math.abs(y - npcMapY) <= 2 then
|
||
targetNpcID = npcID
|
||
break
|
||
end
|
||
end
|
||
|
||
if not targetNpcID then
|
||
if npcTalkNode then
|
||
GUI:removeAllChildren(npcTalkNode)
|
||
end
|
||
return
|
||
end
|
||
|
||
GUIFunction:OnShowNpcTalkTips(targetNpcID)
|
||
|
||
end
|
||
|
||
-- NPC气泡显示
|
||
function GUIFunction:OnShowNpcTalkTips(npcID)
|
||
if not SL:GetValue("MAIN_PLAYER_IS_VALID") or SL:GetValue("IS_PC_OPER_MODE") then
|
||
return
|
||
end
|
||
|
||
if not SL:GetValue("SERVER_OPTION", SW_KEY_NPC_BUTTON) then
|
||
return
|
||
end
|
||
|
||
if npcTalkNode then
|
||
GUI:removeAllChildren(npcTalkNode)
|
||
else
|
||
local winSize = SL:GetValue("SCREEN_SIZE")
|
||
local moveY = SL:GetValue("IS_PC_OPER_MODE") and 0 or -88
|
||
npcTalkNode = GUI:Widget_Create(GUI:Attach_Center(), "npcTalkNode", winSize.width / 2 + 18, winSize.height / 2 + moveY, 0, 0)
|
||
end
|
||
|
||
local imagePopBg = GUI:Image_Create(npcTalkNode, "touch", 0, 0, "res/public/bg_bubble_1.png")
|
||
GUI:setTouchEnabled(imagePopBg, true)
|
||
GUI:addOnClickEvent(imagePopBg, function()
|
||
SL:RequestNPCTalk(npcID)
|
||
end)
|
||
|
||
local size = GUI:getContentSize(imagePopBg)
|
||
local npcName = SL:GetValue("ACTOR_NAME", npcID)
|
||
npcName = SL:GetValue("ACTOR_ONLY_SHOW_BUBBLE_NAME", npcID) or npcName
|
||
if npcName then
|
||
local _, _, showName = string.find(npcName, ".-%#(.-)%#")
|
||
if showName then
|
||
npcName = showName
|
||
end
|
||
end
|
||
local contentText = GUI:Text_Create(imagePopBg, "content", size.width / 2, size.height * 0.6, SL:GetValue("GAME_DATA","DEFAULT_FONT_SIZE") or 16, "#FFFFFF", npcName)
|
||
GUI:setAnchorPoint(contentText, 0.5, 0.5)
|
||
GUI:Text_enableOutline(contentText, "#111111", 1)
|
||
end
|
||
|
||
-- NPC气泡隐藏
|
||
function GUIFunction:OnHideNpcTalkTips()
|
||
if npcTalkNode then
|
||
GUI:removeAllChildren(npcTalkNode)
|
||
end
|
||
end
|
||
|
||
-- NPC气泡清理
|
||
function GUIFunction:OnClearNpcTalkTips()
|
||
if npcTalkNode then
|
||
npcTalkNode = nil
|
||
end
|
||
end
|
||
-------------------------------------------------------------------------
|
||
-- 人物头顶说话 富文本
|
||
function GUIFunction:GenerateActorSayItem(data)
|
||
|
||
local content = string.format("%s:%s", data.SendName, data.Msg)
|
||
local elements = createNormalElements(content, "fonts/font2.ttf", 12, "#FFFFFF", "#000000", 1, true)
|
||
|
||
local richText = GUI:RichTextCombine_Create(-1, "sayRichText", 0, 0, 200, 0)
|
||
GUI:setAnchorPoint(richText, 0.5, 0)
|
||
-- 填充
|
||
GUI:RichTextCombine_pushBackElements(richText, elements)
|
||
|
||
return richText
|
||
end
|
||
|
||
-------------------------------------------------------------------------
|
||
-- 技能相关
|
||
function GUIFunction:CheckSkillAbleToLaunch(skillID, isUserInput)
|
||
--[[
|
||
1: able
|
||
-1: not learned
|
||
-2: is cd
|
||
-3: not enough mana
|
||
-4: buff not allowed
|
||
-5: not enough mount mana
|
||
-6: map limit
|
||
-8: stiffness
|
||
-9: isOff
|
||
-10: horse
|
||
-11: 延迟释放
|
||
-12: 内力值不够
|
||
-13: 目标buff有禁止技能 launch
|
||
-14: 目标buff有禁止技能 User Input
|
||
]]
|
||
-- 挖矿使用普攻CD
|
||
if skillID == SKILL_ID_DIG and not SL:GetValue("SKILL_IS_CDING", SKILL_ID_PuGong) then
|
||
return 1
|
||
end
|
||
|
||
local skillData = SL:GetValue("SKILL_DATA", skillID) or SL:GetValue("COMBO_SKILL_DATA", skillID)
|
||
if not skillData then
|
||
return -1
|
||
end
|
||
|
||
local isCD, currCDTime = SL:GetValue("SKILL_IS_CDING", skillID)
|
||
if isCD then
|
||
if SL:GetValue("SKILL_NEED_CDHINT", skillID) then
|
||
currCDTime = currCDTime or 0
|
||
local lastHintTime = skillData.lastHintTime or 0
|
||
if lastHintTime - currCDTime >= 1 or (lastHintTime == 0 and skillData.DelayTime > 1000) then
|
||
local data = {}
|
||
data.ChannelId = GUIDefine.ChatChannel.SYSTEM
|
||
data.BColor = 249
|
||
data.FColor = 255
|
||
data.Msg = string.format("系统:请在%d秒后使用该技能", math.ceil(currCDTime))
|
||
SL:onLUAEvent(LUA_EVENT_CHAT_MSG_ADD, data)
|
||
|
||
skillData.lastHintTime = currCDTime
|
||
end
|
||
end
|
||
return -2
|
||
end
|
||
|
||
if not SL:GetValue("SKILL_IS_ENOUGH_MP", skillID) then
|
||
return -3
|
||
end
|
||
|
||
if not SL:GetValue("SKILL_IS_ENOUGH_IV", skillID) then
|
||
return -12
|
||
end
|
||
|
||
if SL:GetValue("SKILL_IS_ONOFF_SKILL", skillID) and not SL:GetValue("SKILL_IS_ON_SKILL", skillID) then
|
||
return -9
|
||
end
|
||
|
||
if not SL:GetValue("HORSE_CAN_LAUNCH_SKILL", skillID) then
|
||
return -10
|
||
end
|
||
|
||
if not SL:GetValue("BUFF_CHECK_SKILL_ENABLE", skillID) then
|
||
return -4
|
||
end
|
||
|
||
if SL:GetValue("MAP_FORBID_LAUNCH_SKILL", skillID) then
|
||
return -6
|
||
end
|
||
|
||
if SL:GetValue("SKILL_IS_DELAY_LAUNCH", skillID) then
|
||
return -11
|
||
end
|
||
|
||
local targetID = SL:GetValue("SELECT_SHIFT_ATTACK_ID") or SL:GetValue("SELECT_TARGET_ID")
|
||
if targetID then
|
||
if isUserInput then
|
||
-- 手动释放时是否有不能释放该技能BUFF
|
||
local buffID = SL:GetValue("TARGET_FORBID_SKILL_LAUNCH_BUFF", targetID, skillID)
|
||
if buffID then
|
||
return -13, buffID
|
||
end
|
||
-- 自动释放时是否有不能释放该技能BUFF
|
||
elseif SL:GetValue("TARGET_FORBID_SKILL_AUTO_BUFF", targetID, skillID) then
|
||
return -14
|
||
end
|
||
end
|
||
|
||
if skillData then
|
||
skillData.lastHintTime = 0
|
||
end
|
||
return 1
|
||
end
|
||
|
||
-- 查找背包物品
|
||
local function findBagItem(stdMode, shape)
|
||
local items = BagData.GetBagData()
|
||
for _, item in pairs(items) do
|
||
if item.StdMode == stdMode and item.Shape == shape then
|
||
return item
|
||
end
|
||
end
|
||
return nil
|
||
end
|
||
|
||
-- 检查毒符 type: 1 绿 2 红
|
||
function GUIFunction:CheckDuItem(type)
|
||
local dressType = SL:GetValue("SERVER_OPTION", "UseAmuletType")-- 0 穿戴 1 背包 2 无
|
||
|
||
local dressEquip = GUIFunction:GetEquipDataByPos(GUIDefine.EquipPosUI.Equip_Type_Bujuk)
|
||
if dressType == 2 then
|
||
return true
|
||
end
|
||
if type == 1 then
|
||
|
||
if dressEquip then
|
||
return dressEquip.Shape == 1 or findBagItem(25, 1)
|
||
else
|
||
return findBagItem(25, 1)
|
||
end
|
||
elseif type == 2 then
|
||
if dressEquip then
|
||
return dressEquip.Shape == 2 or findBagItem(25, 2)
|
||
else
|
||
return findBagItem(25, 2)
|
||
end
|
||
end
|
||
end
|
||
|
||
-- 是否护身符
|
||
local function isAmuletItem(item)
|
||
if not item then
|
||
return false
|
||
end
|
||
return item.StdMode == 25 and item.Shape == 5
|
||
end
|
||
|
||
-- 是否毒药粉
|
||
local function isPoisonItem(item)
|
||
if not item then
|
||
return false
|
||
end
|
||
return item.StdMode == 25 and (item.Shape == 1 or item.Shape == 2)
|
||
end
|
||
|
||
-- 使用护身符的技能
|
||
local useAmuletSkill = {
|
||
[13] = true,
|
||
[14] = true,
|
||
[15] = true,
|
||
[16] = true,
|
||
[17] = true,
|
||
[18] = true,
|
||
[19] = true,
|
||
[30] = true,
|
||
[55] = true,
|
||
[57] = true,
|
||
[76] = true,
|
||
}
|
||
|
||
-- 使用毒药粉技能
|
||
local usePoisonSkill = {
|
||
[6] = true,
|
||
[51] = true,
|
||
}
|
||
|
||
-- 检查是否穿戴对应技能装备
|
||
function GUIFunction:CheckDressEquipSkillID(skillID)
|
||
if not (useAmuletSkill[skillID] or usePoisonSkill[skillID]) then
|
||
return true
|
||
end
|
||
|
||
local dressEquip = GUIFunction:GetEquipDataByPos(GUIDefine.EquipPosUI.Equip_Type_Bujuk)
|
||
|
||
-- 没穿
|
||
if not dressEquip then
|
||
return false
|
||
end
|
||
|
||
-- 符
|
||
if useAmuletSkill[skillID] and isAmuletItem(dressEquip) then
|
||
return true
|
||
end
|
||
|
||
-- 毒
|
||
if usePoisonSkill[skillID] and isPoisonItem(dressEquip) then
|
||
return true
|
||
end
|
||
|
||
return false
|
||
end
|
||
|
||
-- 检查背包中是否有释放技能装备
|
||
function GUIFunction:CheckBagEquipSkillID(skillID)
|
||
if not (useAmuletSkill[skillID] or usePoisonSkill[skillID]) then
|
||
return true
|
||
end
|
||
|
||
-- 符
|
||
if useAmuletSkill[skillID] and findBagItem(25, 5) then
|
||
return true
|
||
end
|
||
|
||
-- 毒
|
||
if usePoisonSkill[skillID] and (findBagItem(25, 1) or findBagItem(25, 2)) then
|
||
return true
|
||
end
|
||
|
||
return false
|
||
end
|
||
|
||
-- 获取技能最小攻击距离
|
||
function GUIFunction:GetSkillMinLaunchDistance(skillID)
|
||
local config = SL:GetValue("SKILL_CONFIG", skillID)
|
||
if not config then
|
||
return 1
|
||
end
|
||
|
||
-- 寻路阻塞
|
||
if SL:GetValue("IS_MOVE_BLOCKED") then
|
||
return config.minDis or 1
|
||
end
|
||
|
||
-- 刺杀剑术
|
||
if skillID == SKILL_ID_CiSha then
|
||
return SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_MOVE_GEWEI_CISHA) == 1 and 2 or 0
|
||
end
|
||
|
||
-- 自动走位
|
||
if SL:GetValue("BATTLE_IS_AFK") and SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_AUTO_MOVE) == 1 then
|
||
return config.autoMinDis or 1
|
||
end
|
||
|
||
return config.minDis or 1
|
||
end
|
||
|
||
-- 获取技能最大攻击距离
|
||
function GUIFunction:GetSkillMaxLaunchDistance(skillID)
|
||
local config = SL:GetValue("SKILL_CONFIG", skillID)
|
||
if not config then
|
||
return 1
|
||
end
|
||
|
||
-- 刺杀剑术
|
||
if skillID == SKILL_ID_CiSha then
|
||
return (SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_DAODAOCISHA) ~= 1 and SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_GEWEICISHA) ~= 1) and 1 or 2
|
||
end
|
||
|
||
-- 自动战斗使用手机端范围
|
||
if SL:GetValue("BATTLE_IS_AFK") then
|
||
return config.maxDis
|
||
end
|
||
|
||
local maxDis = SL:GetValue("IS_PC_OPER_MODE") and config.maxDis_pc or config.maxDis
|
||
return maxDis
|
||
end
|
||
|
||
-- 地图坐标计算方向
|
||
function GUIFunction:CalcMapDirection(dX, dY, sX, sY)
|
||
local diffX = dX - sX
|
||
local diffY = dY - sY
|
||
local angle = math.deg(math.atan2(diffY, diffX))
|
||
local ret = SLDefine.Direction.INVALID
|
||
if (angle > -22.5 and angle <= 22.5) then
|
||
ret = SLDefine.Direction.RIGHT
|
||
|
||
elseif (angle > 22.5 and angle <= 67.5) then
|
||
ret = SLDefine.Direction.RIGHT_BOTTOM
|
||
|
||
elseif (angle > 67.5 and angle <= 112.5) then
|
||
ret = SLDefine.Direction.BOTTOM
|
||
|
||
elseif (angle > 112.5 and angle <= 157.5) then
|
||
ret = SLDefine.Direction.LEFT_BOTTOM
|
||
|
||
elseif ((angle > 157.5 and angle <= 180) or (angle <= -157.5 and angle > -180)) then
|
||
ret = SLDefine.Direction.LEFT
|
||
|
||
elseif (angle <= -112.5 and angle > -157.5) then
|
||
ret = SLDefine.Direction.LEFT_UP
|
||
|
||
elseif (angle <= -67.5 and angle > -112.5) then
|
||
ret = SLDefine.Direction.UP
|
||
|
||
elseif (angle <= -22.5 and angle > -67.5) then
|
||
ret = SLDefine.Direction.RIGHT_UP
|
||
end
|
||
return ret
|
||
end
|
||
|
||
-- 计算地图距离
|
||
function GUIFunction:CalcMapDistance(sX, sY, dX, dY)
|
||
return math.max(math.abs(sX - dX), math.abs(sY - dY))
|
||
end
|
||
|
||
---------------------------------------检测技能释放--------------------------------------------
|
||
local SharedInputLaunchData = {}
|
||
local SharedInputMoveData = {}
|
||
local SharedInputMiningData = {}
|
||
-- 自动检测技能行为
|
||
function GUIFunction:AutoFindSkillBehavior()
|
||
if GUIFunction:CheckLaunchFirstSkill() then
|
||
return true
|
||
end
|
||
|
||
if GUIFunction:CheckLaunchComboSkill() then
|
||
return true
|
||
end
|
||
|
||
if GUIFunction:CheckLaunchAutoSkill() then
|
||
return true
|
||
end
|
||
|
||
if GUIFunction:CheckLaunchSimpleSkill() then
|
||
return true
|
||
end
|
||
|
||
if GUIFunction:CheckLaunchLockSkill() then
|
||
return true
|
||
end
|
||
|
||
if GUIFunction:CheckAutoMining() then
|
||
return true
|
||
end
|
||
|
||
return false
|
||
end
|
||
|
||
function GUIFunction:CheckLaunchFirstSkill()
|
||
if not SL:GetValue("SELECT_TARGET_ID") then
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("INPUT_LAUNCH_SKILLID") then
|
||
return false
|
||
end
|
||
|
||
if not SL:GetValue("ATTACK_STATE") and not SL:GetValue("BATTLE_IS_AUTO_LOCK_STATE") and not SL:GetValue("BATTLE_IS_AFK") and
|
||
not SL:GetValue("BATTLE_IS_AUTO_FIGHT_STATE") then
|
||
return false
|
||
end
|
||
|
||
local skillID, destPosX, destPosY = SkillUtils.FindFirstLaunchSkill()
|
||
if not skillID then
|
||
return false
|
||
end
|
||
|
||
local lastMouseInsideActorID = SL:GetValue("MOUSE_INSIDE_ACTORID")
|
||
SharedInputLaunchData.launchType = SL:GetValue("INPUT_LAUNCH_TYPE")
|
||
SharedInputLaunchData.priority = SL:GetValue("INPUT_LAUNCH_PRIORITY")
|
||
SharedInputLaunchData.targetID = lastMouseInsideActorID or SL:GetValue("SELECT_TARGET_ID")
|
||
SharedInputLaunchData.skillID = skillID
|
||
SharedInputLaunchData.destPosX = destPosX
|
||
SharedInputLaunchData.destPosY = destPosY
|
||
SL:InputLaunch(SharedInputLaunchData)
|
||
return true
|
||
end
|
||
|
||
function GUIFunction:CheckLaunchComboSkill()
|
||
if not SL:GetValue("SELECT_TARGET_ID") then
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("INPUT_LAUNCH_SKILLID") then
|
||
return false
|
||
end
|
||
|
||
local isAttackState = SL:GetValue("IS_PC_OPER_MODE") and SL:GetValue("ATTACK_STATE") or false
|
||
if not isAttackState and not SL:GetValue("BATTLE_IS_AUTO_LOCK_STATE") and not SL:GetValue("BATTLE_IS_AFK") and not SL:GetValue("BATTLE_IS_AUTO_FIGHT_STATE") then
|
||
return false
|
||
end
|
||
|
||
local skillID, destPosX, destPosY, isAuto = SkillUtils.FindComboLaunchSkill()
|
||
if not skillID then
|
||
return false
|
||
end
|
||
|
||
SharedInputLaunchData.launchType = isAuto and GUIDefine.LaunchType.AUTO or GUIDefine.LaunchType.USER
|
||
SharedInputLaunchData.priority = GUIDefine.LaunchPriority.SYSTEM
|
||
SharedInputLaunchData.targetID = SL:GetValue("SELECT_TARGET_ID")
|
||
SharedInputLaunchData.skillID = skillID
|
||
SharedInputLaunchData.destPosX = destPosX
|
||
SharedInputLaunchData.destPosY = destPosY
|
||
SL:InputLaunch(SharedInputLaunchData)
|
||
return true
|
||
end
|
||
|
||
function GUIFunction:CheckLaunchAutoSkill()
|
||
-- 挂机/自动战斗
|
||
if not SL:GetValue("BATTLE_IS_AFK") and not SL:GetValue("BATTLE_IS_AUTO_FIGHT_STATE") then
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("INPUT_LAUNCH_SKILLID") then
|
||
return false
|
||
end
|
||
|
||
local targetID = SL:GetValue("SELECT_TARGET_ID")
|
||
if not targetID then
|
||
return false
|
||
end
|
||
|
||
if not GUIFunction:CheckLaunchEnableByID(targetID) then
|
||
SL:SetValue("SELECT_TARGET_ID", nil)
|
||
return false
|
||
end
|
||
|
||
-- 挂机目标死亡,原地等待一段时间
|
||
if SL:GetValue("AFK_TARGET_DEATH") then
|
||
return true
|
||
end
|
||
|
||
if not SL:GetValue("ACTOR_IS_VALID", targetID) then
|
||
SL:SetValue("SELECT_TARGET_ID", nil)
|
||
return false
|
||
end
|
||
|
||
-- 闪避技能
|
||
local skillID, destPosX, destPosY = SkillUtils.FindAvoidDangerSkill()
|
||
if skillID then
|
||
SL:SetValue("AUTO_LAUNCH_AVOID_STAMP")
|
||
else
|
||
-- 自动释放技能
|
||
skillID, destPosX, destPosY = SkillUtils.FindAutoLaunchSkill()
|
||
end
|
||
|
||
if skillID then
|
||
SharedInputLaunchData.launchType = GUIDefine.LaunchType.AUTO
|
||
SharedInputLaunchData.priority = GUIDefine.LaunchPriority.SYSTEM
|
||
SharedInputLaunchData.targetID = targetID
|
||
SharedInputLaunchData.skillID = skillID
|
||
SharedInputLaunchData.destPosX = destPosX
|
||
SharedInputLaunchData.destPosY = destPosY
|
||
SL:InputLaunch(SharedInputLaunchData)
|
||
return true
|
||
end
|
||
|
||
-- 闪避走位
|
||
destPosX, destPosY = SkillUtils.FindAvoidDangerPos()
|
||
if destPosX and destPosY then
|
||
SharedInputMoveData.mapID = SL:GetValue("MAP_ID")
|
||
SharedInputMoveData.x = destPosX
|
||
SharedInputMoveData.y = destPosY
|
||
SharedInputMoveData.type = GUIDefine.InputMoveType.AUTOMOVE
|
||
SL:InputMove(SharedInputMoveData)
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
function GUIFunction:CheckLaunchSimpleSkill()
|
||
if SL:GetValue("INPUT_LAUNCH_SKILLID") then
|
||
return false
|
||
end
|
||
|
||
local targetID = SL:GetValue("SELECT_TARGET_ID")
|
||
if not targetID then
|
||
return false
|
||
end
|
||
|
||
-- 锁定目标状态
|
||
if not SL:GetValue("BATTLE_IS_AUTO_LOCK_STATE") then
|
||
return false
|
||
end
|
||
|
||
if not GUIFunction:CheckLaunchEnableByID(targetID) then
|
||
SL:SetValue("SELECT_TARGET_ID", nil)
|
||
return false
|
||
end
|
||
|
||
if not SL:GetValue("ACTOR_IS_VALID", targetID) then
|
||
SL:SetValue("SELECT_TARGET_ID", nil)
|
||
return false
|
||
end
|
||
|
||
if SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_ALWAYS_ATTACK) ~= 1 then
|
||
return false
|
||
end
|
||
|
||
local skillID, destPosX, destPosY = SkillUtils.FindSimpleLaunchSkill()
|
||
if skillID then
|
||
SharedInputLaunchData.launchType = GUIDefine.LaunchType.LOCK
|
||
SharedInputLaunchData.priority = GUIDefine.LaunchPriority.SYSTEM
|
||
SharedInputLaunchData.targetID = targetID
|
||
SharedInputLaunchData.skillID = skillID
|
||
SharedInputLaunchData.destPosX = destPosX
|
||
SharedInputLaunchData.destPosY = destPosY
|
||
SL:InputLaunch(SharedInputLaunchData)
|
||
return true
|
||
end
|
||
|
||
return false
|
||
end
|
||
|
||
function GUIFunction:CheckLaunchLockSkill()
|
||
-- shift锁定
|
||
if not SL:GetValue("IS_PC_OPER_MODE") then
|
||
return false
|
||
end
|
||
|
||
-- 不在锁定攻击状态
|
||
if not SL:GetValue("ATTACK_STATE") then
|
||
return false
|
||
end
|
||
|
||
local targetID = SL:GetValue("SELECT_SHIFT_ATTACK_ID")
|
||
if not targetID then
|
||
return false
|
||
end
|
||
|
||
if not SL:GetValue("ACTOR_IS_VALID", targetID) then
|
||
SL:SetValue("SELECT_SHIFT_ATTACK_ID", nil)
|
||
return false
|
||
end
|
||
|
||
-- 免shift
|
||
local optionAble = SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_NOT_NEED_SHIFT) == 1
|
||
local shiftAble = SL:GetValue("IS_PRESSED_SHIFT")
|
||
|
||
if (SL:GetValue("ACTOR_IS_PLAYER", targetID) and (optionAble or shiftAble)) or SL:GetValue("ACTOR_IS_MONSTER", targetID) then
|
||
-- 骑马检测
|
||
if not SL:GetValue("HORSE_CAN_LAUNCH_SKILL", SKILL_ID_PuGong) then
|
||
if not SL:RequestHorseDown() then
|
||
SL:SetValue("ATTACK_STATE", false)
|
||
end
|
||
return false
|
||
end
|
||
|
||
local skillID, destPosX, destPosY = SkillUtils.FindLockLaunchSkill()
|
||
if skillID then
|
||
SharedInputLaunchData.launchType = GUIDefine.LaunchType.LOCK
|
||
SharedInputLaunchData.priority = GUIDefine.LaunchPriority.SYSTEM
|
||
SharedInputLaunchData.targetID = targetID
|
||
SharedInputLaunchData.skillID = skillID
|
||
SharedInputLaunchData.destPosX = destPosX
|
||
SharedInputLaunchData.destPosY = destPosY
|
||
SL:InputLaunch(SharedInputLaunchData)
|
||
return true
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
-- 检查能否挖矿
|
||
function GUIFunction:CheckMiningAble()
|
||
local equip = GUIFunction:GetEquipDataByPos(GUIDefine.EquipPosUI.Equip_Type_Weapon)
|
||
if equip and equip.Shape == 19 and equip.Dura and equip.Dura > 0 then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
-- 自动挖矿
|
||
function GUIFunction:CheckAutoMining()
|
||
if SL:GetValue("BATTLE_IS_AUTO_FIGHT_STATE") then
|
||
return false
|
||
end
|
||
|
||
local autoMiningDir, autoMiningDstX, autoMiningDstY = SL:GetValue("AUTO_MINING_DATA")
|
||
if not autoMiningDir or not autoMiningDstX or not autoMiningDstY then
|
||
return false
|
||
end
|
||
|
||
if not GUIFunction:CheckMiningAble() then
|
||
SL:SetValue("AUTO_MINING_DATA", nil, nil, nil)
|
||
return false
|
||
end
|
||
|
||
SharedInputMiningData.dir = autoMiningDir
|
||
SharedInputMiningData.destX = autoMiningDstX
|
||
SharedInputMiningData.destY = autoMiningDstY
|
||
SL:InputMining(SharedInputMiningData)
|
||
|
||
return true
|
||
end
|
||
|
||
-------------------------------------------------------------------------
|
||
-- 新建条件红点控件
|
||
function GUIFunction:InitConditionRedWidget(parent, conditionStr, isTxt)
|
||
if not parent then
|
||
return
|
||
end
|
||
if not conditionStr or string.len(tostring(conditionStr)) <= 0 then
|
||
return
|
||
end
|
||
local data = SL:Split(conditionStr, "&")
|
||
local conditionList = SL:Split(SL:GetValue("IS_PC_OPER_MODE") and data[2] or data[1], "#")
|
||
local conditionID = tonumber(conditionList[1])
|
||
if not conditionID then
|
||
return
|
||
end
|
||
local x = tonumber(conditionList[2]) or 0
|
||
local y = tonumber(conditionList[3]) or 0
|
||
local type = tonumber(conditionList[4]) or 0
|
||
local param = conditionList[5]
|
||
local anP = tonumber(conditionList[6]) or 0 -- txt显示位置基点: 0:左上角, 1:右上角, 2:左下角, 3:右下角, 4:居中
|
||
if isTxt then
|
||
local parentSize = GUI:getContentSize(parent)
|
||
if anP == 0 then
|
||
y = parentSize.height - y
|
||
elseif anP == 1 then
|
||
x = parentSize.width + x
|
||
y = parentSize.height - y
|
||
elseif anP == 2 then
|
||
y = - y
|
||
elseif anP == 3 then
|
||
x = parentSize.width + x
|
||
y = - y
|
||
elseif anP == 4 then
|
||
x = math.floor(parentSize.width / 2) + x
|
||
y = math.floor(parentSize.height / 2) - y
|
||
end
|
||
end
|
||
|
||
GUI._conditionRedID = GUI._conditionRedID + 1
|
||
local conditionRedID = GUI._conditionRedID
|
||
local name = type == 0 and string.format("red_img_%s", conditionRedID) or string.format("red_sfx_%s", conditionRedID)
|
||
local widget = GUI:RedDot_Create(parent, name, x, y, type, param)
|
||
if widget then
|
||
GUI:RedDot_setGID(widget, conditionRedID)
|
||
GUI:RedDot_setBindConditionID(widget, conditionID)
|
||
end
|
||
end
|
||
-------------------------------------------------------------------------
|
||
|
||
local attTypeT = GUIDefine.AttTypeTable
|
||
local function getAddShow(id, value)
|
||
if tonumber(value) and tonumber(value) < 0 then
|
||
return ""
|
||
end
|
||
if id == attTypeT.HP or id == attTypeT.MP or id == attTypeT.Hit_Point or id == attTypeT.Speed_Point or id == attTypeT.Anti_Magic or id == attTypeT.Anti_Posion or
|
||
id == attTypeT.Posion_Recover or id == attTypeT.Health_Recover or id == attTypeT.Spell_Recover or id == attTypeT.Hit_Speed or id == attTypeT.God_Damage or id == attTypeT.Lucky then
|
||
return "+"
|
||
end
|
||
return ""
|
||
end
|
||
|
||
-- 获取BUFF添加属性文本显示
|
||
function GUIFunction:GetBuffAddAttrShow(buffID)
|
||
local config = SL:GetValue("BUFF_CONFIG", buffID)
|
||
if not buffID or not config then
|
||
return ""
|
||
end
|
||
|
||
local att = config.param
|
||
local attList = {}
|
||
if not att or att == "" or att == "0" or att == 0 then
|
||
return ""
|
||
end
|
||
local attArray = SL:Split(att, "|")
|
||
for k, v in ipairs(attArray) do
|
||
local attData = SL:Split(v, "#")
|
||
local attId = tonumber(attData[1])
|
||
local attValue = tonumber(attData[2])
|
||
table.insert(attList, {
|
||
id = attId,
|
||
value = attValue
|
||
})
|
||
end
|
||
|
||
-- 基础属性
|
||
local attrAlignment = SL:GetValue("IS_PC_OPER_MODE") and tonumber(SL:GetValue("GAME_DATA", "pc_tips_attr_alignment")) or 0
|
||
local attrCoefficient = SL:GetValue("IS_PC_OPER_MODE") and -1 or 1
|
||
attrAlignment = math.ceil(attrAlignment / 3)
|
||
|
||
-- 属性显示队列
|
||
local stringAtt = GUIFunction:GetAttDataShow(attList, nil, true)
|
||
-- 把基础属性和元素属性分开
|
||
local basicAttrShow = {}
|
||
local yuansuAttrShow = {}
|
||
for id, v in pairs(stringAtt) do
|
||
v.id = id
|
||
local originId = GetAttOriginId(id)
|
||
local attConfig = SL:GetMetaValue("ATTR_CONFIG", originId)
|
||
v.sort = attConfig and attConfig.sort or originId + 1000
|
||
|
||
if attConfig and attConfig.ys == 1 then
|
||
table.insert(yuansuAttrShow, v)
|
||
else
|
||
table.insert(basicAttrShow, v)
|
||
end
|
||
end
|
||
|
||
table.sort(basicAttrShow, function(a, b)
|
||
return a.sort < b.sort
|
||
end)
|
||
table.sort(yuansuAttrShow, function(a, b)
|
||
return a.sort < b.sort
|
||
end)
|
||
|
||
local attrStr = ""
|
||
local wrapFormat = "%s\\%s"
|
||
if basicAttrShow and next(basicAttrShow) then
|
||
local titleStr = string.format("<%s/FCOLOR=%s>", "[基础属性]:", 154)
|
||
attrStr = string.format(wrapFormat, attrStr, titleStr)
|
||
for _, v in ipairs(basicAttrShow) do
|
||
local name = string.gsub(v.name, " ", "")
|
||
name = string.gsub(name, " ", "")
|
||
local value = getAddShow(v.id, v.value) .. v.value
|
||
local nameLen, chineseLen = SL:GetUTF8ByteLen(name)
|
||
local newLen = math.max(attrAlignment - nameLen - chineseLen * attrCoefficient + SL:GetUTF8ByteLen(value), 0)
|
||
local lenStr = string.format("%%%ds", newLen)
|
||
value = string.format(lenStr, value)
|
||
|
||
local oneStr = name .. value
|
||
local color = v.color
|
||
if color and color > 0 then
|
||
oneStr = string.format("<%s/FCOLOR=%s>", oneStr, color)
|
||
end
|
||
attrStr = string.format(wrapFormat, attrStr, oneStr)
|
||
end
|
||
end
|
||
|
||
if yuansuAttrShow and next(yuansuAttrShow) then
|
||
local yuansuTitle = string.format("<%s/FCOLOR=%s>", "[元素属性]:", 154)
|
||
attrStr = string.format(wrapFormat, attrStr, yuansuTitle)
|
||
for _, v in ipairs(yuansuAttrShow) do
|
||
local name = string.gsub(v.name, " ", "")
|
||
name = string.gsub(name, " ", "")
|
||
local value = getAddShow(v.id, v.value) .. v.value
|
||
local nameLen, chineseLen = SL:GetUTF8ByteLen(name)
|
||
local newLen = math.max(attrAlignment - nameLen - chineseLen * attrCoefficient + SL:GetUTF8ByteLen(value), 0)
|
||
local lenStr = string.format("%%%ds", newLen)
|
||
value = string.format(lenStr, value)
|
||
|
||
local oneStr = name .. value
|
||
local color = v.color
|
||
if color and color > 0 then
|
||
oneStr = string.format("<%s/FCOLOR=%s>", oneStr, color)
|
||
end
|
||
attrStr = string.format(wrapFormat, attrStr, oneStr)
|
||
end
|
||
end
|
||
|
||
return attrStr
|
||
end
|
||
|
||
-------------------------------------------------------------------------
|
||
-- 仓库数据排序逻辑
|
||
function GUIFunction:SortStorageItemFunc(itemA, itemB)
|
||
local powerA = GUIFunction:GetEquipPower(itemA)
|
||
local powerB = GUIFunction:GetEquipPower(itemB)
|
||
if powerA ~= powerB then
|
||
return powerA > powerB
|
||
else
|
||
local isBindA, bindIndexA = SL:CheckItemBind(itemA.Index)
|
||
local isBindB, bindIndexB = SL:CheckItemBind(itemB.Index)
|
||
if isBindA == isBindB then
|
||
return itemA.Index < itemB.Index
|
||
else
|
||
return isBindA
|
||
end
|
||
end
|
||
end
|
||
|
||
------------------------------ UI 控件相关 -------------------------------
|
||
-- 给ScrollView/ListView添加垂直滑动条
|
||
function GUIFunction:SetScrollViewVerticalBar(parent, param)
|
||
if not parent then
|
||
return false
|
||
end
|
||
|
||
local bgPic = SL:FixFilePath(param.bgPic)
|
||
local barPic = SL:FixFilePath(param.barPic)
|
||
local arr1PicN = SL:FixFilePath(param.Arr1PicN)
|
||
local arr1PicP = SL:FixFilePath(param.Arr1PicP)
|
||
local arr2PicN = SL:FixFilePath(param.Arr2PicN)
|
||
local arr2PicP = SL:FixFilePath(param.Arr2PicP)
|
||
local default = param.default or 0
|
||
local x = param.x
|
||
local y = param.y
|
||
local list = param.list
|
||
local callFunc = param.callFunc
|
||
|
||
-- 背景
|
||
local barBg = GUI:Image_Create(parent, "barBg", x, y, bgPic)
|
||
local bgWidth = GUI:getContentSize(barBg).width
|
||
local bgHeight = GUI:getContentSize(list).height
|
||
|
||
GUI:setContentSize(barBg, bgWidth, bgHeight)
|
||
|
||
-- 上
|
||
local btnArr_1 = GUI:Button_Create(barBg, "btnArr_1", bgWidth / 2, bgHeight, arr1PicN)
|
||
if arr1PicP then
|
||
GUI:Button_loadTexturePressed(btnArr_1, arr1PicP)
|
||
end
|
||
GUI:setAnchorPoint(btnArr_1, 0.5, 1)
|
||
-- 下
|
||
local btnArr_2 = GUI:Button_Create(barBg, "btnArr_2", bgWidth / 2, 0, arr2PicN)
|
||
if arr2PicP then
|
||
GUI:Button_loadTexturePressed(btnArr_2, arr2PicP)
|
||
end
|
||
GUI:setAnchorPoint(btnArr_2, 0.5, 0)
|
||
-- bar
|
||
local sliderBar = GUI:Slider_Create(barBg, "sliderBar", bgWidth / 2, bgHeight / 2, "res/public/0.png", "res/public/0.png", barPic)
|
||
local btnArr1H = GUI:getContentSize(btnArr_1).height
|
||
local btnArr2H = GUI:getContentSize(btnArr_2).height
|
||
local barImgSize = GUI:getImageContentSize(barPic)
|
||
GUI:setContentSize(sliderBar, bgHeight - btnArr1H - btnArr2H - barImgSize.height, barImgSize.width)
|
||
|
||
GUI:setAnchorPoint(sliderBar, 0.5, 0.5)
|
||
GUI:setRotation(sliderBar, 90)
|
||
GUI:Slider_setPercent(sliderBar, default)
|
||
|
||
-- 计算偏移
|
||
local function getListOffY()
|
||
return GUI:ScrollView_getInnerContainerSize(list).height - GUI:getContentSize(list).height
|
||
end
|
||
|
||
-- list_cells
|
||
local function listCallback(sender, eventType)
|
||
if callFunc then
|
||
callFunc(sender, eventType)
|
||
end
|
||
|
||
SL:scheduleOnce(sliderBar, function()
|
||
local posY = GUI:ScrollView_getInnerContainerPosition(list).y
|
||
local offY = getListOffY()
|
||
local percent = 100
|
||
if offY > 0 then
|
||
percent = math.min(math.max(0, (offY + posY) / offY * 100), 100)
|
||
end
|
||
sliderBar:setPercent(percent)
|
||
end, 0.01)
|
||
end
|
||
|
||
if tolua.type(list) == "ccui.ListView" then
|
||
GUI:ListView_addOnScrollEvent(list, listCallback)
|
||
else
|
||
GUI:ScrollView_addOnScrollEvent(list, listCallback)
|
||
end
|
||
GUI:ListView_addMouseScrollPercent(list)
|
||
|
||
-- Slider_bar
|
||
GUI:Slider_addOnEvent(sliderBar, function()
|
||
local offY = getListOffY()
|
||
if offY > 0 then
|
||
GUI:ScrollView_scrollToPercentVertical(list, GUI:Slider_getPercent(sliderBar), 0.03, false)
|
||
else
|
||
GUI:Slider_setPercent(sliderBar, 100)
|
||
end
|
||
end)
|
||
|
||
local function upOrDown(percent)
|
||
GUI:Slider_setPercent(sliderBar, percent)
|
||
GUI:ScrollView_scrollToPercentVertical(list, percent, 0.03, false)
|
||
end
|
||
|
||
GUI:addOnClickEvent(btnArr_1, function()
|
||
local offY = getListOffY()
|
||
if offY > 0 then
|
||
upOrDown(0)
|
||
end
|
||
end)
|
||
|
||
GUI:addOnClickEvent(btnArr_2, function()
|
||
local offY = getListOffY()
|
||
if offY > 0 then
|
||
upOrDown(100)
|
||
end
|
||
end)
|
||
end
|
||
--------------------------------------------------------------------------
|
||
|
||
--------------------------- 主玩家检测手动移动触发 -------------------------
|
||
local originPosTab = {}
|
||
function GUIFunction:OnCheckInputMoveFunc()
|
||
local optionRunOne = SL:GetValue("SERVER_OPTION", "RunOne") == true -- 服务器开关控制跑1格
|
||
local isInputMove = false
|
||
local isRunOne = false
|
||
local moveDir = 0xff
|
||
local moveStep = 1
|
||
local moveType = nil
|
||
|
||
-- 点地板
|
||
-- touchPos: 点击地图坐标 touchWay: 点击方式 -1:鼠标右键 1:鼠标左键/单击
|
||
local touchPos = SL:GetValue("INPUT_MOUSE_TOUCH_POS")
|
||
local touchWay = SL:GetValue("INPUT_MOUSE_TOUCH_WAY")
|
||
originPosTab.x = SL:GetMetaValue("X")
|
||
originPosTab.y = SL:GetMetaValue("Y")
|
||
if touchPos and touchPos.x ~= 0 and touchPos.y ~= 0 and touchWay and (touchPos.x ~= originPosTab.x or touchPos.y ~= originPosTab.y) then
|
||
moveDir = SL:GetMetaValue("TARGET_MAPPOS_DIR", originPosTab, touchPos)
|
||
moveStep = touchWay == -1 and 2 or 1
|
||
isRunOne = optionRunOne and touchWay == -1
|
||
isInputMove = (moveDir and moveDir ~= SLDefine.Direction.INVALID) == true
|
||
if isInputMove then
|
||
moveType = GUIDefine.InputMoveType.GRID
|
||
end
|
||
end
|
||
|
||
-- 摇杆
|
||
if not SL:GetValue("IS_PC_OPER_MODE") and not isInputMove then
|
||
moveDir, moveStep = MainJoyStick.GetGamePadMove()
|
||
isRunOne = isRunOne or (optionRunOne and moveStep == 2)
|
||
isInputMove = moveDir ~= SLDefine.Direction.INVALID
|
||
if isInputMove then
|
||
moveType = GUIDefine.InputMoveType.JOYSTICK
|
||
end
|
||
end
|
||
|
||
-- 输入了移动 (点底板或摇杆)
|
||
if isInputMove then
|
||
-- 校正步数
|
||
local runStep = SL:GetValue("RUN_STEP")
|
||
moveStep = moveStep == 2 and runStep or moveStep
|
||
moveStep = SL:GetValue("CAN_RUN_ABLE") and moveStep or 1
|
||
|
||
-- 判断是否可开门
|
||
if SL:GetValue("CAN_OPEN_DOOR_BY_DIR", moveDir, moveStep) then
|
||
return false
|
||
end
|
||
|
||
-- 计算目标点
|
||
local inputX, inputY = SL:GetValue("CALC_DEST_POS_BY_DIR", moveDir, moveStep)
|
||
|
||
-- 限制范围移动
|
||
if SL:GetValue("CHECK_OUT_ESCORT_LIMIT_MOVE", inputX, inputY) then
|
||
SL:ShowSystemTips("你离镖车太远了!")
|
||
return false
|
||
end
|
||
|
||
-- 移动失败
|
||
if inputX == nil or inputY == nil then
|
||
if moveDir ~= SL:GetMetaValue("DIR") then
|
||
-- 转向
|
||
SL:SetValue("TURN_DIR", moveDir)
|
||
end
|
||
return false
|
||
end
|
||
|
||
-- 发起移动
|
||
SL:SetValue("USER_TO_MOVE", inputX, inputY, moveType)
|
||
end
|
||
return true, isInputMove, isRunOne
|
||
end
|
||
--------------------------------------------------------------------------
|
||
|
||
-------------------------------- 数值转换 ---------------------------------
|
||
-- 获取简化数字
|
||
function GUIFunction:GetSimpleNumber(n, places)
|
||
local places = places and "%." .. places .. "f" or "%.2f"
|
||
if n >= 100000000 then
|
||
return string.format(places .. "%s", n / 100000000, "亿")
|
||
end
|
||
if n >= 100000 then
|
||
return string.format(places .. "%s", n / 10000, "万")
|
||
end
|
||
if n >= 10000 then
|
||
return string.format(places .. "%s", n / 10000, "万")
|
||
end
|
||
return tostring(n)
|
||
end
|
||
|
||
local function unitFunc(num, pointBit)
|
||
if pointBit == 0 then
|
||
return math.floor(num)
|
||
end
|
||
local iNum, fNum = math.modf(num)
|
||
local fDecimal = math.pow(10, pointBit)
|
||
local newFNum = math.floor(fNum * fDecimal)
|
||
local newINum = iNum + (newFNum / fDecimal)
|
||
return newINum
|
||
end
|
||
|
||
-- 转化数值血量单位 过十亿(单位:E) 10w-99999w(单位:W)
|
||
function GUIFunction:ConvertHPUnit(hp, pointBit, notCheckSet)
|
||
local hpNum = tonumber(hp) or 0
|
||
if hpNum < 0 then
|
||
return hpNum
|
||
end
|
||
|
||
if notCheckSet then
|
||
return hpNum
|
||
elseif SL:GetValue("SETTING_ENABLED", SLDefine.SETTINGID.SETTING_IDX_HP_UNIT) ~= 1 then
|
||
return hpNum
|
||
end
|
||
|
||
-- 小数点后几位 默认保留后两位
|
||
pointBit = pointBit or 2
|
||
|
||
if hpNum >= 1000000000 then
|
||
hp = unitFunc(hpNum / 100000000, pointBit) .. "E"
|
||
elseif hpNum >= 100000 and hpNum <= 999999999 then
|
||
hp = unitFunc(hpNum / 10000, pointBit) .. "W"
|
||
end
|
||
|
||
return hp
|
||
end
|
||
--------------------------------------------------------------------------
|
||
|