Files
Endfield-Data/LuaScripts/UI/Widgets/ItemObtainWays.lua
2025-12-02 20:37:18 +07:00

534 lines
18 KiB
Lua

local UIWidgetBase = require_ex('Common/Core/UIWidgetBase')
local ActionOnSetNaviTarget = CS.Beyond.Input.ActionOnSetNaviTarget
ItemObtainWays = HL.Class('ItemObtainWays', UIWidgetBase)
ItemObtainWays.hasObtainWay = HL.Field(HL.Boolean) << false
ItemObtainWays.m_obtainCells = HL.Field(HL.Forward('UIListCache'))
ItemObtainWays.m_exitNaviBindingId = HL.Field(HL.Number) << -1
ItemObtainWays.m_itemTipsPosInfo = HL.Field(HL.Table)
ItemObtainWays.m_itemId = HL.Field(HL.String) << ''
ItemObtainWays.m_onClickItem = HL.Field(HL.Function)
ItemObtainWays._OnFirstTimeInit = HL.Override() << function(self)
self.m_obtainCells = UIUtils.genCellCache(self.view.obtainCell)
self.m_exitNaviBindingId = InputManagerInst:CreateBindingByActionId("item_tips_exit_obtain_ways", function()
self:_ToggleNavi(false)
end, self.view.inputBindingGroupMonoTarget.groupId)
InputManagerInst:ToggleBinding(self.m_exitNaviBindingId, false)
end
ItemObtainWays._ToggleNavi = HL.Method(HL.Boolean) << function(self, active)
if active then
if self.hasObtainWay then
local cell = self.m_obtainCells:Get(1)
InputManagerInst.controllerNaviManager:SetTarget(cell.selectedTarget)
else
InputManagerInst.controllerNaviManager:SetTarget(self.view.emptyNode.button)
end
else
InputManagerInst.controllerNaviManager:TryRemoveLayer(self.view.selectableNaviGroup)
end
InputManagerInst:ToggleBinding(self.m_exitNaviBindingId, active)
end
ItemObtainWays.InitItemObtainWays = HL.Method(HL.String, HL.Opt(HL.Number, HL.Table, HL.Function)) << function(
self, itemId, instId, itemTipsPosInfo, onClickItem)
self:_FirstTimeInit()
self.m_itemTipsPosInfo = itemTipsPosInfo
self.m_itemId = itemId
self.m_onClickItem = onClickItem
local itemCfg = Tables.itemTable:GetValue(itemId)
local obtainInfoList = self:_GenerateObtainInfoList(itemId)
self.hasObtainWay = next(obtainInfoList) ~= nil
if self.hasObtainWay then
self.view.gameObject:SetActive(true)
self.view.emptyNode.gameObject:SetActive(false)
self.m_obtainCells:Refresh(#obtainInfoList, function(cell, index)
local obtainInfo = obtainInfoList[index]
self:_RefreshObtainCell(cell, obtainInfo, index)
end)
else
if itemCfg.noObtainWayId == nil or itemCfg.noObtainWayId.Count == 0 then
self.view.gameObject:SetActive(false)
else
local find, showNoObtainWayId = self:_FindShowNoObtainWayId(itemCfg)
if find then
self.view.gameObject:SetActive(true)
self.m_obtainCells:Refresh(0)
self.view.emptyNode.gameObject:SetActive(false)
local _, obtainWayCfg = Tables.systemJumpTable:TryGetValue(showNoObtainWayId)
if obtainWayCfg then
self.view.emptyNode.gameObject:SetActive(true)
self.view.emptyNode.nameTxt:SetAndResolveTextStyle(obtainWayCfg.desc)
self.view.emptyNode.jumpNodeDeco.gameObject:SetActive(false)
self.view.emptyNode.button.onClick:RemoveAllListeners()
local isUnlock = Utils.isSystemUnlocked(obtainWayCfg.bindSystem) and not Utils.isInBlackbox()
if isUnlock then
local phaseId = PhaseId[obtainWayCfg.phaseId]
local phaseArgs
if not string.isEmpty(obtainWayCfg.phaseArgs) then
phaseArgs = Json.decode(obtainWayCfg.phaseArgs)
end
if phaseId ~= nil and PhaseManager:CheckCanOpenPhase(phaseId, phaseArgs) then
self.view.emptyNode.jumpNodeDeco.gameObject:SetActive(true)
self.view.emptyNode.button.onClick:AddListener(function()
PhaseManager:GoToPhase(phaseId, phaseArgs)
Notify(MessageConst.HIDE_ITEM_TIPS)
end)
end
end
end
end
end
end
LayoutRebuilder.ForceRebuildLayoutImmediate(self.transform)
LayoutRebuilder.ForceRebuildLayoutImmediate(self.view.emptyNode.nameTxt.transform)
end
ItemObtainWays._FindShowNoObtainWayId = HL.Method(HL.Any).Return(HL.Boolean, HL.String) << function(self, itemCfg)
if itemCfg == nil or itemCfg.noObtainWayId == nil or itemCfg.noObtainWayId.Count == 0 then
return false, ""
end
if itemCfg.noObtainWayId.Count == 1 then
return true, itemCfg.noObtainWayId[CSIndex(1)]
end
for csIndex = 0, itemCfg.noObtainWayId.Count - 1 do
if csIndex >= itemCfg.noObtainWayConditionId.Count then
return true, itemCfg.noObtainWayId[csIndex]
end
local conditionId = itemCfg.noObtainWayConditionId[csIndex]
local succ, conditionCfg = Tables.noObtainWayCondTable:TryGetValue(conditionId)
if not succ then
return true, itemCfg.noObtainWayId[csIndex]
end
local unlockTag = false
if conditionCfg.conditionType == GEnums.ConditionType.CheckWikiUnlocked then
unlockTag = WikiUtils.isWikiEntryUnlock(conditionCfg.checkId)
elseif conditionCfg.conditionType == GEnums.ConditionType.CheckFacTechTreeUnlocked then
unlockTag = not GameInstance.player.facTechTreeSystem:NodeIsLocked(conditionCfg.checkId)
end
if not unlockTag then
return true, itemCfg.noObtainWayId[csIndex]
end
end
return false, ""
end
ItemObtainWays._GenerateObtainInfoList = HL.Method(HL.String).Return(HL.Table) << function(self, itemId)
local obtainInfoList = {}
local itemCfg = Tables.itemTable:GetValue(itemId)
if itemCfg.obtainWayIds then
for k, obtainWayId in pairs(itemCfg.obtainWayIds) do
local _, obtainWayCfg = Tables.systemJumpTable:TryGetValue(obtainWayId)
if obtainWayCfg then
local isUnlock = Utils.isSystemUnlocked(obtainWayCfg.bindSystem)
if isUnlock then
local phaseId = PhaseId[obtainWayCfg.phaseId]
local phaseArgs
if not string.isEmpty(obtainWayCfg.phaseArgs) then
phaseArgs = Json.decode(obtainWayCfg.phaseArgs)
end
local blockJumpToast = ""
if phaseId ~= nil and not PhaseManager:CheckCanOpenPhase(phaseId, phaseArgs) then
if obtainWayCfg.bindSystem == GEnums.UnlockSystemType.Map then
blockJumpToast = Language.LUA_OBTAIN_WAYS_MAP_JUMP_BLOCKED
else
blockJumpToast = Language.LUA_OBTAIN_WAYS_JUMP_BLOCKED
end
end
table.insert(obtainInfoList, {
name = obtainWayCfg.desc,
iconFolder = UIConst.UI_SPRITE_ITEM_TIPS,
iconId = obtainWayCfg.iconId,
phaseId = phaseId,
phaseArgs = phaseArgs,
blockJumpToast = blockJumpToast,
sortId = -k / 1000,
})
end
end
end
end
local craftInfoList, canCraft = FactoryUtils.getItemCrafts(itemId)
local hasFormula = next(craftInfoList) ~= nil
if canCraft and hasFormula then
self:_InsertCrafts(obtainInfoList, craftInfoList)
end
if self.view.config.ENABLE_DYNAMIC_SORT then
table.sort(obtainInfoList, Utils.genSortFunction({"sortId"}))
end
return obtainInfoList
end
ItemObtainWays._InsertCrafts = HL.Method(HL.Table, HL.Table) << function(self, obtainInfoList, craftInfoList)
local manuSortId, sortId, curOpenedBuildingId
local topPhaseId = PhaseManager:GetTopPhaseId()
if self.view.config.ENABLE_DYNAMIC_SORT then
if topPhaseId == PhaseId.FacMachine then
curOpenedBuildingId = FactoryUtils.getCurOpenedBuildingId()
sortId = 1
else
local inFac = Utils.isInFacMainRegion()
manuSortId = inFac and 1 or -1
sortId = inFac and 100 or -100
end
end
local craftsByBuilding = {}
local manualCrafts = {}
for _, info in pairs(craftInfoList) do
local buildingId = info.buildingId
if not buildingId then
table.insert(manualCrafts, info)
else
if not craftsByBuilding[buildingId] then
craftsByBuilding[buildingId] = {}
end
table.insert(craftsByBuilding[buildingId], info)
end
end
if next(manualCrafts) then
for _, data in pairs(manualCrafts) do
local info = {
name = Language.LUA_OBTAIN_WAYS_MANUAL_CRAFT_NAME,
crafts = manualCrafts,
iconFolder = UIConst.UI_SPRITE_ITEM_TIPS,
iconId = UIConst.UI_MANUALCRAFT_ICON_ID,
phaseId = PhaseId.ManualCraft,
phaseArgs = {jumpId = data.craftId},
sortId = manuSortId,
}
table.insert(obtainInfoList, info)
end
end
for buildingId, crafts in pairs(craftsByBuilding) do
local buildingData = Tables.factoryBuildingTable:GetValue(buildingId)
local groupInfo = {
buildingId = buildingId,
name = buildingData.name,
iconFolder = UIConst.UI_SPRITE_FAC_BUILDING_PANEL_ICON,
iconId = buildingData.iconOnPanel,
}
local hubBan = false
if sortId then
if curOpenedBuildingId == buildingId then
groupInfo.sortId = 1000
else
groupInfo.sortId = sortId
end
end
if buildingData.type == GEnums.FacBuildingType.Hub or buildingData.type == GEnums.FacBuildingType.SubHub then
if Utils.isSystemUnlocked(GEnums.UnlockSystemType.FacHub) then
groupInfo.name = Language.ITEM_OBTAIN_WAY_HUB_CRAFT
groupInfo.phaseId = PhaseId.FacBuildListSelect
local itemId = FactoryUtils.getBuildingItemId(crafts[1].craftId)
groupInfo.phaseArgs = { selectedId = itemId }
if topPhaseId ~= PhaseId.FacMachine and topPhaseId ~= PhaseId.Inventory then
groupInfo.phaseArgs.onlyCraftNode = true
end
else
hubBan = true
end
end
for _, info in pairs(crafts) do
if buildingData.type ~= GEnums.FacBuildingType.Miner then
if not groupInfo.crafts then
groupInfo.crafts = {}
end
table.insert(groupInfo.crafts, info)
end
end
if not hubBan then
table.insert(obtainInfoList, groupInfo)
end
end
end
local jumpBlockWhiteMap = {
[PhaseId.CommonMoneyExchange] = true,
}
ItemObtainWays._RefreshObtainCell = HL.Method(HL.Any, HL.Table, HL.Number) << function(self, cell, info, index)
cell.selectedTarget = cell.normalNode.button
cell.normalNode.nameTxt.text = info.name
local iconId = info.iconId
local iconFolder = info.iconFolder
cell.normalNode.icon.gameObject:SetActive(iconId ~= nil and iconFolder ~= nil)
if iconId ~= nil and iconFolder ~= nil then
cell.normalNode.icon:LoadSprite(info.iconFolder, info.iconId)
end
self:_UpdateCraftCell(cell, info)
cell.normalNode.button.onClick:RemoveAllListeners()
if info.phaseId or not string.isEmpty(info.buildingId) then
cell.normalNode.animationNode:PlayInAnimation()
cell.normalNode.button.onClick:AddListener(function()
local isBlocked
if jumpBlockWhiteMap[info.phaseId] then
isBlocked = UIManager:ShouldBlockAllObtainWaysJump()
else
isBlocked = UIManager:ShouldBlockObtainWaysJump()
end
if isBlocked then
Notify(MessageConst.SHOW_TOAST, Language.LUA_OBTAIN_WAYS_JUMP_BLOCKED)
return
end
if info.blockJumpToast ~= nil and not string.isEmpty(info.blockJumpToast) then
Notify(MessageConst.SHOW_TOAST, info.blockJumpToast)
return
end
Notify(MessageConst.HIDE_ITEM_TIPS)
if info.phaseId then
PhaseManager:GoToPhase(info.phaseId, info.phaseArgs)
else
local firstCraft = info.crafts and info.crafts[1] or nil
if firstCraft then
PhaseManager:GoToPhase(PhaseId.Wiki, {
isItemCraft = true,
itemId = self.m_itemId,
craftId = firstCraft.craftId })
else
Notify(MessageConst.SHOW_WIKI_ENTRY, { buildingId = info.buildingId })
end
end
end)
cell.normalNode.button:ChangeActionOnSetNaviTarget(ActionOnSetNaviTarget.PressConfirmTriggerOnClick)
cell.normalNode.button.interactable = true
else
cell.normalNode.button:ChangeActionOnSetNaviTarget(ActionOnSetNaviTarget.None)
cell.normalNode.animationNode:PlayOutAnimation()
if not DeviceInfo.usingController then
cell.normalNode.button.interactable = false
end
end
LayoutRebuilder.ForceRebuildLayoutImmediate(cell.transform)
cell.gameObject.name = "ObtainWay-" .. index
end
ItemObtainWays._UpdateCraftCell = HL.Method(HL.Table, HL.Table) << function(self, cell, info)
if not cell.craftCells then
cell.craftCells = UIUtils.genCellCache(cell.craftCell)
end
if not info.crafts then
cell.craftCells:Refresh(0)
return
end
local craftCount = #info.crafts
cell.craftCells:Refresh(craftCount, function(craftCell, craftIndex)
local craftInfo = info.crafts[craftIndex]
if not craftCell.itemCells then
craftCell.itemCells = UIUtils.genCellCache(craftCell.itemCell)
end
local incomeCount = craftInfo.incomes and #craftInfo.incomes or 0
local outcomeCount = craftInfo.outcomes and #craftInfo.outcomes or 0
craftCell.itemCells:Refresh(incomeCount + outcomeCount, function(itemCell, itemIndex)
local bundle
if itemIndex <= incomeCount then
bundle = craftInfo.incomes[itemIndex]
else
bundle = craftInfo.outcomes[itemIndex - incomeCount]
end
if self.view.config.IS_SIMPLE_ITEM then
itemCell:InitItemSimple(bundle.id, bundle.count)
else
if self.m_onClickItem then
itemCell:InitItem(bundle, function()
self.m_onClickItem(itemCell, craftCell)
end)
else
itemCell:InitItem(bundle, self.view.config.IS_ITEM_SHOW_TIPS)
end
if self.m_itemTipsPosInfo then
itemCell:SetExtraInfo(self.m_itemTipsPosInfo)
end
end
itemCell.transform:SetSiblingIndex(itemIndex)
itemCell.gameObject.name = "Item-" .. bundle.id
end)
craftCell.arrow.transform:SetSiblingIndex(incomeCount + 1)
craftCell.line.gameObject:SetActive(craftIndex ~= craftCount)
craftCell.mask.gameObject:SetActive(craftIndex == 1)
if craftCell.liquidLabel ~= nil then
craftCell.liquidLabel.gameObject:SetActive(craftInfo.formulaMode == FacConst.FAC_FORMULA_MODE_MAP.LIQUID)
end
craftCell.gameObject.name = "Craft-" .. craftInfo.craftId
if craftCell.pinBtn then
local showPin = not string.isEmpty(craftInfo.craftId) and
Tables.factoryMachineCraftTable:ContainsKey(craftInfo.craftId)
craftCell.pinBtn.gameObject:SetActive(showPin)
if showPin then
craftCell.pinBtn:InitPinBtn(craftInfo.craftId, GEnums.FCPinPosition.Formula:GetHashCode())
craftCell.pinBtn.view.pinToggle.onHoverChange:RemoveAllListeners()
craftCell.pinBtn.view.pinToggle.onHoverChange:AddListener(function(isHover)
if craftCell.stateController == nil then
return
end
if isHover then
craftCell.stateController:SetState("Highlighted")
else
craftCell.stateController:SetState("Other")
end
end)
end
end
if craftCell.add then
if not craftCell.addCells then
craftCell.addCells = UIUtils.genCellCache(craftCell.add)
end
craftCell.addCells:Refresh(incomeCount + outcomeCount - 2, function(addCell, addCellIndex)
local siblingIndex = 0
if addCellIndex <= incomeCount - 1 then
siblingIndex = addCellIndex * 2
else
siblingIndex = (addCellIndex + 1) * 2
end
addCell.transform:SetSiblingIndex(siblingIndex)
end)
end
if self.view.config.IS_SHOW_CRAFT_TIME then
if craftInfo.time then
craftCell.time.text = string.format(Language["LUA_CRAFT_CELL_STANDARD_TIME"], FactoryUtils.getCraftTimeStr(craftInfo.time))
craftCell.time.gameObject:SetActive(true)
else
craftCell.time.gameObject:SetActive(false)
end
else
craftCell.time.gameObject:SetActive(false)
end
end)
end
HL.Commit(ItemObtainWays)
return ItemObtainWays