Files
fs25-adsmartpickup/FS25_ADSmartPickup/adSources.lua
T

619 lines
28 KiB
Lua
Raw 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 Sources
-- Kilder til udkørsel: hvad står der ved en AD-markør (fabrik, silo eller objektlager),
-- hvilke varer rummer/producerer den, hvor meget, og hvordan tages paller ud af et
-- objektlager. Spil-adapter — de rene beslutninger ligger i adOutboundPlanner.
ADSources = {}
ADSources.LOG_PREFIX = "ADSmartPickup: "
-- Objektlager tættere end dette på markøren regnes som markørens (samme som triggere).
ADSources.MAX_DISTANCE = 40
-- Paller der står inden for denne afstand af fabrikkens pallespawner tæller som fabrikkens output.
ADSources.PALLET_RADIUS = 25
local function distance2(ax, az, bx, bz)
local dx, dz = ax - bx, az - bz
return dx * dx + dz * dz
end
local function getNodePosition(node)
if node == nil or (entityExists ~= nil and not entityExists(node)) then
return nil
end
local x, _, z = getWorldTranslation(node)
return x, z
end
local function getPlaceableName(placeable, fallback)
if placeable ~= nil and placeable.getName ~= nil then
local ok, name = pcall(placeable.getName, placeable)
if ok and name ~= nil then
return tostring(name)
end
end
return fallback
end
local function getProductionPoint(placeable)
return placeable ~= nil and placeable.spec_productionPoint ~= nil and placeable.spec_productionPoint.productionPoint or nil
end
-- Varer der KAN stå på paller (spillets fillType-definition: isPalletType eller pallefil).
-- Sukker og mel er palletyper, men læsses som bulk ved en fabrik med læssestation — så om
-- varen er palle eller bulk afgøres pr. kilde i isPalletAt, ikke her.
function ADSources.isPalletFillType(fillType)
local desc = g_fillTypeManager ~= nil and g_fillTypeManager.getFillTypeByIndex ~= nil and g_fillTypeManager:getFillTypeByIndex(fillType) or nil
return desc ~= nil and (desc.isPalletType == true or desc.palletFilename ~= nil)
end
local function stationSupports(station, fillType)
if station == nil then
return false
end
if station.supportedFillTypes ~= nil then
return station.supportedFillTypes[fillType] == true
end
if station.getIsFillTypeSupported ~= nil then
local ok, value = pcall(station.getIsFillTypeSupported, station, fillType)
return ok and value == true
end
return false
end
-- Palle eller bulk ved DENNE kilde: silo = bulk; objektlager = palle; fabrik = bulk hvis
-- markørens læssestation udleverer varen, ellers palle hvis varen er en palletype.
function ADSources.isPalletAt(source, fillType)
if source.kind == "silo" then
return false
elseif source.kind == "objectStorage" then
return true
end
local productionPoint = getProductionPoint(source.placeable)
local loadingStation = productionPoint ~= nil and productionPoint.loadingStation or nil
if stationSupports(source.station, fillType) or stationSupports(loadingStation, fillType) then
return false
end
return ADSources.isPalletFillType(fillType)
end
-- Placeable'ns "nærmeste punkt" for kildegenkendelse: pallespawnerens første plads (fabrik)
-- eller rodnoden.
local function getPlaceableAnchor(placeable)
local productionPoint = getProductionPoint(placeable)
local spawner = productionPoint ~= nil and productionPoint.palletSpawner or nil
local place = spawner ~= nil and spawner.spawnPlaces ~= nil and spawner.spawnPlaces[1] or nil
local node = place ~= nil and place.startNode or placeable.rootNode
local x, z = getNodePosition(node)
if x == nil and node ~= placeable.rootNode then
x, z = getNodePosition(placeable.rootNode)
end
return x, z
end
-- Nærmeste placeable inden for MAX_DISTANCE af waypointet som farmen må bruge og predicate godkender.
local function findPlaceableNear(wayPoint, farmId, predicate)
local placeables = g_currentMission ~= nil and g_currentMission.placeableSystem ~= nil and g_currentMission.placeableSystem.placeables or {}
local access = g_currentMission ~= nil and g_currentMission.accessHandler or nil
local best, bestDistance = nil, ADSources.MAX_DISTANCE * ADSources.MAX_DISTANCE
for _, placeable in pairs(placeables) do
if predicate(placeable) and (access == nil or access:canFarmAccess(farmId, placeable)) then
local x, z = getPlaceableAnchor(placeable)
if x ~= nil then
local d = distance2(wayPoint.x, wayPoint.z, x, z)
if d < bestDistance then
best, bestDistance = placeable, d
end
end
end
end
return best
end
local function isObjectStorage(placeable)
return placeable.spec_objectStorage ~= nil
end
local function isProductionPoint(placeable)
return getProductionPoint(placeable) ~= nil
end
-- {kind = "factory"|"silo"|"objectStorage", placeable, station|nil, wayPointId, name} eller nil.
function ADSources.identify(adEnv, wayPointId, farmId)
local wayPoint = adEnv.ADGraphManager:getWayPointById(wayPointId)
if wayPoint == nil then
return nil
end
local marker = adEnv.ADGraphManager.getMapMarkerByWayPointId ~= nil and adEnv.ADGraphManager:getMapMarkerByWayPointId(wayPointId) or nil
local markerName = marker ~= nil and tostring(marker.name) or tostring(wayPointId)
local station = ADSmartPickup.getLoadStationAtWayPointId(adEnv, wayPointId, farmId)
local placeable = station ~= nil and station.owningPlaceable or nil
if placeable ~= nil and getProductionPoint(placeable) ~= nil then
return {kind = "factory", placeable = placeable, station = station, wayPointId = wayPointId, name = getPlaceableName(placeable, markerName)}
end
if placeable ~= nil and placeable.spec_silo ~= nil then
return {kind = "silo", placeable = placeable, station = station, wayPointId = wayPointId, name = getPlaceableName(placeable, markerName)}
end
-- Rene pallefabrikker (halmvarer, bageri ...) har ingen læssestation: find dem på afstand
-- til pallespawneren; dernæst objektlagre.
local factory = findPlaceableNear(wayPoint, farmId, isProductionPoint)
if factory ~= nil then
-- produktionspunktets egen læssestation (bulk-outputs), også når markøren ikke rammer triggeren
local loadingStation = getProductionPoint(factory).loadingStation
return {kind = "factory", placeable = factory, station = loadingStation, wayPointId = wayPointId, name = getPlaceableName(factory, markerName)}
end
local storage = findPlaceableNear(wayPoint, farmId, isObjectStorage)
if storage ~= nil then
return {kind = "objectStorage", placeable = storage, station = nil, wayPointId = wayPointId, name = getPlaceableName(storage, markerName)}
end
return nil
end
local function isPalletVehicle(vehicle)
return vehicle ~= nil and (vehicle.spec_pallet ~= nil or vehicle.isPallet == true)
end
local function getPalletContent(vehicle)
if vehicle.getFillUnitFillType ~= nil and vehicle.getFillUnitFillLevel ~= nil then
return vehicle:getFillUnitFillType(1), vehicle:getFillUnitFillLevel(1) or 0
end
local units = vehicle.spec_fillUnit ~= nil and vehicle.spec_fillUnit.fillUnits or nil
if units ~= nil and units[1] ~= nil then
return units[1].fillType, units[1].fillLevel or 0
end
return nil, 0
end
-- Liter af varen på paller der står ved fabrikkens spawner (pallespawneren tømmer lageret
-- ud på jorden løbende, så det er dér varen fysisk er).
local function getPalletsNearSpawner(placeable, fillType, farmId)
local productionPoint = getProductionPoint(placeable)
local spawner = productionPoint ~= nil and productionPoint.palletSpawner or nil
local node = spawner ~= nil and spawner.spawnPlaces ~= nil and spawner.spawnPlaces[1] ~= nil and spawner.spawnPlaces[1].startNode or placeable.rootNode
local sx, sz = getNodePosition(node)
if sx == nil then
return 0
end
local vehicles = g_currentMission ~= nil and g_currentMission.vehicleSystem ~= nil and g_currentMission.vehicleSystem.vehicles or {}
local total, count = 0, 0
local radius2 = ADSources.PALLET_RADIUS * ADSources.PALLET_RADIUS
for _, vehicle in pairs(vehicles) do
if isPalletVehicle(vehicle) and (vehicle.getOwnerFarmId == nil or vehicle:getOwnerFarmId() == farmId) then
local palletFillType, level = getPalletContent(vehicle)
local x, z = getNodePosition(vehicle.rootNode)
if palletFillType == fillType and x ~= nil and distance2(sx, sz, x, z) <= radius2 then
total = total + level
count = count + 1
end
end
end
return total, count
end
-- canPallet: varen er en palletype (kan stå på paller); palletLiters: liter på paller ved
-- kilden når varen ELLERS læsses som bulk (fabrik med både læssestation og pallespawner).
local function newProduct(fillType, available, level, capacity, isPallet)
local name = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType)
local title = g_fillTypeManager ~= nil and g_fillTypeManager.getFillTypeTitleByIndex ~= nil and g_fillTypeManager:getFillTypeTitleByIndex(fillType) or nil
return {fillType = fillType, name = name, title = title or name, available = available, level = level, capacity = capacity, isPallet = isPallet, canPallet = isPallet or ADSources.isPalletFillType(fillType), palletLiters = 0, palletCount = 0}
end
local function getFactoryProducts(source, farmId)
local productionPoint = getProductionPoint(source.placeable)
local storage = productionPoint ~= nil and productionPoint.storage or nil
local seen, products = {}, {}
for _, production in ipairs(productionPoint ~= nil and productionPoint.productions or {}) do
for _, output in ipairs(production.outputs or {}) do
local fillType = output.type
if fillType ~= nil and not seen[fillType] then
seen[fillType] = true
local level = storage ~= nil and storage.getFillLevel ~= nil and (storage:getFillLevel(fillType) or 0) or 0
local capacity = storage ~= nil and storage.getCapacity ~= nil and (storage:getCapacity(fillType) or 0) or 0
local isPallet = ADSources.isPalletAt(source, fillType)
local palletLiters, palletCount = 0, 0
if ADSources.isPalletFillType(fillType) then
palletLiters, palletCount = getPalletsNearSpawner(source.placeable, fillType, farmId)
end
local available = level + (isPallet and palletLiters or 0)
local product = newProduct(fillType, available, level, capacity, isPallet)
product.palletLiters, product.palletCount = palletLiters, palletCount
table.insert(products, product)
end
end
end
return products
end
local function getSiloProducts(source)
local storages = source.placeable.spec_silo ~= nil and source.placeable.spec_silo.storages or {}
local levels, capacities = {}, {}
for _, storage in pairs(storages) do
for fillType, level in pairs(storage.fillLevels or {}) do
if (level or 0) > 0 then
levels[fillType] = (levels[fillType] or 0) + level
capacities[fillType] = (capacities[fillType] or 0) + (storage.getCapacity ~= nil and (storage:getCapacity(fillType) or 0) or 0)
end
end
end
local products = {}
for fillType, level in pairs(levels) do
table.insert(products, newProduct(fillType, level, level, capacities[fillType] or 0, false))
end
table.sort(products, function(a, b) return a.fillType < b.fillType end)
return products
end
-- Et objektlagers post: {fillType, fillLevel pr. objekt} for paller og baller.
local function getObjectInfoContent(objectInfo)
local object = objectInfo.objects ~= nil and objectInfo.objects[1] or nil
if object == nil then
return nil, 0
end
local attributes = object.palletAttributes or object.baleAttributes
if attributes ~= nil then
return attributes.fillType, attributes.fillLevel or 0
end
return object.fillType, object.fillLevel or 0
end
local function getObjectStorageProducts(source)
local spec = source.placeable.spec_objectStorage
local products = {}
for _, objectInfo in ipairs(spec ~= nil and spec.objectInfos or {}) do
local fillType, perObject = getObjectInfoContent(objectInfo)
local count = objectInfo.numObjects or 0
if fillType ~= nil and count > 0 then
local product = newProduct(fillType, count * perObject, spec.numStoredObjects or count, spec.capacity or 0, true)
product.palletCount = count
table.insert(products, product)
end
end
return products
end
-- Varer ved kilden med tilgængelig mængde: { {fillType, name, title, available, level, capacity, isPallet} }.
function ADSources.getProducts(adEnv, source, farmId)
if source.kind == "factory" then
return getFactoryProducts(source, farmId)
elseif source.kind == "silo" then
return getSiloProducts(source)
elseif source.kind == "objectStorage" then
return getObjectStorageProducts(source)
end
return {}
end
-- Objektlager: objectInfo-indeks + antal for varen; nil når lageret ikke har den.
function ADSources.getObjectInfoIndex(source, fillType)
local spec = source.placeable ~= nil and source.placeable.spec_objectStorage or nil
for index, objectInfo in ipairs(spec ~= nil and spec.objectInfos or {}) do
local infoFillType = getObjectInfoContent(objectInfo)
if infoFillType == fillType and (objectInfo.numObjects or 0) > 0 then
return index, objectInfo.numObjects
end
end
return nil
end
function ADSources.countStored(source, fillType)
local _, count = ADSources.getObjectInfoIndex(source, fillType)
return count or 0
end
-- Bed lageret spawne ÉT objekt (det knappen i spillet gør). connection = nil, så
-- AutomaticBaleStorage-moddens kø (der kun fanger klient-kald) ikke blander sig.
function ADSources.spawnOne(source, objectInfoIndex)
local placeable = source.placeable
if placeable == nil or placeable.removeAbstractObjectsFromStorage == nil then
return false
end
local ok = pcall(placeable.removeAbstractObjectsFromStorage, placeable, objectInfoIndex, 1, nil)
return ok == true
end
function ADSources.stationAccepts(station, fillType)
if station.acceptedFillTypes ~= nil then
return station.acceptedFillTypes[fillType] == true
end
if station.getIsFillTypeSupported ~= nil then
return station:getIsFillTypeSupported(fillType) == true
end
return station.supportedFillTypes ~= nil and station.supportedFillTypes[fillType] == true
end
-- Markører hvis aflæsningsstation er et rigtigt salgssted: { {marker, station} }.
function ADSources.getSellMarkers(adEnv, farmId)
local result = {}
for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do
local station = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId)
if station ~= nil and ADPrices.isSellingStation(station) then
table.insert(result, {marker = marker, station = station})
end
end
return result
end
-- ---- paller til lager: objektlager (palleskur) som mål ----
function ADSources.objectStorageAccepts(placeable, fillType)
local spec = placeable ~= nil and placeable.spec_objectStorage or nil
if spec == nil or spec.supportsPallets == false then
return false
end
if placeable.getObjectStorageSupportsFillType ~= nil then
local ok, value = pcall(placeable.getObjectStorageSupportsFillType, placeable, fillType)
return ok and value == true
end
return true
end
-- Ledige pladser (objekter); uendeligt når lageret ingen kapacitet opgiver.
function ADSources.objectStorageFreeSlots(placeable)
local spec = placeable ~= nil and placeable.spec_objectStorage or nil
if spec == nil then
return 0
end
local capacity = spec.capacity or 0
if capacity <= 0 then
return math.huge
end
local stored = spec.storedObjects ~= nil and #spec.storedObjects or (spec.numStoredObjects or 0)
return math.max(0, capacity - stored)
end
-- Nærmeste markør ved et objektlager der tager varen og har plads, med rute fra traktoren;
-- kilderne selv udelukkes. {wayPointId, name, free = pladser} eller nil.
function ADSources.findPalletStore(adEnv, vehicle, fillType, excludedPlaceables, isReachable, farmId)
local x, z = getNodePosition(vehicle.rootNode)
if x == nil then
return nil
end
local candidates = {}
for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do
local source = ADSources.identify(adEnv, marker.id, farmId)
if source ~= nil and source.kind == "objectStorage" and not (excludedPlaceables ~= nil and excludedPlaceables[source.placeable])
and ADSources.objectStorageAccepts(source.placeable, fillType) and ADSources.objectStorageFreeSlots(source.placeable) >= 1 then
local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id)
table.insert(candidates, {marker = marker, source = source, distance = distance2(x, z, wayPoint.x, wayPoint.z)})
end
end
table.sort(candidates, function(a, b) return a.distance < b.distance end)
for _, candidate in ipairs(candidates) do
if isReachable == nil or isReachable(candidate.marker.id) then
return {wayPointId = candidate.marker.id, name = tostring(candidate.marker.name), free = ADSources.objectStorageFreeSlots(candidate.source.placeable)}
end
end
return nil
end
-- ---- reserve: hvad gårdens egne fabrikker og stalde skal bruge det næste døgn ----
ADSources.RESERVE_HOURS = 24
local function isOwnedBy(placeable, farmId)
if placeable.getOwnerFarmId ~= nil then
local ok, owner = pcall(placeable.getOwnerFarmId, placeable)
return ok and owner == farmId
end
return placeable.ownerFarmId == farmId
end
local function isProductionWanted(productionPoint, production)
local isEnabled = false
if productionPoint.getIsProductionEnabled ~= nil then
isEnabled = productionPoint:getIsProductionEnabled(production.id) == true
else
for _, active in ipairs(productionPoint.activeProductions or {}) do
if active == production then isEnabled = true end
end
end
local missingInputs = ProductionPoint ~= nil and ProductionPoint.PROD_STATUS ~= nil and ProductionPoint.PROD_STATUS.MISSING_INPUTS or nil
return isEnabled or (missingInputs ~= nil and production.status == missingInputs)
end
-- Fabrik: døgnforbrug af varen i ønskede produktioner minus det den har, højst fri plads.
local function getProductionReserve(placeable, fillType)
local productionPoint = getProductionPoint(placeable)
if productionPoint == nil or productionPoint.storage == nil then
return 0
end
local perMinute = 0
for _, production in ipairs(productionPoint.productions or {}) do
if isProductionWanted(productionPoint, production) then
for _, input in ipairs(production.inputs or {}) do
if input.type == fillType then
local cyclesPerMinute = production.cyclesPerMinute or ((production.cyclesPerHour or 0) / 60)
perMinute = perMinute + (input.amount or 0) * cyclesPerMinute
end
end
end
end
if perMinute <= 0 then
return 0
end
local storage = productionPoint.storage
local level = storage.getFillLevel ~= nil and (storage:getFillLevel(fillType) or 0) or ((storage.fillLevels or {})[fillType] or 0)
local free = storage.getFreeCapacity ~= nil and storage:getFreeCapacity(fillType) or nil
if free == nil then
local capacity = storage.getCapacity ~= nil and (storage:getCapacity(fillType) or 0) or 0
free = math.max(0, capacity - level)
end
local need = perMinute * 60 * ADSources.RESERVE_HOURS - level
return math.max(0, math.min(need, free))
end
-- Stald: foder/halm/vand-rate × timer minus beholdning, højst fri plads (spec-felter som
-- Distribution Redux læser dem); automatisk vandforsyning = intet behov.
local function getHusbandryReserve(placeable, fillType)
if placeable.getHusbandryIsFillTypeSupported == nil or placeable.getHusbandryFillLevel == nil then
return 0
end
local okSupported, supported = pcall(placeable.getHusbandryIsFillTypeSupported, placeable, fillType)
if not okSupported or supported ~= true then
return 0
end
local name = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or ""
local rate, level = 0, placeable:getHusbandryFillLevel(fillType) or 0
local food, straw, water = placeable.spec_husbandryFood, placeable.spec_husbandryStraw, placeable.spec_husbandryWater
if name == "WATER" then
if water == nil or water.automaticWaterSupply then return 0 end
rate = water.litersPerHour or 0
elseif name == "STRAW" and straw ~= nil then
rate = straw.inputLitersPerHour or 0
elseif food ~= nil then
rate = food.litersPerHour or 0
level = 0
for _, value in pairs(food.fillLevels or {}) do level = level + (value or 0) end
end
if rate <= 0 then
return 0
end
local free = placeable.getHusbandryFreeCapacity ~= nil and (placeable:getHusbandryFreeCapacity(fillType) or 0) or math.huge
return math.max(0, math.min(rate * ADSources.RESERVE_HOURS - level, free))
end
-- {liters, consumers = {navne}} — gårdens samlede behov for varen; udelukkede placeables (kilderne) tæller ikke.
function ADSources.getFarmDemand(adEnv, fillType, farmId, excludedPlaceables)
local placeables = g_currentMission ~= nil and g_currentMission.placeableSystem ~= nil and g_currentMission.placeableSystem.placeables or {}
local total, consumers = 0, {}
for _, placeable in pairs(placeables) do
if isOwnedBy(placeable, farmId) and not (excludedPlaceables ~= nil and excludedPlaceables[placeable]) then
local reserve = getProductionReserve(placeable, fillType) + getHusbandryReserve(placeable, fillType)
if reserve > 0 then
total = total + reserve
table.insert(consumers, getPlaceableName(placeable, "?"))
end
end
end
return {liters = total, consumers = consumers}
end
-- ---- inventar: alt gården har liggende, pr. bygning ----
local function addEntry(entries, fillType, level, capacity, extra)
local entry = newProduct(fillType, level, level, capacity, false)
entry.isOutput = extra ~= nil and extra.isOutput or false
entry.count = extra ~= nil and extra.count or nil
table.insert(entries, entry)
end
local function factoryEntries(placeable)
local productionPoint = getProductionPoint(placeable)
local storage = productionPoint ~= nil and productionPoint.storage or nil
local entries = {}
if storage == nil then return entries end
local outputs = {}
for _, production in ipairs(productionPoint.productions or {}) do
for _, output in ipairs(production.outputs or {}) do outputs[output.type] = true end
end
for fillType, level in pairs(storage.fillLevels or {}) do
if (level or 0) > 0 then
local capacity = storage.getCapacity ~= nil and (storage:getCapacity(fillType) or 0) or 0
addEntry(entries, fillType, level, capacity, {isOutput = outputs[fillType] == true})
end
end
return entries
end
local function siloEntries(placeable)
local entries, levels, capacities = {}, {}, {}
for _, storage in pairs(placeable.spec_silo.storages or {}) do
for fillType, level in pairs(storage.fillLevels or {}) do
if (level or 0) > 0 then
levels[fillType] = (levels[fillType] or 0) + level
capacities[fillType] = (capacities[fillType] or 0) + (storage.getCapacity ~= nil and (storage:getCapacity(fillType) or 0) or 0)
end
end
end
for fillType, level in pairs(levels) do addEntry(entries, fillType, level, capacities[fillType] or 0) end
return entries
end
local function objectStorageEntries(placeable)
local entries = {}
local spec = placeable.spec_objectStorage
for _, objectInfo in ipairs(spec.objectInfos or {}) do
local fillType, perObject = getObjectInfoContent(objectInfo)
local count = objectInfo.numObjects or 0
if fillType ~= nil and count > 0 then
addEntry(entries, fillType, count * perObject, spec.capacity or 0, {count = count})
end
end
return entries
end
local function husbandryEntries(placeable)
local entries, seen = {}, {}
local food = placeable.spec_husbandryFood
if food ~= nil then
local total = 0
for _, level in pairs(food.fillLevels or {}) do total = total + (level or 0) end
for fillType, level in pairs(food.fillLevels or {}) do
if (level or 0) > 0 then
seen[fillType] = true
addEntry(entries, fillType, level, level + math.max(0, (food.capacity or 0) - total))
end
end
end
for _, name in ipairs({"STRAW", "WATER", "MILK", "LIQUIDMANURE", "MANURE"}) do
local fillType = g_fillTypeManager ~= nil and g_fillTypeManager.getFillTypeIndexByName ~= nil and g_fillTypeManager:getFillTypeIndexByName(name) or nil
if fillType == nil and g_fillTypeManager ~= nil then
-- test-fakes uden getFillTypeIndexByName: slå navnet op baglæns
for index = 1, 64 do
if g_fillTypeManager:getFillTypeNameByIndex(index) == name then fillType = index break end
end
end
if fillType ~= nil and not seen[fillType] and placeable.getHusbandryIsFillTypeSupported ~= nil and placeable:getHusbandryIsFillTypeSupported(fillType) then
local level = placeable.getHusbandryFillLevel ~= nil and (placeable:getHusbandryFillLevel(fillType) or 0) or 0
if level > 0 then
local free = placeable.getHusbandryFreeCapacity ~= nil and (placeable:getHusbandryFreeCapacity(fillType) or 0) or 0
addEntry(entries, fillType, level, level + free)
end
end
end
return entries
end
-- { {name, kind = "factory"|"silo"|"objectStorage"|"husbandry", entries = {{fillType, name, title, level, capacity, isOutput, count}}} }
-- kun gårdens bygninger med indhold; sorteret på slags, dernæst navn.
function ADSources.getFarmInventory(adEnv, farmId)
local placeables = g_currentMission ~= nil and g_currentMission.placeableSystem ~= nil and g_currentMission.placeableSystem.placeables or {}
local result = {}
for _, placeable in pairs(placeables) do
if isOwnedBy(placeable, farmId) then
local kind, entries = nil, nil
if getProductionPoint(placeable) ~= nil then
kind, entries = "factory", factoryEntries(placeable)
elseif placeable.spec_silo ~= nil then
kind, entries = "silo", siloEntries(placeable)
elseif placeable.spec_objectStorage ~= nil then
kind, entries = "objectStorage", objectStorageEntries(placeable)
elseif placeable.getHusbandryFillLevel ~= nil then
kind, entries = "husbandry", husbandryEntries(placeable)
end
if entries ~= nil and #entries > 0 then
table.sort(entries, function(a, b)
if a.isOutput ~= b.isOutput then return a.isOutput end
return tostring(a.title) < tostring(b.title)
end)
table.insert(result, {name = getPlaceableName(placeable, "?"), kind = kind, entries = entries, placeable = placeable})
end
end
end
local order = {factory = 1, husbandry = 2, objectStorage = 3, silo = 4}
table.sort(result, function(a, b)
if order[a.kind] ~= order[b.kind] then return order[a.kind] < order[b.kind] end
return a.name < b.name
end)
return result
end
function ADSources.getSourcePlaceables(sources)
local set = {}
for _, source in ipairs(sources or {}) do
if source.placeable ~= nil then
set[source.placeable] = true
end
end
return set
end