223 lines
10 KiB
Lua
223 lines
10 KiB
Lua
-- 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 == "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
|
||
|
||
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
|