459 lines
20 KiB
Lua
459 lines
20 KiB
Lua
-- AD Flow Guide
|
|
-- "Opsæt flow": flowguidens trin oven på ADGuide (ren Lua, ingen spil-API) — samme trin-skærm og knapper
|
|
-- som markguiden. Kladden er en kopi af flowets felter, så intet ændres før [Gem]/[Start flow]. Det
|
|
-- spil-afhængige kommer i `context` (GUI'et henter det ud fra kladden, se previewRun):
|
|
-- {buildings = {{id, name, label, hasMarker, text}} -- kandidater til Fra (udkørsel) / Til (forsyning)
|
|
-- fillTypes = {{name, title}} -- varer målet tager (forsyning, Vælg selv)
|
|
-- products = {{name, title}} -- varer kilderne har (udkørsel)
|
|
-- storeBuildings = {{id, name, text}} -- lagre der kan tage flowets lagervarer
|
|
-- waitPools = {{group, count}}
|
|
-- vehicles = {{id, label, text, otherRunId, otherRunName, blocked}}} -- label = kort navn (resumé)
|
|
-- Gem: ADRunsController.createRun/updateRun + assignVehicle/unassignVehicle (GUI'et).
|
|
|
|
ADFlowGuide = {}
|
|
|
|
ADFlowGuide.ORDER = {"name", "direction", "buildings", "goods", "store", "rules", "wait", "tractors", "summary"}
|
|
ADFlowGuide.POLICIES = {"off", "store", "sell", "sellElseStore"}
|
|
ADFlowGuide.MAX_NAMED_TRACTORS = 3
|
|
ADFlowGuide.MAX_NAMED_GOODS = 3
|
|
|
|
local function L(key, args) return {key = key, args = args} end
|
|
local function T(text) return {text = text} end
|
|
|
|
local function isOut(guide) return guide.draft.kind == "outbound" end
|
|
|
|
local function hasStorePolicy(draft)
|
|
for _, product in ipairs(draft.products or {}) do
|
|
if product.policy == "store" or product.policy == "sellElseStore" then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local VISIBLE = {
|
|
name = function(guide) return guide.draft.isNew == true end,
|
|
store = function(guide) return isOut(guide) and hasStorePolicy(guide.draft) end,
|
|
}
|
|
|
|
function ADFlowGuide.isVisible(step, guide)
|
|
local rule = VISIBLE[step]
|
|
if rule ~= nil then return rule(guide) == true end
|
|
for _, id in ipairs(ADFlowGuide.ORDER) do
|
|
if id == step then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
ADFlowGuide.DEF = {order = ADFlowGuide.ORDER, isVisible = ADFlowGuide.isVisible}
|
|
|
|
-- Overskrift pr. trin; "Fra"/"Til" følger retningen.
|
|
function ADFlowGuide.stepKey(step, guide)
|
|
if step == "buildings" then
|
|
return (guide ~= nil and isOut(guide)) and "spu_guide_flow_step_from" or "spu_guide_flow_step_to"
|
|
end
|
|
return "spu_guide_flow_step_" .. tostring(step)
|
|
end
|
|
|
|
local KIND_HINTS = {buildings = true, goods = true, rules = true}
|
|
function ADFlowGuide.hintKey(step, guide)
|
|
if KIND_HINTS[step] then
|
|
return "spu_guide_flow_hint_" .. step .. ((guide ~= nil and isOut(guide)) and "_out" or "_in")
|
|
end
|
|
return "spu_guide_flow_hint_" .. tostring(step)
|
|
end
|
|
|
|
-- ---- kladde ----
|
|
|
|
local RUN_FIELDS = {
|
|
"id", "name", "kind", "sourceBuildingIds", "targetBuildingIds", "storeBuildingIds", "products",
|
|
"ingredientMode", "ingredients", "sellAtPercent", "storeAbovePercent", "sellAbovePercent", "collectRound", "loops",
|
|
"returnBelowPercent", "waitPoolGroup", "vehicleIds",
|
|
}
|
|
|
|
local function draftFrom(run, isNew)
|
|
local draft = {}
|
|
for _, key in ipairs(RUN_FIELDS) do draft[key] = ADGuide.deepCopy(run[key]) end
|
|
for _, key in ipairs({"sourceBuildingIds", "targetBuildingIds", "storeBuildingIds", "products", "ingredients", "vehicleIds"}) do
|
|
draft[key] = draft[key] or {}
|
|
end
|
|
draft.kind = draft.kind == "outbound" and "outbound" or "supply"
|
|
draft.ingredientMode = draft.ingredientMode == "manual" and "manual" or "auto"
|
|
draft.sellAtPercent = draft.sellAtPercent or ADRuns.DEFAULT_SELL_AT_PERCENT
|
|
draft.storeAbovePercent = draft.storeAbovePercent or ADRuns.DEFAULT_STORE_ABOVE_PERCENT
|
|
draft.sellAbovePercent = draft.sellAbovePercent or ADRuns.DEFAULT_SELL_ABOVE_PERCENT
|
|
draft.returnBelowPercent = draft.returnBelowPercent or ADRuns.DEFAULT_RETURN_BELOW_PERCENT
|
|
draft.loops = draft.loops or 0
|
|
draft.waitPoolGroup = draft.waitPoolGroup or ""
|
|
draft.collectRound = draft.collectRound == true
|
|
draft.isNew = isNew == true
|
|
draft.showAllBuildings = false
|
|
draft.storeAuto = #draft.storeBuildingIds == 0
|
|
return draft
|
|
end
|
|
|
|
function ADFlowGuide.open(run, context, options)
|
|
return ADGuide.new(ADFlowGuide.DEF, draftFrom(run, false), context, options)
|
|
end
|
|
|
|
-- Nyt flow: intet oprettes før [Gem]; kladden har standardværdierne fra ADRuns.createRun.
|
|
function ADFlowGuide.openNew(name, context)
|
|
local _, run = ADRuns.createRun(ADRuns.newStore(), name, "supply")
|
|
local draft = draftFrom(run, true)
|
|
draft.id = nil
|
|
return ADGuide.new(ADFlowGuide.DEF, draft, context)
|
|
end
|
|
|
|
-- Run-formet tabel til controllerens opslag (varer, vogne) før noget er gemt: markører fra de valgte
|
|
-- bygninger. markerIds(buildingId, role) -> {wayPointId, ...}.
|
|
function ADFlowGuide.previewRun(draft, markerIds)
|
|
local run = ADGuide.deepCopy(draft)
|
|
local function resolve(ids, role)
|
|
local result, seen = {}, {}
|
|
for _, buildingId in ipairs(ids or {}) do
|
|
for _, wayPointId in ipairs(markerIds(buildingId, role) or {}) do
|
|
if not seen[wayPointId] then
|
|
seen[wayPointId] = true
|
|
table.insert(result, wayPointId)
|
|
end
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
run.sourceWayPointIds = resolve(draft.sourceBuildingIds, "load")
|
|
run.targetWayPointIds = resolve(draft.targetBuildingIds, "unload")
|
|
run.targetWayPointId = run.targetWayPointIds[1]
|
|
return run
|
|
end
|
|
|
|
-- ---- valg ----
|
|
|
|
local SET_VALUES = {
|
|
kind = true, ingredientMode = true, sellAtPercent = true, storeAbovePercent = true, sellAbovePercent = true, loops = true,
|
|
returnBelowPercent = true, waitPoolGroup = true,
|
|
}
|
|
local BOOL_VALUES = {showAllBuildings = true, storeAuto = true, collectRound = true}
|
|
local LIST_VALUES = {ingredients = true, storeBuildingIds = true, vehicleIds = true}
|
|
|
|
local function setPolicy(products, name, policy)
|
|
local result = {}
|
|
for _, product in ipairs(products or {}) do
|
|
if product.fillType ~= name then table.insert(result, {fillType = product.fillType, policy = product.policy}) end
|
|
end
|
|
if policy ~= "off" then table.insert(result, {fillType = name, policy = policy}) end
|
|
return result
|
|
end
|
|
|
|
function ADFlowGuide.choose(guide, id, value)
|
|
local draft = ADGuide.deepCopy(guide.draft)
|
|
if SET_VALUES[id] then
|
|
draft[id] = value
|
|
elseif BOOL_VALUES[id] then
|
|
draft[id] = value == true
|
|
elseif LIST_VALUES[id] then
|
|
draft[id] = ADGuide.toggleItem(draft[id], value.item, value.on)
|
|
elseif id == "buildings" then
|
|
local key = draft.kind == "outbound" and "sourceBuildingIds" or "targetBuildingIds"
|
|
draft[key] = ADGuide.toggleItem(draft[key], value.item, value.on)
|
|
elseif id == "policy" then
|
|
draft.products = setPolicy(draft.products, value.item, value.value)
|
|
elseif id == "name" then
|
|
if type(value) ~= "string" or not value:match("%S") then return guide end
|
|
draft.name = value
|
|
else
|
|
return guide
|
|
end
|
|
return ADGuide.withDraft(guide, draft)
|
|
end
|
|
|
|
-- ---- rækker ----
|
|
|
|
local function choice(id, title, options, value, item)
|
|
return {type = "choice", id = id, title = title, options = options, value = value, item = item}
|
|
end
|
|
|
|
local function toggle(id, title, value)
|
|
return {type = "toggle", id = id, title = title, off = L("ui_no"), on = L("ui_yes"), value = value == true}
|
|
end
|
|
|
|
local function check(id, item, text, value)
|
|
return {type = "check", id = id, item = item, title = T(text), value = value == true}
|
|
end
|
|
|
|
local function text(key, args) return {type = "text", label = L(key, args)} end
|
|
|
|
local function percentOptions(from, to, step)
|
|
local options = {}
|
|
for percent = from, to, step do table.insert(options, {label = T(string.format("%d %%", percent)), value = percent}) end
|
|
return options
|
|
end
|
|
|
|
-- "Sælg altid over": Fra, 50-100 %
|
|
local function sellAboveOptions()
|
|
local options = {{label = L("spu_sellAbove_off"), value = 0}}
|
|
for _, option in ipairs(percentOptions(50, ADRuns.MAX_SELL_ABOVE_PERCENT, 5)) do table.insert(options, option) end
|
|
return options
|
|
end
|
|
|
|
local function chosenSet(list)
|
|
local set = {}
|
|
for _, value in ipairs(list or {}) do set[value] = true end
|
|
return set
|
|
end
|
|
|
|
local function buildingIds(draft)
|
|
return draft.kind == "outbound" and draft.sourceBuildingIds or draft.targetBuildingIds
|
|
end
|
|
|
|
local function rowsName(guide)
|
|
return {
|
|
{type = "text", label = T(guide.draft.name or "")},
|
|
{type = "link", id = "rename", value = true, label = L("spu_guide_flow_rename")},
|
|
}
|
|
end
|
|
|
|
local function rowsDirection(guide)
|
|
return {choice("kind", L("spu_direction"), {
|
|
{label = L("spu_direction_in"), value = "supply"}, {label = L("spu_direction_out"), value = "outbound"}}, guide.draft.kind)}
|
|
end
|
|
|
|
-- Bygninger i fast rækkefølge (navn, markør); uden markør kun med "Vis alle" (eller når valgt).
|
|
local function rowsBuildings(guide)
|
|
local draft, rows = guide.draft, {}
|
|
local chosen = chosenSet(buildingIds(draft))
|
|
local candidates = guide.context.buildings or {}
|
|
local shown = ADFlowView.buildingRows(candidates, chosen, draft.showAllBuildings)
|
|
local hidden = ADFlowView.hiddenCount(candidates, shown)
|
|
if hidden > 0 or draft.showAllBuildings then
|
|
table.insert(rows, toggle("showAllBuildings", L("spu_showAllBuildings", {hidden}), draft.showAllBuildings))
|
|
end
|
|
for _, building in ipairs(shown) do
|
|
table.insert(rows, check("buildings", building.id, building.text or building.name, chosen[building.id]))
|
|
end
|
|
if #shown == 0 then table.insert(rows, text("spu_noBuildings")) end
|
|
return rows
|
|
end
|
|
|
|
local function rowsGoods(guide)
|
|
local draft, context, rows = guide.draft, guide.context, {}
|
|
if isOut(guide) then
|
|
local products = context.products or {}
|
|
if #products == 0 then return {text("spu_guide_flow_noProducts")} end
|
|
local options = {}
|
|
for _, policy in ipairs(ADFlowGuide.POLICIES) do table.insert(options, {label = L("spu_policy_" .. policy), value = policy}) end
|
|
for _, product in ipairs(products) do
|
|
table.insert(rows, choice("policy", T(product.text or product.title), options, ADRuns.getProductPolicy(draft, product.name), product.name))
|
|
end
|
|
return rows
|
|
end
|
|
table.insert(rows, choice("ingredientMode", L("spu_guide_flow_goods"), {
|
|
{label = L("spu_guide_flow_goodsAutoChoice"), value = "auto"}, {label = L("spu_guide_manual"), value = "manual"}}, draft.ingredientMode))
|
|
if draft.ingredientMode ~= "manual" then
|
|
table.insert(rows, text("spu_guide_flow_goodsAutoText"))
|
|
return rows
|
|
end
|
|
local chosen = chosenSet(draft.ingredients)
|
|
for _, fillType in ipairs(context.fillTypes or {}) do
|
|
table.insert(rows, check("ingredients", fillType.name, " " .. tostring(fillType.title), chosen[fillType.name]))
|
|
end
|
|
if #(context.fillTypes or {}) == 0 then table.insert(rows, text("spu_guide_flow_noGoodsTo")) end
|
|
return rows
|
|
end
|
|
|
|
local function rowsStore(guide)
|
|
local draft, rows = guide.draft, {}
|
|
table.insert(rows, choice("storeAuto", L("spu_guide_store"), {
|
|
{label = L("spu_guide_flow_storeAutoChoice"), value = true}, {label = L("spu_guide_manual"), value = false}}, draft.storeAuto))
|
|
if draft.storeAuto then
|
|
table.insert(rows, text("spu_guide_flow_storeAutoText"))
|
|
return rows
|
|
end
|
|
local chosen = chosenSet(draft.storeBuildingIds)
|
|
for _, building in ipairs(guide.context.storeBuildings or {}) do
|
|
table.insert(rows, check("storeBuildingIds", building.id, building.text, chosen[building.id]))
|
|
end
|
|
if #(guide.context.storeBuildings or {}) == 0 then table.insert(rows, text("spu_noBuildings")) end
|
|
return rows
|
|
end
|
|
|
|
local function rowsRules(guide)
|
|
local draft = guide.draft
|
|
if isOut(guide) then
|
|
return {
|
|
choice("sellAtPercent", L("spu_sellAt"), percentOptions(ADRuns.MIN_SELL_AT_PERCENT, ADRuns.MAX_SELL_AT_PERCENT, 5), draft.sellAtPercent),
|
|
choice("storeAbovePercent", L("spu_storeAbove"), percentOptions(ADRuns.MIN_STORE_ABOVE_PERCENT, ADRuns.MAX_STORE_ABOVE_PERCENT, 5), draft.storeAbovePercent),
|
|
choice("sellAbovePercent", L("spu_sellAbove"), sellAboveOptions(), draft.sellAbovePercent),
|
|
toggle("collectRound", L("spu_collectRound"), draft.collectRound),
|
|
}
|
|
end
|
|
local loops = {{label = L("spu_loops_infinite"), value = 0}}
|
|
for count = 1, ADRuns.MAX_LOOPS do table.insert(loops, {label = T(tostring(count)), value = count}) end
|
|
return {
|
|
choice("loops", L("spu_loops"), loops, draft.loops),
|
|
choice("returnBelowPercent", L("spu_returnBelow"), percentOptions(ADRuns.MIN_RETURN_BELOW_PERCENT, ADRuns.MAX_RETURN_BELOW_PERCENT, 10), draft.returnBelowPercent),
|
|
}
|
|
end
|
|
|
|
local function rowsWait(guide)
|
|
local options = {{label = L("spu_waitPool_all"), value = ""}}
|
|
for _, pool in ipairs(guide.context.waitPools or {}) do
|
|
table.insert(options, {label = T(string.format("%s (%d)", tostring(pool.group), pool.count or 0)), value = pool.group})
|
|
end
|
|
return {choice("waitPoolGroup", L("spu_waitPool"), options, guide.draft.waitPoolGroup or "")}
|
|
end
|
|
|
|
-- Traktorer: flowets egne først, så de ledige. Traktorer i andre flows og blokerede (vognen passer ikke)
|
|
-- skjules med en linje hver.
|
|
local function rowsTractors(guide)
|
|
local draft, rows = guide.draft, {}
|
|
local inRun = chosenSet(draft.vehicleIds)
|
|
local entries = {}
|
|
local other, blocked = 0, 0
|
|
for _, vehicle in ipairs(guide.context.vehicles or {}) do
|
|
local state = "free"
|
|
if inRun[vehicle.id] then
|
|
state = "in"
|
|
elseif vehicle.otherRunId ~= nil and vehicle.otherRunId ~= draft.id then
|
|
state = "other"
|
|
other = other + 1
|
|
elseif vehicle.blocked then
|
|
state = "blocked"
|
|
blocked = blocked + 1
|
|
end
|
|
table.insert(entries, {id = vehicle.id, label = tostring(vehicle.text), state = state})
|
|
end
|
|
for _, entry in ipairs(ADFlowView.vehicleRows(entries, false)) do
|
|
table.insert(rows, check("vehicleIds", entry.id, entry.label, entry.state == "in"))
|
|
end
|
|
if #rows == 0 then table.insert(rows, text("spu_guide_flow_noTractors")) end
|
|
if other > 0 then table.insert(rows, text("spu_guide_flow_otherFlows", {other})) end
|
|
if blocked > 0 then table.insert(rows, text("spu_guide_flow_blocked", {blocked})) end
|
|
return rows
|
|
end
|
|
|
|
local function rowsSummary(guide)
|
|
local rows = {}
|
|
for _, line in ipairs(ADFlowGuide.summary(guide)) do
|
|
table.insert(rows, {type = "link", id = "jump", value = line.step, line = line})
|
|
end
|
|
return rows
|
|
end
|
|
|
|
local ROWS = {
|
|
name = rowsName, direction = rowsDirection, buildings = rowsBuildings, goods = rowsGoods, store = rowsStore,
|
|
rules = rowsRules, wait = rowsWait, tractors = rowsTractors, summary = rowsSummary,
|
|
}
|
|
|
|
function ADFlowGuide.rows(guide)
|
|
local builder = ROWS[guide.step]
|
|
return builder ~= nil and builder(guide) or {}
|
|
end
|
|
|
|
-- ---- resumé ----
|
|
|
|
-- Korte navne til resuméet (field, ellers navn, ellers rækkens tekst).
|
|
local function namesFor(ids, entries, field)
|
|
local byId = {}
|
|
for _, entry in ipairs(entries or {}) do byId[entry.id or entry.name] = entry[field] or entry.name or entry.text end
|
|
local names = {}
|
|
for _, id in ipairs(ids or {}) do table.insert(names, tostring(byId[id] or id)) end
|
|
return names
|
|
end
|
|
|
|
local SUMMARY = {
|
|
name = function(guide) return {T(guide.draft.name or "")} end,
|
|
direction = function(guide) return {L(isOut(guide) and "spu_direction_out" or "spu_direction_in")} end,
|
|
buildings = function(guide)
|
|
local names = namesFor(buildingIds(guide.draft), guide.context.buildings, "name")
|
|
if #names == 0 then return {L("spu_guide_flow_none")} end
|
|
return {T(ADFlowView.joinCounted(names, " + ", ""))}
|
|
end,
|
|
goods = function(guide)
|
|
local draft = guide.draft
|
|
if isOut(guide) then
|
|
local parts = {}
|
|
local titles = {}
|
|
for _, product in ipairs(guide.context.products or {}) do titles[product.name] = product.title end
|
|
for _, product in ipairs(draft.products or {}) do
|
|
table.insert(parts, {key = "spu_policy_" .. product.policy, prefix = tostring(titles[product.fillType] or product.fillType) .. ": "})
|
|
end
|
|
if #parts == 0 then return {L("spu_guide_flow_none")} end
|
|
return parts
|
|
end
|
|
if draft.ingredientMode ~= "manual" then return {L("spu_guide_flow_goodsAuto")} end
|
|
if #draft.ingredients == 0 then return {L("spu_guide_flow_none")} end
|
|
if #draft.ingredients > ADFlowGuide.MAX_NAMED_GOODS then return {L("spu_guide_flow_sumGoods", {#draft.ingredients})} end
|
|
local byName = {}
|
|
for _, fillType in ipairs(guide.context.fillTypes or {}) do byName[fillType.name] = fillType.title end
|
|
local names = {}
|
|
for _, name in ipairs(draft.ingredients) do table.insert(names, tostring(byName[name] or name)) end
|
|
return {T(table.concat(names, " + "))}
|
|
end,
|
|
store = function(guide)
|
|
local draft = guide.draft
|
|
if draft.storeAuto or #draft.storeBuildingIds == 0 then return {L("spu_guide_sum_auto")} end
|
|
if #draft.storeBuildingIds > 2 then return {L("spu_guide_sum_stores", {#draft.storeBuildingIds})} end
|
|
return {T(table.concat(namesFor(draft.storeBuildingIds, guide.context.storeBuildings, "name"), " + "))}
|
|
end,
|
|
rules = function(guide)
|
|
local draft = guide.draft
|
|
if isOut(guide) then
|
|
local parts = {L("spu_guide_flow_sumSellAt", {draft.sellAtPercent}), L("spu_guide_flow_sumStoreAbove", {draft.storeAbovePercent})}
|
|
if (draft.sellAbovePercent or 0) > 0 then table.insert(parts, L("spu_guide_flow_sumSellAbove", {draft.sellAbovePercent})) end
|
|
if draft.collectRound then table.insert(parts, L("spu_guide_flow_sumRound")) end
|
|
return parts
|
|
end
|
|
local loops = (draft.loops or 0) > 0 and L("spu_guide_flow_sumLoops", {draft.loops}) or L("spu_guide_flow_sumLoopsInf")
|
|
return {loops, L("spu_guide_flow_sumReturn", {draft.returnBelowPercent})}
|
|
end,
|
|
wait = function(guide)
|
|
local group = guide.draft.waitPoolGroup or ""
|
|
return {group == "" and L("spu_waitPool_all") or T(group)}
|
|
end,
|
|
tractors = function(guide)
|
|
local ids = guide.draft.vehicleIds
|
|
if #ids == 0 then return {L("spu_guide_flow_sumNoTractors")} end
|
|
if #ids > ADFlowGuide.MAX_NAMED_TRACTORS then return {L("spu_guide_flow_sumTractors", {#ids})} end
|
|
return {T(table.concat(namesFor(ids, guide.context.vehicles, "label"), ", "))}
|
|
end,
|
|
}
|
|
|
|
-- Resumé-linjer {step, title, parts}: Navn (altid) + de synlige trin.
|
|
function ADFlowGuide.summary(guide)
|
|
local lines = {}
|
|
for _, step in ipairs(ADFlowGuide.ORDER) do
|
|
local build = SUMMARY[step]
|
|
if build ~= nil and (step == "name" or ADFlowGuide.isVisible(step, guide)) then
|
|
table.insert(lines, {step = step, title = L(ADFlowGuide.stepKey(step, guide)), parts = build(guide)})
|
|
end
|
|
end
|
|
return lines
|
|
end
|
|
|
|
-- ---- gem ----
|
|
|
|
function ADFlowGuide.result(guide)
|
|
local draft = guide.draft
|
|
local storeIds = ADGuide.deepCopy(draft.storeBuildingIds)
|
|
if ADFlowGuide.isVisible("store", guide) and draft.storeAuto then storeIds = {} end
|
|
local changes = {
|
|
kind = draft.kind, sourceBuildingIds = ADGuide.deepCopy(draft.sourceBuildingIds),
|
|
targetBuildingIds = ADGuide.deepCopy(draft.targetBuildingIds), storeBuildingIds = storeIds,
|
|
products = ADGuide.deepCopy(draft.products), ingredientMode = draft.ingredientMode,
|
|
ingredients = ADGuide.deepCopy(draft.ingredients), sellAtPercent = draft.sellAtPercent,
|
|
storeAbovePercent = draft.storeAbovePercent, sellAbovePercent = draft.sellAbovePercent or 0,
|
|
collectRound = draft.collectRound, loops = draft.loops,
|
|
returnBelowPercent = draft.returnBelowPercent, waitPoolGroup = draft.waitPoolGroup or "",
|
|
}
|
|
if draft.name ~= nil and draft.name:match("%S") then changes.name = draft.name end
|
|
return {isNew = draft.isNew == true, runId = draft.id, name = draft.name, kind = draft.kind, changes = changes,
|
|
vehicleIds = ADGuide.deepCopy(draft.vehicleIds)}
|
|
end
|
|
|
|
-- Traktorer der skal tildeles/fjernes efter gem.
|
|
function ADFlowGuide.vehicleChanges(oldIds, newIds)
|
|
local old, new = chosenSet(oldIds), chosenSet(newIds)
|
|
local added, removed = {}, {}
|
|
for _, id in ipairs(newIds or {}) do if not old[id] then table.insert(added, id) end end
|
|
for _, id in ipairs(oldIds or {}) do if not new[id] then table.insert(removed, id) end end
|
|
return added, removed
|
|
end
|