Files
fs25-adsmartpickup/FS25_ADSmartPickup/adMonthView.lua
T

147 lines
7.2 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- AD Month View
-- Rene regler for fanen Måned: hvilke marker har arbejde i gang, hvor langt er de, hvad kommer bagefter,
-- og lukker vinduet (høst/såning) ved månedsskiftet? GUI'et oversætter nøglerne; spillet kaldes kun via
-- ctx-funktionerne (testbart uden FS).
ADMonthView = {}
ADMonthView.PERIODS = 12
-- Trin der kræver afgrøden eller såvinduet: sorteres før pleje/klargøring
ADMonthView.MAIN_STAGES = {harvesting = true, mowing = true, sowing = true}
-- Trin før såningen i klargøringskæden (lukker såvinduet, bliver marken ikke sået)
ADMonthView.BEFORE_SOWING = {mowing = true, tedding = true, raking = true, collecting = true, harvesting = true,
strawCollecting = true, baling = true, baleCollecting = true, mulching = true,
liming = true, plowing = true, cultivating = true, sowing = true}
function ADMonthView.nextPeriod(period)
if type(period) ~= "number" or period < 1 then return 1 end
return period % ADMonthView.PERIODS + 1
end
-- Visse FS25-sæsondata gemmer overgangene som lister af {startState, endState}; strukturen er ikke
-- dokumenteret, så alle tabeller i periodens data gennemsøges. Ukendt = nej (ingen falsk alarm).
local function findsTransition(data, fromState, toState, depth)
if type(data) ~= "table" or depth > 3 then return false end
if data.startState == fromState and data.endState == toState then return true end
for _, value in pairs(data) do
if type(value) == "table" and findsTransition(value, fromState, toState, depth + 1) then return true end
end
return false
end
-- Visner afgrøden (stadie state) ved overgangen til periode nextPeriod?
function ADMonthView.withersIn(fruit, nextPeriod, state)
if fruit == nil or type(state) ~= "number" or state <= 0 then return false end
local withered = fruit.witheredState
if type(withered) ~= "number" or withered <= 0 then return false end
local periods = fruit.growthDataSeasonal ~= nil and fruit.growthDataSeasonal.periods or nil
local data = periods ~= nil and periods[nextPeriod] or nil
return findsTransition(data, state, withered, 0)
end
-- Såvindue for en afgrøde: "closes" (kan sås nu, ikke næste måned), "open" (også næste måned), "closed".
function ADMonthView.sowWindow(plantableIn, fruitName, period)
if fruitName == nil or fruitName == "" or plantableIn == nil then return "open" end
local now = plantableIn(fruitName, period)
if not now then return "closed" end
return plantableIn(fruitName, ADMonthView.nextPeriod(period)) and "open" or "closes"
end
-- Er marken i gang (vises i tabellen)? Venter/færdig og passiv "klar" (manuel uden Start nu) er ikke.
function ADMonthView.isActive(field)
if field == nil then return false end
if field.stage == "idle" or field.stage == "done" then return false end
if field.stage == "ready" then return ADFieldModel.shouldStart(field) end
return true
end
-- Næste trin i kæden (uden at ændre marken). nil = intet (pleje går tilbage til venter, sidste trin -> færdig).
function ADMonthView.nextStage(field, info)
if field.stage == "ready" then
local stages = ADFieldModel.workStages(ADFieldModel.applyTarget(field.plan, info.kind, info.fruitName), info.kind, info.needs)
return stages[1]
end
if ADFieldModel.isCare(field.stage) then return nil end
local nextField = ADFieldModel.advance(field, info.needs)
if nextField.stage == "done" or nextField.stage == "idle" then return nil end
return nextField.stage
end
-- Vindue for en aktiv mark: "harvestCloses" | "lastSowMonth" | "ok".
-- ctx = {period, plantableIn(name, period), withers(info, nextPeriod)}
function ADMonthView.window(field, info, ctx)
local stage = field.stage
local cropStage = stage == "harvesting" or stage == "mowing" or stage == "ready"
if cropStage and info.kind ~= "bare" and ctx.withers ~= nil and ctx.withers(info, ADMonthView.nextPeriod(ctx.period)) then
return "harvestCloses"
end
local sowsLater = field.plan ~= nil and field.plan.sow and ADMonthView.BEFORE_SOWING[stage]
if sowsLater and ADMonthView.sowWindow(ctx.plantableIn, ADFieldModel.sowFruit(field), ctx.period) == "closes" then
return "lastSowMonth"
end
return "ok"
end
-- Fremdrift 0-1. Høst/slåning: andelen af HELE arealet der stadig står (standingRatio) — readyRatio duer ikke,
-- for slået/høstet afgrøde forsvinder også fra dens nævner (in-game 27/9 F90: halvt slået = 0 %), og
-- Courseplays tal er kun positionen i kurset (starter forfra på 0 ved genstart). Øvrige trin: Courseplay.
function ADMonthView.progress(field, info, cpProgress)
local cropStage = field.stage == "harvesting" or field.stage == "mowing"
if cropStage and type(info.standingRatio) == "number" then
return math.max(0, math.min(1, 1 - info.standingRatio))
end
if type(cpProgress) == "number" then return math.max(0, math.min(1, cpProgress)) end
if cropStage and type(info.readyRatio) == "number" then
return math.max(0, math.min(1, 1 - info.readyRatio))
end
return nil
end
local function priority(row)
if row.window ~= "ok" then return 0 end
if ADMonthView.MAIN_STAGES[row.stage] then return 1 end
return 2
end
-- Hele fanen: {rows = {...}, critical = n, upcoming = {...}}.
-- infos = ADFields.list(), fieldsById = ADFieldJobs.state.fields,
-- ctx = {period, plantableIn(name, period), withers(info, nextPeriod), cpProgress(fieldId) -> 0-1|nil}
function ADMonthView.build(infos, fieldsById, ctx)
local rows, upcoming, critical = {}, {}, 0
for _, info in ipairs(infos or {}) do
local field = fieldsById[info.id]
if field ~= nil and ADMonthView.isActive(field) then
local row = {id = info.id, stage = field.stage, crop = info.cropTitle, sowFruit = nil,
progress = ADMonthView.progress(field, info, ctx.cpProgress ~= nil and ctx.cpProgress(info.id) or nil),
nextStage = ADMonthView.nextStage(field, info), window = ADMonthView.window(field, info, ctx)}
if field.stage == "sowing" or (info.kind == "bare" and ADMonthView.BEFORE_SOWING[field.stage]) then
row.sowFruit = field.plan.sow and ADFieldModel.sowFruit(field) or nil
end
if row.window ~= "ok" then critical = critical + 1 end
table.insert(rows, row)
elseif field ~= nil and info.kind == "bare" and (field.stage == "idle" or field.stage == "done") then
local target = field.plan.targetFruit
if target ~= nil and target ~= "" and ctx.plantableIn ~= nil and ctx.plantableIn(target, ctx.period) then
table.insert(upcoming, {id = info.id, fruit = target,
closes = ADMonthView.sowWindow(ctx.plantableIn, target, ctx.period) == "closes"})
end
end
end
table.sort(rows, function(a, b)
local pa, pb = priority(a), priority(b)
if pa ~= pb then return pa < pb end
return a.id < b.id
end)
table.sort(upcoming, function(a, b)
if a.closes ~= b.closes then return a.closes end
return a.id < b.id
end)
return {rows = rows, critical = critical, upcoming = upcoming}
end
-- "50 %" / "–"
function ADMonthView.percentText(progress)
if progress == nil then return "–" end
return string.format("%d %%", math.floor(progress * 100 + 0.5))
end