-- Smart Pickup — fanen Udkørsel -- Kilder (afkrydsning), varer med politik (Fra/Lager/Salg/Salg, ellers lager) og aktuel pris i -- % af årets top, regler (pristærskel, lagertærskel, opsamlingsrunde) og status/advarsler. -- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua). -- Bedste pris-% for varen over alle salgssteder (uanset vejnet — det er til visning; turen -- bruger kun nåelige). {percent, stationName} eller nil. SmartPickupFrame.SELL_MARKERS_CACHE_MS = 30000 -- Salgsstederne slås op over alle markører × stationer; cachet, så det ikke sker pr. vare pr. sekund. function SmartPickupFrame:getSellMarkersCached(adEnv) local time = g_time or (os.clock ~= nil and os.clock() * 1000) or 0 if self.sellMarkersCache == nil or (time - (self.sellMarkersCacheTime or 0)) > SmartPickupFrame.SELL_MARKERS_CACHE_MS then self.sellMarkersCache = ADSources.getSellMarkers(adEnv, g_currentMission:getFarmId()) self.sellMarkersCacheTime = time end return self.sellMarkersCache end function SmartPickupFrame:getProductQuote(adEnv, fillType) if ADSources == nil or ADPrices == nil then return nil end local best = nil for _, entry in ipairs(self:getSellMarkersCached(adEnv)) do if ADSources.stationAccepts(entry.station, fillType) then local quote = ADPrices.getQuote(entry.station, fillType) if quote ~= nil and (best == nil or quote.percent > best.percent) then best = {percent = quote.percent, stationName = tostring(entry.marker.name)} end end end return best end -- "Sukker — 150.0k l — 78 % af top (Grain Elevator)" function SmartPickupFrame:describeProduct(adEnv, product) local price = self.i18n:getText("spu_price_none") local quote = self:getProductQuote(adEnv, product.fillType) if quote ~= nil then price = string.format(self.i18n:getText("spu_price_pct"), quote.percent, quote.stationName) end return string.format(self.i18n:getText("spu_product_row"), tostring(product.title), SmartPickupFrame.formatCompact(product.available or 0), price) end -- Paller lagres i et palleskur (objektlager) i stedet for en silo — samme politikker som bulk. function SmartPickupFrame.getPoliciesFor(product) return SmartPickupFrame.POLICIES end function SmartPickupFrame.getPolicyIndex(policies, policy) for index, name in ipairs(policies) do if name == policy then return index end end return 1 end function SmartPickupFrame:fillSourceRows(adEnv, run) local chosen = {} for _, id in ipairs(run.sourceWayPointIds or {}) do chosen[id] = true end local entries = ADRunsController.getSourceMarkers(adEnv, g_currentMission:getFarmId()) for _, entry in ipairs(entries) do local row = self:addRow(self.ingredientPrefab, {kind = "source", wayPointId = entry.marker.id}) local kindText = self.i18n:getText("spu_source_kind_" .. tostring(entry.kind)) row:getDescendantByName("title"):setText(string.format(" %s — %s (%s)", tostring(entry.marker.name), tostring(entry.name), kindText)) row:getDescendantByName("option"):setState(chosen[entry.marker.id] and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false) end if #entries == 0 then self:addTextRow(self.i18n:getText("spu_noSources")) end end function SmartPickupFrame:fillProductRows(adEnv, run) self.productRows = {} local products = ADRunsController.getRunProducts(adEnv, run) for _, product in ipairs(products) do local policies = SmartPickupFrame.getPoliciesFor(product) local policyTexts = {} for _, policy in ipairs(policies) do table.insert(policyTexts, self.i18n:getText("spu_policy_" .. policy)) end local row = self:addRow(self.productPrefab, {kind = "product", name = product.name, policies = policies}) local option = row:getDescendantByName("option") option:setTexts(policyTexts) option:setState(SmartPickupFrame.getPolicyIndex(policies, product.policy), false) local title = row:getDescendantByName("title") title:setText(self:describeProduct(adEnv, product)) table.insert(self.productRows, {name = product.name, title = title, option = option}) end if #products == 0 then self:addTextRow(#(run.sourceWayPointIds or {}) == 0 and self.i18n:getText("spu_noSources") or self.i18n:getText("spu_noProducts")) end end function SmartPickupFrame:fillOutboundStatusRows(adEnv, run) self.outboundStatusRows = {} local status = ADRunsController.getOutboundStatus(adEnv, run) for _, reason in ipairs(status.reasons or {}) do table.insert(self.outboundStatusRows, self:addTextRow(string.format(self.i18n:getText("spu_outbound_waiting"), reason))) end if status.warning ~= nil then table.insert(self.outboundStatusRows, self:addTextRow(string.format(self.i18n:getText("spu_outbound_warning"), status.warning))) end end function SmartPickupFrame:rebuildOutboundTab(adEnv, run) 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_sources")) self:fillSourceRows(adEnv, run) self:addTextRow(self.i18n:getText("spu_section_products")) self:fillProductRows(adEnv, run) self:fillOutboundStatusRows(adEnv, run) end -- Hvert sekund: produktrækkernes mængde/pris og statuslinjerne (antal linjer ændres kun ved rebuild). function SmartPickupFrame:refreshOutboundRows(adEnv, run) local byName = {} for _, product in ipairs(ADRunsController.getRunProducts(adEnv, run)) do byName[product.name] = product end for _, row in ipairs(self.productRows or {}) do if byName[row.name] ~= nil then row.title:setText(self:describeProduct(adEnv, byName[row.name])) end end local status = ADRunsController.getOutboundStatus(adEnv, run) local lines = {} for _, reason in ipairs(status.reasons or {}) do table.insert(lines, string.format(self.i18n:getText("spu_outbound_waiting"), reason)) end if status.warning ~= nil then table.insert(lines, string.format(self.i18n:getText("spu_outbound_warning"), status.warning)) end for index, row in ipairs(self.outboundStatusRows or {}) do row:setText(lines[index] or "") end end -- Oversigt: "SUGAR 78 % af top (kræver 90), lager 41 % · ⚠ …" eller "Sukker 150.0k l — 92 % af top (…)". function SmartPickupFrame:describeOutboundOverview(adEnv, run) local status = ADRunsController.getOutboundStatus(adEnv, run) local parts = {} for _, reason in ipairs(status.reasons or {}) do table.insert(parts, reason) end if #parts == 0 then for _, product in ipairs(status.products or {}) do if product.policy ~= "off" then table.insert(parts, self:describeProduct(adEnv, product)) end end end if status.warning ~= nil then table.insert(parts, string.format(self.i18n:getText("spu_outbound_warning"), status.warning)) end if #parts == 0 then return self.i18n:getText("spu_noSources") end return table.concat(parts, " · ") end -- ---- callbacks ---- function SmartPickupFrame:onClickSource(state, element) self:safe(function(frame) local run, data = frame:getRun(), frame.rowData[element] if run == nil or data == nil then return end ADRunsController.store = ADRuns.toggleSource(ADRunsController.store, run.id, data.wayPointId) Logging.info(SmartPickupFrame.LOG_PREFIX .. "run '%s': sources=%s", tostring(run.name), table.concat(ADRuns.getRun(ADRunsController.store, run.id).sourceWayPointIds, " ")) frame:requestRebuild() end) end function SmartPickupFrame:onClickProduct(state, element) local clicked = self.rowData[element] if clicked ~= nil and clicked.kind == "storageBuilding" then return self:safe(function(frame) frame:onClickStorageBuilding(state) end) end self:safe(function(frame) local run, data = frame:getRun(), frame.rowData[element] if run == nil or data == nil or data.kind ~= "product" then return end local policy = (data.policies or SmartPickupFrame.POLICIES)[state] or "off" ADRunsController.store = ADRuns.setProductPolicy(ADRunsController.store, run.id, data.name, policy) Logging.info(SmartPickupFrame.LOG_PREFIX .. "run '%s': %s=%s", tostring(run.name), tostring(data.name), policy) end) end function SmartPickupFrame:onClickSellAt(state) self:safe(function(frame) local run = frame:getRun() if run == nil then return end ADRunsController.updateRun(run.id, {sellAtPercent = frame.sellAtSteps[state] or ADRuns.DEFAULT_SELL_AT_PERCENT}) end) end function SmartPickupFrame:onClickStoreAbove(state) self:safe(function(frame) local run = frame:getRun() if run == nil then return end ADRunsController.updateRun(run.id, {storeAbovePercent = frame.storeAboveSteps[state] or ADRuns.DEFAULT_STORE_ABOVE_PERCENT}) end) end function SmartPickupFrame:onClickCollectRound(state) self:safe(function(frame) local run = frame:getRun() if run == nil then return end ADRunsController.updateRun(run.id, {collectRound = state == SmartPickupFrame.STATE_ON}) end) end