-- Smart Pickup — fanen Flows -- Tavle øverst: én tekstrække pr. flow (Vare · Fra → Til · Regel · Traktorer · Status), det valgte -- markeret med ">". Under tavlen: detail-blok for det valgte flow — Retning, Fra/Til som BYGNINGER -- (markøren findes automatisk), Varer, Regler, Vent ved, Traktorer, Status — og Wait-puljerne. -- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua). -- ---- tavlen ---- local function joinOr(list, empty) if #list == 0 then return empty end return table.concat(list, " + ") end -- Én række i Oversigt: {flow, varer, fra, til, traktorer "kører/i alt", status}. -- Status = advarsel (!!), ellers begrundelse, ellers flowets regel. function SmartPickupFrame:flowCells(adEnv, run) local row = ADRunsController.getFlowRow(adEnv, run) local i18n = self.i18n local products if row.productAuto then products = i18n:getText("spu_flow_needBased") else local titles = {} for _, name in ipairs(row.productNames) do local index = g_fillTypeManager:getFillTypeIndexByName(name) local title = index ~= nil and g_fillTypeManager.getFillTypeTitleByIndex ~= nil and g_fillTypeManager:getFillTypeTitleByIndex(index) or name table.insert(titles, tostring(title)) end products = joinOr(titles, i18n:getText("spu_flow_noProducts")) end local missing = {} for _, name in ipairs(row.missing) do missing[name] = true end local function mark(names) local out = {} for _, name in ipairs(names) do table.insert(out, missing[name] and (name .. " !") or name) end return out end local from, to if row.kind == "outbound" then from = joinOr(mark(row.fromNames), i18n:getText("spu_flow_noSource")) local seen, policies = {}, {} for _, policy in ipairs(row.policies) do if not seen[policy] then seen[policy] = true; table.insert(policies, i18n:getText("spu_policy_" .. policy)) end end to = joinOr(policies, i18n:getText("spu_flow_noProducts")) else from = i18n:getText("spu_from_allSilos") to = joinOr(mark(row.toNames), i18n:getText("spu_flow_noTarget")) end local rule if row.kind == "outbound" then rule = string.format(i18n:getText("spu_flow_ruleOut"), row.sellAtPercent or 90, row.storeAbovePercent or 80) if row.collectRound then rule = rule .. ", " .. i18n:getText("spu_flow_round") end else rule = row.loops ~= nil and row.loops > 0 and string.format(i18n:getText("spu_flow_ruleInLoops"), row.loops) or i18n:getText("spu_flow_ruleIn") end local status = rule if row.warning ~= nil then status = "!! " .. row.warning elseif row.reason ~= nil then status = row.reason end local name = (run.id == self.selectedRunId and "> " or "") .. tostring(run.name) return {name, products, from, to, string.format("%d/%d", row.running, row.total), status} end -- Fanen Oversigt: alle flows som tabel, grupperet Ind/Ud efter navn. function SmartPickupFrame:fillOverviewRows(adEnv) self.overviewRows = {} local i18n = self.i18n self:addCellRow(self.flowPrefab, {i18n:getText("spu_col_flow"), i18n:getText("spu_col_goods"), i18n:getText("spu_col_from"), i18n:getText("spu_col_to"), i18n:getText("spu_col_tractors"), i18n:getText("spu_col_status")}) for _, group in ipairs(ADFlowView.boardGroups(ADRunsController.store.runs)) do self:addTextRow(i18n:getText(group.kind == "outbound" and "spu_board_outbound" or "spu_board_supply")) for _, run in ipairs(group.runs) do table.insert(self.overviewRows, {runId = run.id, cells = self:addCellRow(self.flowPrefab, self:flowCells(adEnv, run))}) end end if #ADRunsController.store.runs == 0 then self:addTextRow(i18n:getText("spu_noRuns")) end end function SmartPickupFrame:refreshOverview(adEnv) for _, entry in ipairs(self.overviewRows or {}) do local run = ADRuns.getRun(ADRunsController.store, entry.runId) if run ~= nil then SmartPickupFrame.setCells(entry.cells, self:flowCells(adEnv, run)) end end end -- ---- detail-blok ---- -- "Kostald 1 (stald) — markør 'cow 1 milk' 12 m" / "… — INGEN MARKØR inden for 40 m" function SmartPickupFrame:describeBuilding(building, role) local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, role) or {} local kindText = self.i18n:getText("spu_source_kind_" .. tostring(building.kind)) if markers[1] == nil then return string.format(" %s (%s) — %s", building.name, kindText, self.i18n:getText("spu_noMarker")) end -- kort form, så flere markører kan stå på én række: "Cow Barn (large) — Cow 1 Milk 6 m · Cow 1 Slurry 4 m" local parts = {} for _, marker in ipairs(markers) do table.insert(parts, string.format(self.i18n:getText("spu_markerAt"), marker.name, marker.distance)) end return string.format(" %s — %s", building.name, table.concat(parts, " · ")) end -- Afkrydsning pr. bygning: kilder (udkørsel, role "load") eller mål (forsyning, role "unload"). function SmartPickupFrame:fillBuildingRows(adEnv, run, role) if ADBuildings == nil then self:addTextRow(self.i18n:getText("spu_status_noAd")) return end local chosen = {} local ids = role == "load" and run.sourceBuildingIds or role == "store" and run.storeBuildingIds or run.targetBuildingIds local rowKind = role == "load" and "sourceBuilding" or role == "store" and "storeBuilding" or "targetBuilding" for _, id in ipairs(ids or {}) do chosen[id] = true end local count = 0 -- kandidater -> valgte først, så med markør; uden markør kun med "Vis alle bygninger" local candidates = {} -- "Lager til": kun bygninger der kan tage flowets lagervarer (æg-paller -> palleskure der tager æg) local storeGoods = role == "store" and ADRunsController.getStoreGoods(adEnv, run) or nil for _, building in ipairs(ADBuildings.list(adEnv, g_currentMission:getFarmId())) do local isStoreKind = building.kind == "silo" or building.kind == "factory" or building.kind == "objectStorage" local fits = (role == "load" and building.canBeSource) or (role == "unload" and building.canBeTarget) or (role == "store" and isStoreKind and (chosen[building.id] or ADRunsController.canStoreAt(adEnv, building, storeGoods))) if fits then local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, role == "store" and "unload" or role) or {} table.insert(candidates, {id = building.id, name = building.name, hasMarker = markers[1] ~= nil, building = building}) end end local shown = ADFlowView.buildingRows(candidates, chosen, self.showAllBuildings == true) local hiddenBuildings = ADFlowView.hiddenCount(candidates, shown) if hiddenBuildings > 0 or self.showAllBuildings then self:addToggleRow("showAllBuildings", string.format(self.i18n:getText("spu_showAllBuildings"), hiddenBuildings), {self.i18n:getText("ui_no"), self.i18n:getText("ui_yes")}, self.showAllBuildings == true) end for _, entry in ipairs(shown) do local building = entry.building count = count + 1 local row = self:addRow(self.ingredientPrefab, {kind = rowKind, buildingId = building.id}) row:getDescendantByName("title"):setText(self:describeBuilding(building, role == "store" and "unload" or role)) row:getDescendantByName("option"):setState(chosen[building.id] and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false) end -- valgte bygninger der ikke længere findes (solgt) for _, id in ipairs(ids or {}) do if ADBuildings.find(adEnv, g_currentMission:getFarmId(), id) == nil then local row = self:addRow(self.ingredientPrefab, {kind = rowKind, buildingId = id}) row:getDescendantByName("title"):setText(string.format(" %s — %s", tostring(id), self.i18n:getText("spu_buildingGone"))) row:getDescendantByName("option"):setState(SmartPickupFrame.STATE_ON, false) end end if count == 0 then self:addTextRow(self.i18n:getText("spu_noBuildings")) end end function SmartPickupFrame:rebuildFlowDetail(adEnv, run) ADRunsController.resolveMarkers(adEnv, run) run = self:getRun() local isOut = run.kind == "outbound" self:addTextRow(string.format(self.i18n:getText("spu_section_flow"), run.name)) self.directionRowOption = self:addToggleRow("direction", self.i18n:getText("spu_direction"), {self.i18n:getText("spu_direction_in"), self.i18n:getText("spu_direction_out")}, isOut) if isOut then self:addTextRow(self.i18n:getText("spu_section_from")) self:fillBuildingRows(adEnv, run, "load") self:addTextRow(self.i18n:getText("spu_section_products")) self:fillProductRows(adEnv, run) self:addTextRow(self.i18n:getText("spu_section_rules")) self.sellAtOption:setState(SmartPickupFrame.getStepIndex(self.sellAtSteps, run.sellAtPercent, ADRuns.DEFAULT_SELL_AT_PERCENT), false) self.storeAboveOption:setState(SmartPickupFrame.getStepIndex(self.storeAboveSteps, run.storeAbovePercent, ADRuns.DEFAULT_STORE_ABOVE_PERCENT), false) self.collectRoundRowOption = self:addToggleRow("collectRound", self.i18n:getText("spu_collectRound"), {self.i18n:getText("ui_no"), self.i18n:getText("ui_yes")}, run.collectRound == true) self:addTextRow(self.i18n:getText("spu_section_store")) self:fillBuildingRows(adEnv, run, "store") self:fillOutboundStatusRows(adEnv, run) else self:addTextRow(self.i18n:getText("spu_section_to")) self:fillBuildingRows(adEnv, run, "unload") self:addTextRow(self.i18n:getText("spu_section_targets")) self.ingredientModeRowOption = self:addToggleRow("ingredientMode", self.i18n:getText("spu_ingredientMode"), {self.i18n:getText("spu_mode_auto"), self.i18n:getText("spu_mode_manual")}, run.ingredientMode == "manual") self:fillIngredientRows(adEnv, run) self:fillNeedsRows(adEnv, run) self:addTextRow(self.i18n:getText("spu_section_rules")) self.loopsOption:setState(run.loops + 1, false) self.returnBelowOption:setState(self:getReturnBelowIndex(run), false) end end -- ---- callbacks ---- function SmartPickupFrame:onClickDirection(state) self:safe(function(frame) local run = frame:getRun() if run == nil then return end ADRunsController.updateRun(run.id, {kind = state == SmartPickupFrame.STATE_ON and "outbound" or "supply"}) frame:requestRebuild() end) end function SmartPickupFrame:onClickBuilding(state, element) self:safe(function(frame) local run, data = frame:getRun(), frame.rowData[element] if run == nil or data == nil then return end if data.kind == "sourceBuilding" then ADRunsController.store = ADRuns.toggleSourceBuilding(ADRunsController.store, run.id, data.buildingId) elseif data.kind == "storeBuilding" then ADRunsController.store = ADRuns.toggleStoreBuilding(ADRunsController.store, run.id, data.buildingId) local updatedStore = ADRuns.getRun(ADRunsController.store, run.id) Logging.info(SmartPickupFrame.LOG_PREFIX .. "run '%s': storeBuildings=%s", tostring(run.name), table.concat(updatedStore.storeBuildingIds or {}, " ")) frame:requestRebuild() return else ADRunsController.store = ADRuns.toggleTargetBuilding(ADRunsController.store, run.id, data.buildingId) end local updated = ADRuns.getRun(ADRunsController.store, run.id) Logging.info(SmartPickupFrame.LOG_PREFIX .. "run '%s': %s=%s", tostring(run.name), data.kind == "sourceBuilding" and "sourceBuildings" or "targetBuildings", table.concat(data.kind == "sourceBuilding" and updated.sourceBuildingIds or updated.targetBuildingIds, " ")) ADRunsController.resolveMarkers(frame.getAdEnv(), updated) frame:requestRebuild() end) end