Files
fs25-adsmartpickup/FS25_ADSmartPickup/gui/SmartPickupFieldGuide.lua
T

237 lines
13 KiB
Lua

-- Smart Pickup — guiden "Opsæt mark" og fanen Markers knapper
-- Henter det spil-afhængige (afgrøder der kan sås, slåafgrøder, halm, maskiner, marksiloer, siloer i nærheden)
-- som `context` til ADFieldGuide og gemmer guidens resultat via ADFieldJobs. Selve trin-skærmen er fælles
-- (gui/SmartPickupGuide.lua). Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
-- lagervalget viser de nærmeste siloer (plus valgte, marksiloer og gæringssiloer)
SmartPickupFrame.FIELD_STORE_ROWS = 8
function SmartPickupFrame:initFieldButtons(i18n)
self.fieldStartButtonInfo = {inputAction = InputAction.MENU_ACTIVATE, text = i18n:getText("spu_field_button_start"), callback = function() self:onClickFieldStartStop() end}
self.fieldSetupButtonInfo = {inputAction = InputAction.MENU_EXTRA_1, text = i18n:getText("spu_guide_field_open"), callback = function() self:onClickFieldSetup() end}
self.fieldFleetButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_guide_fleet_open"), callback = function() self:onClickFieldFleet(true) end}
self.fieldFleetCloseButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_guide_fleet_close"), callback = function() self:onClickFieldFleet(false) end}
self.fieldButtons = {self.backButtonInfo, self.fieldStartButtonInfo, self.fieldSetupButtonInfo, self.fieldFleetButtonInfo}
self.fieldFleetButtons = {self.backButtonInfo, self.fieldFleetCloseButtonInfo}
end
function SmartPickupFrame:getFieldButtons()
return self.fieldView == "fleet" and self.fieldFleetButtons or self.fieldButtons
end
-- ---- context til ADFieldGuide ----
-- {[fieldId] = rigIds} for alle marker
function SmartPickupFrame.rigIdsByField()
local byField = {}
for fieldId, field in pairs(ADFieldJobs.state.fields) do byField[fieldId] = field.plan ~= nil and field.plan.rigIds or {} end
return byField
end
local function fruitTypes()
return g_fruitTypeManager ~= nil and g_fruitTypeManager.fruitTypes or {}
end
-- Afgrøder der kan sås, slåafgrøder (navne) og afgrøder med halm (skår efter mejetærskeren).
function SmartPickupFrame:fruitContext()
local sowable, straw, mowable = {}, {}, {}
for _, fruit in ipairs(fruitTypes()) do
if fruit.allowsSeeding ~= false and fruit.fillType ~= nil and fruit.name ~= nil then
table.insert(sowable, {name = fruit.name, title = tostring(fruit.fillType.title or fruit.name)})
end
local ok, hasStraw = pcall(function() return fruit.hasWindrow == true or fruit.windrowName ~= nil end)
if ok and hasStraw and fruit.name ~= nil then straw[fruit.name] = true end
end
if ADFields ~= nil and g_fruitTypeManager ~= nil then
for index in pairs(ADFields.getMowable()) do
local fruit = g_fruitTypeManager:getFruitTypeByIndex(index)
if fruit ~= nil and fruit.name ~= nil then mowable[fruit.name] = true end
end
end
return sowable, mowable, straw
end
-- Markens vare ud fra kladdens plan (ensilage -> skår, hø -> tørskår, høst -> afgrøden); nil på bar mark.
local function fieldFillType(info, plan)
if info.kind == "mowable" then
return ADFieldModel.product(plan, "mowable") == "hay" and info.hay or info.windrow
end
if info.kind == "harvest" then return info.harvestFillType end
return nil
end
-- Siloer der tager markens vare: marksilo først, gæringssiloer, så de nærmeste (samme regel som før).
function SmartPickupFrame:fieldStoreContext(adEnv, info, plan, chosenIds)
local fillType = fieldFillType(info, plan)
local farmId = g_currentMission:getFarmId()
local fieldSilos, silosById = {}, {}
for _, building in ipairs(ADFields.fieldSilos(adEnv, farmId, info)) do
local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, "unload") or {}
table.insert(fieldSilos, {id = building.id, name = tostring(building.name),
text = markers[1] ~= nil and tostring(markers[1].name) or tostring(building.name)})
silosById[building.id] = true
end
if fillType == nil then return nil, 0, fieldSilos end
local chosen = {}
for _, id in ipairs(chosenIds or {}) do chosen[id] = true end
local fermenterIds = {}
if info.kind == "mowable" and ADFieldModel.product(plan, "mowable") == "silage" then
for _, building in ipairs(ADFieldJobs.getFermenters(adEnv, farmId, fillType, info.x, info.z)) do fermenterIds[building.id] = true end
end
local entries = {}
for _, building in ipairs(ADBuildings.list(adEnv, farmId)) do
local isSilo = building.kind == "silo" and ADRunsController.canStoreAt(adEnv, building, {{fillType = fillType, isPallet = false}})
if chosen[building.id] or isSilo or fermenterIds[building.id] then
local distance = nil
local node = building.placeable ~= nil and building.placeable.rootNode or nil
if node ~= nil and info.x ~= nil then
local bx, _, bz = getWorldTranslation(node)
distance = math.sqrt((bx - info.x) ^ 2 + (bz - info.z) ^ 2)
end
table.insert(entries, {id = building.id, building = building, distance = distance, chosen = chosen[building.id] == true,
fieldSilo = silosById[building.id] == true, fermenter = fermenterIds[building.id] == true})
end
end
local shown, hidden = ADFieldView.storeRows(entries, SmartPickupFrame.FIELD_STORE_ROWS)
local stores = {}
for _, entry in ipairs(shown) do
local building = entry.building
local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, "unload") or {}
-- det der skelner rækkerne først (rækken afkorter bagfra): markør, afstand, art — så bygningens navn
local label = (markers[1] ~= nil and tostring(markers[1].name) or tostring(building.name)) .. ", " .. ADFieldView.distanceText(entry.distance)
if entry.fieldSilo then label = label .. " (" .. self.i18n:getText("spu_field_fieldSilo") .. ")" end
if entry.fermenter then label = label .. " (" .. self.i18n:getText("spu_field_fermenter") .. ")" end
if markers[1] ~= nil then label = label .. " — " .. tostring(building.name) end
table.insert(stores, {id = building.id, text = label})
end
return stores, hidden, fieldSilos
end
-- Markerne til trin 1 ("F22 — Hvede — Venter").
function SmartPickupFrame:fieldPickList()
local fields = {}
for _, row in ipairs(ADFieldView.rows(ADFields.list(), ADFieldJobs.state.fields)) do
local crop = ADFieldView.cropText(row.info, function(key) return self.i18n:getText(key) end)
table.insert(fields, {id = row.info.id, text = string.format("F%d — %s — %s", row.info.id, crop, self:fieldStatusText(row.field, row.info, true))})
end
return fields
end
-- context for en mark (info) med kladdens plan; info nil = trin 1 uden valgt mark.
function SmartPickupFrame:fieldGuideContext(adEnv, info, plan, chosenStoreIds)
local sowable, mowable, straw = self:fruitContext()
local context = {info = info or {}, sowable = sowable, mowable = mowable, straw = straw,
rigIdsByField = SmartPickupFrame.rigIdsByField(), fieldSilos = {}, storeHidden = 0, fields = self:fieldPickList(), rigs = {}}
for _, rig in ipairs(ADFieldJobs.getRigs(adEnv)) do
table.insert(context.rigs, {id = rig.id, role = rig.role, text = string.format("%s — %s", tostring(rig.label), self:roleText(rig.role))})
end
if info ~= nil then
context.stores, context.storeHidden, context.fieldSilos = self:fieldStoreContext(adEnv, info, plan or {}, chosenStoreIds)
end
return context
end
-- ---- hooks til den fælles guide-skærm ----
local function chosenStoreIds(guide)
local ids = {}
for _, id in ipairs(guide.draft.storeIds or {}) do table.insert(ids, id) end
for _, id in ipairs(guide.draft.plan ~= nil and guide.draft.plan.storeBuildingIds or {}) do table.insert(ids, id) end
return ids
end
SmartPickupFrame.GUIDE_HOOKS = SmartPickupFrame.GUIDE_HOOKS or {}
SmartPickupFrame.GUIDE_HOOKS.field = {
model = ADFieldGuide,
tab = SmartPickupFrame.TAB_FIELDS,
cannotAdvanceKey = "spu_guide_pickField",
heading = function(frame, guide)
if guide.draft.fieldId == nil then return frame.i18n:getText("spu_guide_field_titleNone") end
return string.format(frame.i18n:getText("spu_guide_field_title"), guide.draft.fieldId)
end,
context = function(frame, adEnv, guide)
local fieldId = guide.draft.fieldId
if fieldId == nil then return frame:fieldGuideContext(adEnv, nil) end
local info = ADFields.getInfo(fieldId)
-- marken er solgt/bygget over mens guiden var åben
if info == nil or info.cultivable == false then return nil end
return frame:fieldGuideContext(adEnv, info, guide.draft.plan, chosenStoreIds(guide))
end,
choose = function(frame, id, value)
if id ~= "field" then return false end
local info = ADFields.getInfo(value)
if info == nil then return true end
local field = ADFieldJobs.getField(value)
frame.selectedFieldId = value
frame.statusOverride = nil
frame.guide = ADFieldGuide.pickField(frame.guide, field, frame:fieldGuideContext(frame.getAdEnv(), info, field.plan, field.plan.storeBuildingIds))
return true
end,
canAdvance = function(guide) return guide.draft.fieldId ~= nil end,
startKey = function() return "spu_guide_runAuto" end,
-- mål-afgrøde kører altid automatisk: ingen "Gem uden at starte"
showSaveOnly = function(guide) return (guide.draft.plan.targetFruit or "") == "" end,
save = function(frame, guide, start) frame:saveFieldGuide(guide, start) end,
afterRows = function(frame, adEnv, guide)
if guide.step ~= "summary" or guide.draft.fieldId == nil then return end
local info = guide.context.info
if info ~= nil and info.markerId == nil then
frame:addTextRow(" " .. string.format(frame.i18n:getText("spu_guide_noMarker"), guide.draft.fieldId))
end
end,
}
-- Gem: mål-afgrøde (hvis ændret), planen, og faste maskiner (fjernes fra andre marker).
function SmartPickupFrame:saveFieldGuide(guide, start)
local result = ADFieldGuide.result(guide, start)
if result.fieldId == nil then return end
if result.targetChanged then ADFieldJobs.setTarget(result.fieldId, result.targetFruit) end
ADFieldJobs.setPlan(result.fieldId, result.plan)
local byField = SmartPickupFrame.rigIdsByField()
for fieldId, ids in pairs(ADFieldGuide.applyRigs(byField, result.fieldId, result.rigIds)) do
if table.concat(byField[fieldId] or {}, " ") ~= table.concat(ids, " ") then
ADFieldJobs.setPlan(fieldId, {rigIds = ids})
end
end
ADFieldJobs.log(result.fieldId, "guide gemt: mode=%s mål=%s faste=%s lager=%s", tostring(result.plan.mode), result.targetFruit ~= "" and result.targetFruit or "-",
table.concat(result.rigIds, " "), table.concat(result.plan.storeBuildingIds or {}, " "))
self.selectedFieldId = result.fieldId
self.statusOverride = string.format(self.i18n:getText("spu_guide_saved"), result.fieldId)
self.statusOverrideTicks = SmartPickupFrame.STATUS_OVERRIDE_TICKS
end
-- ---- knapper og [Ret] ----
-- [Opsæt mark]: den valgte mark med de nuværende valg, ellers trin 1 (vælg mark).
function SmartPickupFrame:onClickFieldSetup()
self:safe(function(frame)
local adEnv = frame.getAdEnv()
if adEnv == nil then return end
local info = frame.selectedFieldId ~= nil and ADFields.getInfo(frame.selectedFieldId) or nil
frame.fieldView = nil
if info == nil then
frame:openGuide("field", ADFieldGuide.openPicker(frame:fieldGuideContext(adEnv, nil)))
return
end
local field = ADFieldJobs.getField(info.id)
frame:openGuide("field", ADFieldGuide.open(field, frame:fieldGuideContext(adEnv, info, field.plan, field.plan.storeBuildingIds)))
end)
end
-- [Ret] på en resumé-linje i fanens oversigt: kun det ene trin; [Gem] gemmer og går tilbage.
function SmartPickupFrame:openFieldStep(fieldId, step)
local adEnv = self.getAdEnv()
local info = ADFields.getInfo(fieldId)
if adEnv == nil or info == nil then return end
local field = ADFieldJobs.getField(fieldId)
local context = self:fieldGuideContext(adEnv, info, field.plan, field.plan.storeBuildingIds)
self:openGuide("field", ADFieldGuide.open(field, context, {step = step, single = true, returnTo = "close"}))
end
function SmartPickupFrame:onClickFieldFleet(show)
self:safe(function(frame)
frame.fieldView = show and "fleet" or nil
frame:requestRebuild()
end)
end