feat(kæde): kæder slås selv til ([Kæde til]/[Fjern]); tomme kædeflows slettes; runsView med traktorer (v1.62.0.0)
This commit is contained in:
@@ -17,7 +17,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 = {}, userOff = {}, finalKeep = {}, soldByChain = {}}
|
||||
ADChain.state = {byChain = {}, paused = {}, dismissed = {}, userOff = {}, finalKeep = {}, soldByChain = {}, optIn = {}}
|
||||
ADChain.last = nil
|
||||
-- {[nøgle] = true}: produktioner (ikke kædens) der var tændt ved sidste tick — til at se spillerens slukninger
|
||||
ADChain.prevEnabled = nil
|
||||
@@ -54,13 +54,15 @@ end
|
||||
-- roots = {[recipeKey] = true} rødderne ved sidste tick (nil = ukendt, fx gem fra en ældre version).
|
||||
function ADChain.newState()
|
||||
-- finalKeep = {[rodnøgle] = true}: slutproduktet beholdes (standard: sælg straks); soldByChain = {["rod|vare"] = true}
|
||||
return {byChain = {}, paused = {}, dismissed = {}, userOff = {}, roots = nil, finalKeep = {}, soldByChain = {}}
|
||||
-- optIn = {[opskriftsnøgle] = true}: produktioner spilleren selv har slået til som kæde (tændte produktioner er
|
||||
-- ellers ikke kæder — FS25 tænder dem som standard)
|
||||
return {byChain = {}, paused = {}, dismissed = {}, userOff = {}, roots = nil, finalKeep = {}, soldByChain = {}, optIn = {}}
|
||||
end
|
||||
|
||||
function ADChain.stateToRecords(state)
|
||||
local records = {byChain = sortedKeys(state.byChain), paused = sortedKeys(state.paused), userOff = sortedKeys(state.userOff), dismissed = {},
|
||||
roots = state.roots ~= nil and sortedKeys(state.roots) or nil,
|
||||
finalKeep = sortedKeys(state.finalKeep or {}), soldByChain = sortedKeys(state.soldByChain or {})}
|
||||
finalKeep = sortedKeys(state.finalKeep or {}), soldByChain = sortedKeys(state.soldByChain or {}), optIn = sortedKeys(state.optIn or {})}
|
||||
local ids = {}
|
||||
for id in pairs(state.dismissed or {}) do table.insert(ids, id) end
|
||||
table.sort(ids)
|
||||
@@ -79,6 +81,7 @@ function ADChain.stateFromRecords(records)
|
||||
for _, key in ipairs(records.userOff or {}) do state.userOff[key] = true end
|
||||
for _, key in ipairs(records.finalKeep or {}) do state.finalKeep[key] = true end
|
||||
for _, key in ipairs(records.soldByChain or {}) do state.soldByChain[key] = true end
|
||||
for _, key in ipairs(records.optIn or {}) do state.optIn[key] = true end
|
||||
if records.roots ~= nil then
|
||||
state.roots = {}
|
||||
for _, key in ipairs(records.roots) do state.roots[key] = true end
|
||||
@@ -123,12 +126,15 @@ end
|
||||
|
||||
-- Modellens kopi af opskrifterne: pausede rødder markeres paused (kører for sig selv, men skaber intet nyt), og
|
||||
-- slukkede userOff-produktioner får 0 cyklusser (de dækker intet behov). Originalerne røres ikke.
|
||||
function ADChain.modelRecipes(recipes, paused, userOff)
|
||||
-- optIn = {[nøgle] = true}: kun de produktioner er rødder (andre tændte markeres notChosen: kører for sig selv som
|
||||
-- kilde, men kæden skaber intet for dem). optIn = nil = alle tændte er rødder (som før).
|
||||
function ADChain.modelRecipes(recipes, paused, userOff, optIn)
|
||||
local result = {}
|
||||
for index, recipe in ipairs(recipes or {}) do
|
||||
local copy = {}
|
||||
for key, value in pairs(recipe) do copy[key] = value end
|
||||
if (paused or {})[recipe.key] then copy.paused = true end
|
||||
if optIn ~= nil and recipe.enabled and not recipe.byChain and not optIn[recipe.key] then copy.notChosen = true end
|
||||
if (userOff or {})[recipe.key] and not recipe.enabled then copy.cyclesPerMonth = 0 end
|
||||
result[index] = copy
|
||||
end
|
||||
@@ -263,7 +269,9 @@ function ADChain.runsView(runs)
|
||||
for _, run in ipairs(runs or {}) do
|
||||
table.insert(list, {id = run.id, name = run.name, kind = run.kind, targetBuildingIds = run.targetBuildingIds,
|
||||
ingredientMode = run.ingredientMode, ingredients = run.ingredients, stopped = run.stopped == true,
|
||||
chain = run.chain, waitPoolGroup = run.waitPoolGroup})
|
||||
chain = run.chain, waitPoolGroup = run.waitPoolGroup,
|
||||
-- traktorerne: uden dem ligner alle kædeflows tomme (sammenlægning/sletning må kun ramme tomme)
|
||||
vehicleIds = run.vehicleIds or {}})
|
||||
end
|
||||
return list
|
||||
end
|
||||
@@ -293,12 +301,12 @@ local function farmId()
|
||||
end
|
||||
|
||||
local function plan(data, state)
|
||||
local recipes = ADChain.modelRecipes(data.recipes, state.paused, state.userOff)
|
||||
local recipes = ADChain.modelRecipes(data.recipes, state.paused, state.userOff, state.optIn)
|
||||
local chain = ADChainModel.build(recipes, data.husbandry, data.crops, data.fieldGoods)
|
||||
-- pausede rødder: det de bruger, er beskyttet mod slukning (modellen regnet som om de ikke var pauset)
|
||||
local protected = {}
|
||||
if next(state.paused) ~= nil then
|
||||
protected = ADChainModel.build(ADChain.modelRecipes(data.recipes, {}, state.userOff), data.husbandry, data.crops, data.fieldGoods).needRecipes
|
||||
protected = ADChainModel.build(ADChain.modelRecipes(data.recipes, {}, state.userOff, state.optIn), data.husbandry, data.crops, data.fieldGoods).needRecipes
|
||||
end
|
||||
local used = ADChain.unionFruits(data.usedFruits, chain.fieldDemand)
|
||||
-- ufuldstændig markliste: udbuddet ville være undervurderet -> ingen mangler, forslag eller markskift endnu
|
||||
@@ -383,7 +391,7 @@ function ADChain.evaluate(adEnv, act)
|
||||
ADChain.last = {chain = result.chain, shortages = result.shortages, actions = result.actions, edges = result.edges,
|
||||
missingFlows = ADChainActions.missingFlows(result.edges, runs), flowStatus = ADChain.flowStatus(result.edges, runs, ADChain.noVehicle),
|
||||
paused = paused, userOff = copySet(state.userOff), finalKeep = copySet(state.finalKeep or {}),
|
||||
sellable = ADChain.sellableRoots(data, result, runs), data = data, fields = data.fields, fieldsIncomplete = data.fieldsIncomplete == true, titles = data.fillTitles, at = ADChain.now, switchCount = ADChain.switchCount,
|
||||
sellable = ADChain.sellableRoots(data, result, runs), candidates = ADChain.candidates(data.recipes, state), data = data, fields = data.fields, fieldsIncomplete = data.fieldsIncomplete == true, titles = data.fillTitles, at = ADChain.now, switchCount = ADChain.switchCount,
|
||||
dependency = dependency}
|
||||
return ADChain.last
|
||||
end
|
||||
@@ -496,6 +504,29 @@ function ADChain.dismiss(fieldId)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Tændte produktioner der ikke er valgt som kæde (og ikke pauset): {{key, name, buildingName}} til fanen Kæder.
|
||||
function ADChain.candidates(recipes, state)
|
||||
local list = {}
|
||||
for _, recipe in ipairs(recipes or {}) do
|
||||
if recipe.enabled and not recipe.byChain and not (state.optIn or {})[recipe.key] and not (state.paused or {})[recipe.key] then
|
||||
table.insert(list, {key = recipe.key, name = recipe.name, buildingName = recipe.buildingName})
|
||||
end
|
||||
end
|
||||
table.sort(list, function(a, b)
|
||||
if tostring(a.buildingName) ~= tostring(b.buildingName) then return tostring(a.buildingName) < tostring(b.buildingName) end
|
||||
return tostring(a.name) < tostring(b.name)
|
||||
end)
|
||||
return list
|
||||
end
|
||||
|
||||
-- Slå en produktion til/fra som kæde (fra = også pausen ophæves, kæden slipper den ved næste tick).
|
||||
function ADChain.setOptIn(recipeKey, on)
|
||||
if recipeKey == nil then return end
|
||||
ADChain.state.optIn[recipeKey] = on and true or nil
|
||||
if not on then ADChain.state.paused[recipeKey] = nil end
|
||||
Logging.info(ADChain.LOG_PREFIX .. "%s %s", tostring(recipeKey), on and "slået til som kæde" or "fjernet fra kæderne")
|
||||
end
|
||||
|
||||
-- Rødder med et slutprodukt der kan sælges straks (gården bruger det ikke selv). -> {[rodnøgle] = true}
|
||||
function ADChain.sellableRoots(data, result, runs)
|
||||
local set = {}
|
||||
@@ -546,6 +577,9 @@ function ADChain.save()
|
||||
for index, key in ipairs(records.soldByChain) do
|
||||
xmlFile:setString(string.format("%s.soldByChain.output(%d)#key", ADChain.ROOT, index - 1), key)
|
||||
end
|
||||
for index, key in ipairs(records.optIn) do
|
||||
xmlFile:setString(string.format("%s.optIn.recipe(%d)#key", ADChain.ROOT, index - 1), key)
|
||||
end
|
||||
if records.roots ~= nil then
|
||||
xmlFile:setBool(ADChain.ROOT .. ".roots#known", true)
|
||||
for index, key in ipairs(records.roots) do
|
||||
@@ -573,7 +607,10 @@ 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 = {}, userOff = {}, dismissed = {}, finalKeep = {}, soldByChain = {}}
|
||||
local records = {byChain = {}, paused = {}, userOff = {}, dismissed = {}, finalKeep = {}, soldByChain = {}, optIn = {}}
|
||||
xmlFile:iterate(ADChain.ROOT .. ".optIn.recipe", function(_, key)
|
||||
table.insert(records.optIn, xmlFile:getString(key .. "#key"))
|
||||
end)
|
||||
xmlFile:iterate(ADChain.ROOT .. ".finalKeep.root", function(_, key)
|
||||
table.insert(records.finalKeep, xmlFile:getString(key .. "#key"))
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user