fix(kæde): kæden tager aldrig spillerens traktorer, respekterer slukkede produktioner og handler ikke på delvise data

This commit is contained in:
2026-09-30 13:52:15 +02:00
parent 32f2886a55
commit b389fa3564
3 changed files with 107 additions and 28 deletions
+44 -6
View File
@@ -15,7 +15,7 @@ ADChain.LOG_PREFIX = "ADSmartPickup: kæde: "
-- Et afvist forslag vises igen, når manglen for afgrøden har ændret sig mere end dette.
ADChain.DISMISS_CHANGE = 0.25
ADChain.state = {byChain = {}, paused = {}, dismissed = {}}
ADChain.state = {byChain = {}, paused = {}, dismissed = {}, userOff = {}}
ADChain.last = nil
-- run-id -> true: flows kæden oprettede stoppet, fordi der ikke var traktor/vogn (kun i hukommelsen)
ADChain.noVehicle = {}
@@ -38,12 +38,13 @@ end
-- ---- rene hjælpere ----
-- userOff = {[recipeKey] = true}: produktioner spilleren slukkede selv — kæden tænder dem ikke igen.
function ADChain.newState()
return {byChain = {}, paused = {}, dismissed = {}}
return {byChain = {}, paused = {}, dismissed = {}, userOff = {}}
end
function ADChain.stateToRecords(state)
local records = {byChain = sortedKeys(state.byChain), paused = sortedKeys(state.paused), dismissed = {}}
local records = {byChain = sortedKeys(state.byChain), paused = sortedKeys(state.paused), userOff = sortedKeys(state.userOff), dismissed = {}}
local ids = {}
for id in pairs(state.dismissed or {}) do table.insert(ids, id) end
table.sort(ids)
@@ -59,6 +60,7 @@ function ADChain.stateFromRecords(records)
if records == nil then return state end
for _, key in ipairs(records.byChain or {}) do state.byChain[key] = true end
for _, key in ipairs(records.paused or {}) do state.paused[key] = true end
for _, key in ipairs(records.userOff or {}) do state.userOff[key] = true end
for _, entry in ipairs(records.dismissed or {}) do
local id = tonumber(entry.id)
if id ~= nil and entry.fruit ~= nil and entry.fruit ~= "" then
@@ -109,6 +111,25 @@ function ADChain.recipesWithPaused(recipes, paused)
return result
end
-- Spillerens eget valg: en produktion kæden tændte (byChain) som er slukket, selv om kæden stadig har brug for
-- den, er slukket af spilleren (eller tændingen virkede ikke) -> userOff. En nøgle ryddes fra userOff, når kæden
-- ikke længere har brug for den (men ikke på delvise data). -> {userOff = ny tabel, added = {nye nøgler}}
function ADChain.playerOverrides(recipes, needRecipes, userOff, isPartial)
local result, added = {}, {}
for key in pairs(userOff or {}) do
if isPartial or ((needRecipes or {})[key] or 0) > 0 then result[key] = true end
end
for _, recipe in ipairs(recipes or {}) do
local needed = ((needRecipes or {})[recipe.key] or 0) > 0
if recipe.byChain and not recipe.enabled and needed and not result[recipe.key] then
result[recipe.key] = true
table.insert(added, recipe.key)
end
end
table.sort(added)
return {userOff = result, added = added}
end
-- Rødder hvis flows ikke må stoppes: kædens aktuelle rødder + pausede rødder (pause rører intet).
function ADChain.activeRoots(chain, paused)
local result = {}
@@ -242,7 +263,18 @@ end
function ADChain.approve(fieldId)
local action = suggestionFor(fieldId)
if action == nil then return false end
ADFieldJobs.setTarget(fieldId, action.to, "chain")
local ok, err = pcall(function()
-- et auto-skift må aldrig overskrive en afgrøde spilleren har sat siden; et forslag godkender spilleren selv
if action.mode == "auto" then
local plan = ADFieldJobs.getField(fieldId).plan or {}
if plan.targetSource == "user" then error("spilleren har selv valgt afgrøde") end
end
ADFieldJobs.setTarget(fieldId, action.to, "chain")
end)
if not ok then
Logging.warning(ADChain.LOG_PREFIX .. "F%s: forslag kunne ikke godkendes: %s", tostring(fieldId), tostring(err))
return false
end
Logging.info(ADChain.LOG_PREFIX .. "F%s: forslag godkendt: %s -> %s", tostring(fieldId), tostring(action.from), tostring(action.to))
return true
end
@@ -251,7 +283,7 @@ end
function ADChain.dismiss(fieldId)
local action = suggestionFor(fieldId)
if action == nil then return false end
local missingHa = 0
local missingHa = action.hectares or 0
for _, shortage in ipairs(ADChain.last.shortages or {}) do
if shortage.fruit == action.to then missingHa = shortage.missingHa end
end
@@ -286,6 +318,9 @@ function ADChain.save()
for index, key in ipairs(records.paused) do
xmlFile:setString(string.format("%s.paused.root(%d)#key", ADChain.ROOT, index - 1), key)
end
for index, key in ipairs(records.userOff) do
xmlFile:setString(string.format("%s.userOff.recipe(%d)#key", ADChain.ROOT, index - 1), key)
end
for index, entry in ipairs(records.dismissed) do
local key = string.format("%s.dismissed.field(%d)", ADChain.ROOT, index - 1)
xmlFile:setInt(key .. "#id", entry.id)
@@ -304,13 +339,16 @@ function ADChain.load()
if path == nil or not fileExists(path) then return end
local xmlFile = XMLFile.load("ADSmartPickupChain", path)
if xmlFile == nil then return end
local records = {byChain = {}, paused = {}, dismissed = {}}
local records = {byChain = {}, paused = {}, userOff = {}, dismissed = {}}
xmlFile:iterate(ADChain.ROOT .. ".byChain.recipe", function(_, key)
table.insert(records.byChain, xmlFile:getString(key .. "#key"))
end)
xmlFile:iterate(ADChain.ROOT .. ".paused.root", function(_, key)
table.insert(records.paused, xmlFile:getString(key .. "#key"))
end)
xmlFile:iterate(ADChain.ROOT .. ".userOff.recipe", function(_, key)
table.insert(records.userOff, xmlFile:getString(key .. "#key"))
end)
xmlFile:iterate(ADChain.ROOT .. ".dismissed.field", function(_, key)
table.insert(records.dismissed, {id = xmlFile:getInt(key .. "#id"), fruit = xmlFile:getString(key .. "#fruit"),
missingHa = tonumber(xmlFile:getString(key .. "#missingHa"))})