-- 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 -- 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:onClickProduct(state, element) local clicked = self.rowData[element] if clicked ~= nil and clicked.kind == "guideRow" then return self:onClickGuideRow(state, clicked) end if clicked ~= nil and clicked.kind == "storageBuilding" then return self:safe(function(frame) frame:onClickStorageBuilding(state) end) end if clicked ~= nil and SmartPickupFrame.FIELD_ROW_KINDS ~= nil and SmartPickupFrame.FIELD_ROW_KINDS[clicked.kind] then return self:onClickFieldRow(state, clicked) 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