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("%s", 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, "")
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 "
" 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("%s%s%s", prefix, name, data.Msg or "")
if isPrivateTime then
return string.format("%s%s", 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
--------------------------------------------------------------------------