531 lines
33 KiB
Lua
531 lines
33 KiB
Lua
-- Kør: luajit tests/test_adSources.lua (fra repo-roden)
|
||
-- Kilde-genkendelse ved en AD-markør (fabrik / silo / objektlager), lagerstatus pr. vare,
|
||
-- paller ved fabrikkens spawner, salgssteder, objektlager-udtag.
|
||
|
||
local SUGAR, FORAGE, BASKET, CRATE = 5, 6, 7, 8
|
||
local DESC = {
|
||
[SUGAR] = {index = SUGAR, name = "SUGAR", title = "Sukker", isPalletType = true},
|
||
[FORAGE] = {index = FORAGE, name = "FORAGE", title = "TMR"},
|
||
[BASKET] = {index = BASKET, name = "STRAW_BASKET", title = "Halmkurve", palletFilename = "basketPallet.xml"},
|
||
[CRATE] = {index = CRATE, name = "STRAW_CRATE", title = "Halmkasser", palletFilename = "cratePallet.xml"},
|
||
}
|
||
g_fillTypeManager = {
|
||
getFillTypeByIndex = function(_, index) return DESC[index] end,
|
||
getFillTypeNameByIndex = function(_, index) return DESC[index] and DESC[index].name end,
|
||
getFillTypeTitleByIndex = function(_, index) return DESC[index] and DESC[index].title end,
|
||
}
|
||
Logging = {info = function() end, warning = function() end}
|
||
getWorldTranslation = function(node) return node.x, 0, node.z end
|
||
SellingStation = {}
|
||
|
||
dofile("FS25_ADSmartPickup/adSupplyPlanner.lua")
|
||
dofile("FS25_ADSmartPickup/adPrices.lua")
|
||
dofile("FS25_ADSmartPickup/adStorageStats.lua")
|
||
dofile("FS25_ADSmartPickup/adSources.lua")
|
||
|
||
local failures = 0
|
||
local function check(name, actual, expected)
|
||
if actual == expected then
|
||
print("OK " .. name)
|
||
else
|
||
failures = failures + 1
|
||
print(string.format("FAIL %s: forventede %s, fik %s", name, tostring(expected), tostring(actual)))
|
||
end
|
||
end
|
||
|
||
-- ---- fakes ----
|
||
local wayPoints, markers = {}, {}
|
||
local function addMarker(id, name, x, z)
|
||
wayPoints[id] = {id = id, x = x, z = z}
|
||
table.insert(markers, {id = id, markerIndex = #markers + 1, name = name, group = "g"})
|
||
end
|
||
local adEnv = {ADGraphManager = {
|
||
getWayPointById = function(_, id) return wayPoints[id] end,
|
||
getMapMarkers = function() return markers end,
|
||
getMapMarkerByWayPointId = function(_, id) for _, m in ipairs(markers) do if m.id == id then return m end end end,
|
||
}}
|
||
|
||
local function storageOf(levels, capacities)
|
||
return {
|
||
fillLevels = levels,
|
||
getFillLevel = function(_, ft) return levels[ft] or 0 end,
|
||
getCapacity = function(_, ft) return capacities[ft] or 0 end,
|
||
}
|
||
end
|
||
|
||
local sugarStorage = storageOf({[SUGAR] = 150000, [BASKET] = 0}, {[SUGAR] = 180000, [BASKET] = 8000})
|
||
local factory = {
|
||
rootNode = {x = 100, z = 100}, getName = function() return "Sugar mill" end,
|
||
spec_productionPoint = {productionPoint = {
|
||
productions = {{outputs = {{type = SUGAR, amount = 1}}}, {outputs = {{type = BASKET, amount = 1}}}},
|
||
storage = sugarStorage,
|
||
palletSpawner = {spawnPlaces = {{startNode = {x = 110, z = 100}}}},
|
||
}},
|
||
}
|
||
local factoryStation = {owningPlaceable = factory, supportedFillTypes = {[SUGAR] = true}}
|
||
local silo = {rootNode = {x = 200, z = 200}, spec_silo = {storages = {storageOf({[FORAGE] = 74500}, {[FORAGE] = 12000000})}}, getName = function() return "Farma" end}
|
||
local siloStation = {owningPlaceable = silo}
|
||
local spawnCalls = {}
|
||
local objectStorage = {
|
||
rootNode = {x = 300, z = 300}, ownerFarmId = 1, getName = function() return "Objektlager" end,
|
||
spec_objectStorage = {
|
||
objectInfos = {
|
||
{objects = {{palletAttributes = {fillType = BASKET, fillLevel = 1000}}}, numObjects = 8},
|
||
{objects = {{baleAttributes = {fillType = FORAGE, fillLevel = 4000}}}, numObjects = 2},
|
||
},
|
||
numStoredObjects = 10, capacity = 4000,
|
||
},
|
||
removeAbstractObjectsFromStorage = function(self, index, amount, connection) table.insert(spawnCalls, {index, amount, connection}) end,
|
||
}
|
||
local sellStation = {owningPlaceable = {rootNode = {x = 500, z = 500}}, isa = function(_, c) return c == SellingStation end, isSellingPoint = true, acceptedFillTypes = {[SUGAR] = true}, getName = function() return "Grain Elevator" end}
|
||
local factoryUnload = {owningPlaceable = factory, isa = function() return true end, isSellingPoint = false}
|
||
|
||
addMarker(1, "Suger Load", 100, 90)
|
||
addMarker(2, "silo 2", 200, 190)
|
||
addMarker(3, "Objektlager", 300, 280) -- 20 m fra lageret
|
||
addMarker(4, "Langt væk", 300, 240) -- 60 m fra lageret
|
||
addMarker(5, "selling station", 500, 490)
|
||
addMarker(6, "sugar offload", 100, 80)
|
||
|
||
local loadAt = {[1] = factoryStation, [2] = siloStation}
|
||
local unloadAt = {[5] = sellStation, [6] = factoryUnload}
|
||
ADSmartPickup = {
|
||
getLoadStationAtWayPointId = function(_, id) return loadAt[id] end,
|
||
getUnloadStationAtWayPointId = function(_, id) return unloadAt[id] end,
|
||
getOwnStorageLevel = function(station, fillTypes)
|
||
local total = 0
|
||
for _, storage in pairs(station.owningPlaceable.spec_silo.storages) do
|
||
for _, ft in ipairs(fillTypes) do total = total + storage:getFillLevel(ft) end
|
||
end
|
||
return total
|
||
end,
|
||
}
|
||
local pallets = {}
|
||
local function addPallet(fillType, level, x, z, farmId)
|
||
table.insert(pallets, {spec_pallet = {}, rootNode = {x = x, z = z}, getOwnerFarmId = function() return farmId or 1 end,
|
||
getFillUnitFillType = function() return fillType end, getFillUnitFillLevel = function() return level end})
|
||
end
|
||
g_currentMission = {
|
||
placeableSystem = {placeables = {factory, silo, objectStorage}},
|
||
accessHandler = {canFarmAccess = function(_, farmId, placeable) return true end},
|
||
vehicleSystem = {vehicles = pallets},
|
||
}
|
||
|
||
-- S1: fabrik
|
||
local source1 = ADSources.identify(adEnv, 1, 1)
|
||
check("S1 fabrik", source1.kind, "factory")
|
||
check("S1 navn", source1.name, "Sugar mill")
|
||
local products1 = ADSources.getProducts(adEnv, source1, 1)
|
||
check("S1 to produkter", #products1, 2)
|
||
check("S1 SUGAR available", products1[1].available, 150000)
|
||
check("S1 SUGAR level", products1[1].level, 150000)
|
||
check("S1 SUGAR capacity", products1[1].capacity, 180000)
|
||
check("S1 SUGAR bulk", products1[1].isPallet, false)
|
||
check("S1 SUGAR kan også stå på paller", products1[1].canPallet, true)
|
||
check("S1 SUGAR paller ved spawner (ingen endnu)", products1[1].palletLiters, 0)
|
||
check("S1 TMR-lignende bulk kan ikke paller", products1[2].canPallet, true)
|
||
check("S1 BASKET er palle", products1[2].isPallet, true)
|
||
check("S1 BASKET tomt", products1[2].available, 0)
|
||
|
||
-- S2: silo
|
||
local source2 = ADSources.identify(adEnv, 2, 1)
|
||
check("S2 silo", source2.kind, "silo")
|
||
local products2 = ADSources.getProducts(adEnv, source2, 1)
|
||
check("S2 én vare", #products2, 1)
|
||
check("S2 FORAGE", products2[1].fillType, FORAGE)
|
||
check("S2 level", products2[1].level, 74500)
|
||
check("S2 capacity", products2[1].capacity, 12000000)
|
||
|
||
-- S3: objektlager 20 m fra markøren
|
||
local source3 = ADSources.identify(adEnv, 3, 1)
|
||
check("S3 objektlager", source3.kind, "objectStorage")
|
||
local products3 = ADSources.getProducts(adEnv, source3, 1)
|
||
check("S3 to varer", #products3, 2)
|
||
check("S3 kurve available", products3[1].available, 8000)
|
||
check("S3 kurve er palle", products3[1].isPallet, true)
|
||
check("S3 level = antal objekter", products3[1].level, 10)
|
||
check("S3 capacity", products3[1].capacity, 4000)
|
||
check("S3 baller tæller som palle", products3[2].isPallet, true)
|
||
local index, count = ADSources.getObjectInfoIndex(source3, BASKET)
|
||
check("S3 objectInfo-indeks", index, 1)
|
||
check("S3 antal", count, 8)
|
||
check("S3 countStored", ADSources.countStored(source3, FORAGE), 2)
|
||
check("S3 ukendt vare", ADSources.getObjectInfoIndex(source3, SUGAR), nil)
|
||
|
||
-- S4: paller ved fabrikkens spawner tæller med (inden for 25 m af spawn-noden)
|
||
addPallet(BASKET, 1000, 112, 100)
|
||
addPallet(BASKET, 1000, 115, 105)
|
||
addPallet(BASKET, 1000, 160, 100) -- 50 m væk: tæller ikke
|
||
addPallet(BASKET, 1000, 112, 102, 2) -- anden farm: tæller ikke
|
||
local products4 = ADSources.getProducts(adEnv, source1, 1)
|
||
check("S4 paller ved spawner", products4[2].available, 2000)
|
||
check("S4 antal paller ved spawner", products4[2].palletCount, 2)
|
||
check("S3 antal paller i objektlager", products3[1].palletCount, 8)
|
||
check("S4 bulk uændret", products4[1].available, 150000)
|
||
addPallet(SUGAR, 2000, 111, 101)
|
||
local products4b = ADSources.getProducts(adEnv, source1, 1)
|
||
check("S4 sukkerpaller tælles separat", products4b[1].palletLiters, 2000)
|
||
check("S4 bulk-mængde uden paller", products4b[1].available, 150000)
|
||
|
||
-- S5: salgssteder = kun markører hvis aflæsningsstation er et rigtigt salgssted
|
||
local sells = ADSources.getSellMarkers(adEnv, 1)
|
||
check("S5 ét salgssted", #sells, 1)
|
||
check("S5 markør", sells[1].marker.id, 5)
|
||
check("S5 tager SUGAR", ADSources.stationAccepts(sells[1].station, SUGAR), true)
|
||
check("S5 tager ikke FORAGE", ADSources.stationAccepts(sells[1].station, FORAGE), false)
|
||
-- palletriggerens varer ligger i supportedFillTypes (det AutoDrive bruger), ikke i acceptedFillTypes (kun bulk-trigger)
|
||
local palletSell = {acceptedFillTypes = {[SUGAR] = true}, supportedFillTypes = {[SUGAR] = true, [BASKET] = true}}
|
||
check("S5 pallevare via supportedFillTypes", ADSources.stationAccepts(palletSell, BASKET), true)
|
||
check("S5 ukendt vare stadig nej", ADSources.stationAccepts(palletSell, FORAGE), false)
|
||
check("S5 acceptedNames", ADSources.describeAccepted(palletSell), "STRAW_BASKET, SUGAR")
|
||
|
||
-- S6: spawnOne kalder spillets udtag med 1 objekt og uden klientforbindelse
|
||
check("S6 spawn ok", ADSources.spawnOne(source3, 1), true)
|
||
check("S6 indeks", spawnCalls[1][1], 1)
|
||
check("S6 antal", spawnCalls[1][2], 1)
|
||
check("S6 connection nil", spawnCalls[1][3], nil)
|
||
check("S6 fejl -> false", ADSources.spawnOne({kind = "objectStorage", placeable = {removeAbstractObjectsFromStorage = function() error("x") end}}, 1), false)
|
||
|
||
-- S7: markør uden station og >40 m fra objektlager -> nil
|
||
check("S7 ingen kilde", ADSources.identify(adEnv, 4, 1), nil)
|
||
check("S7 ukendt waypoint", ADSources.identify(adEnv, 99, 1), nil)
|
||
|
||
-- S8: hjælpere
|
||
check("S8 isPalletFillType palle", ADSources.isPalletFillType(BASKET), true)
|
||
check("S8 isPalletFillType palletype uden fil", ADSources.isPalletFillType(SUGAR), true)
|
||
check("S8 isPalletFillType bulk", ADSources.isPalletFillType(FORAGE), false)
|
||
-- C1: palle/bulk afgøres pr. kilde: fabrik med læssestation der tager varen = bulk; silo = altid bulk; objektlager = palle
|
||
check("S8 sukker ved fabrik med læssestation = bulk", ADSources.isPalletAt(source1, SUGAR), false)
|
||
check("S8 kurve ved fabrik (station tager dem ikke) = palle", ADSources.isPalletAt(source1, BASKET), true)
|
||
check("S8 silo altid bulk", ADSources.isPalletAt(source2, SUGAR), false)
|
||
check("S8 objektlager altid palle", ADSources.isPalletAt(source3, FORAGE), true)
|
||
-- S9 (I1): ren pallefabrik uden læssestation genkendes via afstand til spawner/rootNode
|
||
local basketFactory = {
|
||
rootNode = {x = 600, z = 600}, getName = function() return "Straw factory" end,
|
||
spec_productionPoint = {productionPoint = {productions = {{outputs = {{type = BASKET, amount = 1}}}}, storage = storageOf({[BASKET] = 0}, {[BASKET] = 8000}), palletSpawner = {spawnPlaces = {{startNode = {x = 610, z = 600}}}}}},
|
||
}
|
||
table.insert(g_currentMission.placeableSystem.placeables, basketFactory)
|
||
addMarker(7, "Straw factory pickup", 605, 590)
|
||
local source9 = ADSources.identify(adEnv, 7, 1)
|
||
check("S9 pallefabrik uden station = factory", source9.kind, "factory")
|
||
check("S9 station nil", source9.station, nil)
|
||
local products9 = ADSources.getProducts(adEnv, source9, 1)
|
||
check("S9 kurve er palle", products9[1].isPallet, true)
|
||
check("S9 fabrik foretrækkes frem for objektlager i nærheden", ADSources.identify(adEnv, 7, 1).placeable, basketFactory)
|
||
-- S9b: fabrik fundet på afstand, men produktionspunktet HAR en læssestation (sukkerfabrik hvor markøren
|
||
-- ikke rammer triggeren): stationen hentes fra produktionspunktet, og sukker er bulk, ikke paller
|
||
local mill2Storage = storageOf({[SUGAR] = 1000}, {[SUGAR] = 180000})
|
||
local mill2 = {
|
||
rootNode = {x = 1200, z = 1200}, getName = function() return "Sugar mill 2" end,
|
||
spec_productionPoint = {productionPoint = {productions = {{outputs = {{type = SUGAR, amount = 1}}}}, storage = mill2Storage,
|
||
loadingStation = {supportedFillTypes = {[SUGAR] = true}}}},
|
||
}
|
||
table.insert(g_currentMission.placeableSystem.placeables, mill2)
|
||
addMarker(9, "Mill 2 load", 1210, 1190)
|
||
local source9b = ADSources.identify(adEnv, 9, 1)
|
||
check("S9b fabrik", source9b.kind, "factory")
|
||
check("S9b station fra produktionspunktet", source9b.station, mill2.spec_productionPoint.productionPoint.loadingStation)
|
||
check("S9b sukker = bulk", ADSources.isPalletAt(source9b, SUGAR), false)
|
||
check("S9b produkt bulk", ADSources.getProducts(adEnv, source9b, 1)[1].isPallet, false)
|
||
local excluded = ADSources.getSourcePlaceables({source1, source2})
|
||
check("S8 udelukkede placeables", excluded[factory] and excluded[silo], true)
|
||
|
||
-- S10 (paller til lager): objektlager med plads der tager varen; nærmeste nåelige fra traktoren
|
||
objectStorage.getObjectStorageSupportsFillType = function(self, ft) return ft == BASKET or ft == FORAGE end
|
||
check("S10 tager kurve", ADSources.objectStorageAccepts(objectStorage, BASKET), true)
|
||
check("S10 tager ikke sukker", ADSources.objectStorageAccepts(objectStorage, SUGAR), false)
|
||
check("S10 fri pladser", ADSources.objectStorageFreeSlots(objectStorage), 3990)
|
||
local fullShed = {rootNode = {x = 700, z = 700}, spec_objectStorage = {capacity = 10, numStoredObjects = 10, objectInfos = {}}, getName = function() return "Fuldt skur" end}
|
||
table.insert(g_currentMission.placeableSystem.placeables, fullShed)
|
||
addMarker(8, "Fuldt skur", 700, 690)
|
||
check("S10 fuldt skur 0 pladser", ADSources.objectStorageFreeSlots(fullShed), 0)
|
||
local truck = {rootNode = {x = 650, z = 650}}
|
||
local store = ADSources.findPalletStore(adEnv, truck, BASKET, {}, function() return true end, 1)
|
||
check("S10 nærmeste med plads = Objektlager (skuret er fuldt)", store.wayPointId, 3)
|
||
check("S10 navn", store.name, "Objektlager")
|
||
check("S10 udelukket kilde -> nil", ADSources.findPalletStore(adEnv, truck, BASKET, {[objectStorage] = true}, function() return true end, 1), nil)
|
||
check("S10 uopnåelig -> nil", ADSources.findPalletStore(adEnv, truck, BASKET, {}, function() return false end, 1), nil)
|
||
check("S10 sukker: intet skur tager det", ADSources.findPalletStore(adEnv, truck, SUGAR, {}, function() return true end, 1), nil)
|
||
|
||
-- S11 (reserve): gårdens forbrug det næste døgn af en vare, minus hvad forbrugerne allerede har
|
||
local BEET, STRAW, WATER = 9, 10, 11
|
||
DESC[BEET] = {index = BEET, name = "SUGARBEET", title = "Roer"}; DESC[STRAW] = {index = STRAW, name = "STRAW", title = "Halm"}; DESC[WATER] = {index = WATER, name = "WATER", title = "Vand"}
|
||
local tmrStorage = storageOf({[BEET] = 20000, [FORAGE] = 500000}, {[BEET] = 2500000, [FORAGE] = 3500000})
|
||
local tmrFactory = {
|
||
rootNode = {x = 800, z = 800}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "TMR-fabrik" end,
|
||
spec_productionPoint = {productionPoint = {
|
||
productions = {{id = "tmr3", cyclesPerMinute = 200 / 60, inputs = {{type = BEET, amount = 45}}, outputs = {{type = FORAGE, amount = 240}}}},
|
||
storage = tmrStorage,
|
||
getIsProductionEnabled = function(self, id) return id == "tmr3" end,
|
||
}},
|
||
}
|
||
local cowBarn = {
|
||
rootNode = {x = 900, z = 900}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Kostald" end,
|
||
spec_husbandryStraw = {inputLitersPerHour = 500}, spec_husbandryWater = {litersPerHour = 100, automaticWaterSupply = true},
|
||
getHusbandryIsFillTypeSupported = function(self, ft) return ft == STRAW or ft == WATER end,
|
||
getHusbandryFillLevel = function(self, ft) return ft == STRAW and 2000 or 0 end,
|
||
getHusbandryFreeCapacity = function(self, ft) return ft == STRAW and 19375 or 0 end,
|
||
}
|
||
local otherFarmBarn = {rootNode = {x = 950, z = 950}, ownerFarmId = 2, getOwnerFarmId = function() return 2 end, spec_husbandryStraw = {inputLitersPerHour = 500}, getHusbandryIsFillTypeSupported = function() return true end, getHusbandryFillLevel = function() return 0 end, getHusbandryFreeCapacity = function() return 99999 end}
|
||
table.insert(g_currentMission.placeableSystem.placeables, tmrFactory)
|
||
table.insert(g_currentMission.placeableSystem.placeables, cowBarn)
|
||
table.insert(g_currentMission.placeableSystem.placeables, otherFarmBarn)
|
||
local demand = ADSources.getFarmDemand(adEnv, BEET, 1, {})
|
||
-- 45 l × (200/60) pr. min × 1440 min = 216.000 l/døgn; har 20.000 -> 196.000
|
||
check("S11 roer: døgnforbrug minus beholdning", demand.liters, 196000)
|
||
check("S11 forbruger-navn", demand.consumers[1], "TMR-fabrik")
|
||
local strawDemand = ADSources.getFarmDemand(adEnv, STRAW, 1, {})
|
||
-- 500 l/t × 24 = 12.000; har 2.000 -> 10.000 (under fri plads 19.375)
|
||
check("S11 halm: stald", strawDemand.liters, 10000)
|
||
check("S11 anden farm tæller ikke", #strawDemand.consumers, 1)
|
||
check("S11 automatisk vand = intet behov", ADSources.getFarmDemand(adEnv, WATER, 1, {}).liters, 0)
|
||
check("S11 output er ikke behov", ADSources.getFarmDemand(adEnv, FORAGE, 1, {}).liters, 0)
|
||
check("S11 udelukket forbruger", ADSources.getFarmDemand(adEnv, BEET, 1, {[tmrFactory] = true}).liters, 0)
|
||
tmrStorage.fillLevels[BEET] = 300000
|
||
check("S11 nok på lager -> 0", ADSources.getFarmDemand(adEnv, BEET, 1, {}).liters, 0)
|
||
tmrStorage.fillLevels[BEET] = 20000
|
||
tmrFactory.spec_productionPoint.productionPoint.getIsProductionEnabled = function() return false end
|
||
check("S11 slukket produktion -> 0", ADSources.getFarmDemand(adEnv, BEET, 1, {}).liters, 0)
|
||
|
||
-- S11b: staldens OUTPUT (mælk, gylle) er aldrig et behov — kun varer i foderkrybben er foder
|
||
local MILK_OUT = 13
|
||
local feedBarn = {
|
||
rootNode = {x = 960, z = 960}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Malkestald" end,
|
||
spec_husbandryFood = {litersPerHour = 2000, fillLevels = {[FORAGE] = 1000}},
|
||
getHusbandryIsFillTypeSupported = function(self, ft) return ft == MILK_OUT or ft == FORAGE end,
|
||
getHusbandryFillLevel = function(self, ft) return ft == MILK_OUT and 200000 or ft == FORAGE and 1000 or 0 end,
|
||
getHusbandryFreeCapacity = function(self, ft) return 9999999 end,
|
||
}
|
||
table.insert(g_currentMission.placeableSystem.placeables, feedBarn)
|
||
check("S11b mælk er ikke behov", ADSources.getFarmDemand(adEnv, MILK_OUT, 1, {}).liters, 0)
|
||
check("S11b foder er behov (2000 l/t × 24 − 1000)", ADSources.getFarmDemand(adEnv, FORAGE, 1, {}).liters, 47000)
|
||
-- tom krybbe: foderet kendes fra dyretypens foderdefinition
|
||
feedBarn.spec_husbandryFood.fillLevels = {}
|
||
feedBarn.getHusbandryFillLevel = function(self, ft) return ft == MILK_OUT and 200000 or 0 end
|
||
g_currentMission.animalFoodSystem = {getAnimalFood = function() return {groups = {{fillTypes = {FORAGE}}}} end}
|
||
check("S11b tom krybbe: foder stadig behov", ADSources.getFarmDemand(adEnv, FORAGE, 1, {}).liters, 48000)
|
||
check("S11b tom krybbe: mælk stadig ikke behov", ADSources.getFarmDemand(adEnv, MILK_OUT, 1, {}).liters, 0)
|
||
g_currentMission.animalFoodSystem = nil
|
||
table.remove(g_currentMission.placeableSystem.placeables)
|
||
|
||
-- S12 (inventar): alt gården har liggende, pr. bygning, kun bygninger med indhold
|
||
factory.ownerFarmId = 1; silo.ownerFarmId = 1; objectStorage.ownerFarmId = 1
|
||
local inventory = ADSources.getFarmInventory(adEnv, 1)
|
||
local byName = {}
|
||
for _, entry in ipairs(inventory) do byName[entry.name] = entry end
|
||
check("S12 sukkerfabrik med", byName["Sugar mill"] ~= nil, true)
|
||
check("S12 fabrik-kind", byName["Sugar mill"].kind, "factory")
|
||
check("S12 fabrik sukker", byName["Sugar mill"].entries[1].level, 150000)
|
||
check("S12 fabrik sukker er output", byName["Sugar mill"].entries[1].isOutput, true)
|
||
local beetEntry
|
||
for _, e in ipairs(byName["TMR-fabrik"].entries) do if e.fillType == BEET then beetEntry = e end end
|
||
check("S12 TMR-fabrik roer er input", beetEntry.isOutput, false)
|
||
check("S12 outputs først", byName["TMR-fabrik"].entries[1].isOutput, true)
|
||
check("S12 silo", byName["Farma"].entries[1].fillType, FORAGE)
|
||
check("S12 objektlager kurve som antal", byName["Objektlager"].entries[1].count, 8)
|
||
check("S12 stald halm", byName["Kostald"].entries[1].level, 2000)
|
||
check("S12 stald kapacitet = niveau + fri", byName["Kostald"].entries[1].capacity, 21375)
|
||
check("S12 tomt skur udeladt", byName["Fuldt skur"], nil)
|
||
check("S12 anden farm udeladt", #inventory, 5)
|
||
|
||
-- S13: Wait-markører er hverken kilder eller lagermål, selv om et objektlager står inden for 40 m
|
||
-- (in-game 23/9: 'cow wait 1' blev valgt som palle-lager -> Dragon holdt ved Wait med stropperne af)
|
||
wayPoints[20] = {id = 20, x = 300, z = 275}
|
||
table.insert(markers, {id = 20, markerIndex = #markers + 1, name = "cow wait 1", group = "cow wait"})
|
||
check("S13 Wait-markør er ikke en kilde", ADSources.identify(adEnv, 20, 1), nil)
|
||
local truck2 = {rootNode = {x = 300, z = 270}}
|
||
local store13 = ADSources.findPalletStore(adEnv, truck2, BASKET, {}, function() return true end, 1)
|
||
check("S13 palle-lager = objektlagerets egen markør, ikke Wait", store13.wayPointId, 3)
|
||
|
||
-- S14: stald som kilde — markør ved staldens læssestation (mælketank/gylle); varer = det stationen udleverer
|
||
local MILK = 12
|
||
DESC[MILK] = {index = MILK, name = "MILK", title = "Mælk"}
|
||
local barnLevels = {[MILK] = 4200, [STRAW] = 2000}
|
||
local milkBarn = {
|
||
rootNode = {x = 1500, z = 1500}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Kostald" end,
|
||
getHusbandryFillLevel = function(self, ft) return barnLevels[ft] or 0 end,
|
||
getHusbandryCapacity = function(self, ft) return ft == MILK and 25000 or ft == STRAW and 21375 or 0 end,
|
||
getHusbandryFreeCapacity = function(self, ft) return ft == MILK and 20800 or 0 end,
|
||
getHusbandryIsFillTypeSupported = function(self, ft) return ft == MILK or ft == STRAW end,
|
||
}
|
||
local milkStation = {owningPlaceable = milkBarn, supportedFillTypes = {[MILK] = true}}
|
||
addMarker(10, "cow 1 milk", 1500, 1490); loadAt[10] = milkStation
|
||
local source14 = ADSources.identify(adEnv, 10, 1)
|
||
check("S14 stald", source14.kind, "husbandry")
|
||
check("S14 navn", source14.name, "Kostald")
|
||
local products14 = ADSources.getProducts(adEnv, source14, 1)
|
||
check("S14 én vare (kun det tanken udleverer)", #products14, 1)
|
||
check("S14 mælk", products14[1].fillType, MILK)
|
||
check("S14 niveau", products14[1].level, 4200)
|
||
check("S14 kapacitet", products14[1].capacity, 25000)
|
||
check("S14 bulk", products14[1].isPallet, false)
|
||
check("S14 isPalletAt stald = bulk", ADSources.isPalletAt(source14, MILK), false)
|
||
check("S14 kilde-markør i listen", ADRunsController ~= nil and true or true, true)
|
||
|
||
-- S14b: mælketank-udvidelse (siloExtension) — læssestationen trækker fra stald + tank; niveauet skal
|
||
-- være stationens samlede mængde, ikke kun staldens egen beholder
|
||
milkStation.getAllFillLevels = function(self, farmId) return {[MILK] = 1275 + 136912}, 10025000 end
|
||
local products14b = ADSources.getProducts(adEnv, source14, 1)
|
||
check("S14b stald + udvidelsestank", products14b[1].level, 138187)
|
||
check("S14b tilgængeligt = samlet", products14b[1].available, 138187)
|
||
milkStation.getAllFillLevels = nil
|
||
|
||
-- S14c: mælketank (silo med udvidelses-lager) — tanken selv er tom, puljen via læssestationen har mælken
|
||
local tank = {spec_silo = {storages = {{fillLevels = {}, getCapacity = function() return 10000000 end}}}}
|
||
local tankSource = {kind = "silo", placeable = tank, wayPointId = 999, station = {getAllFillLevels = function() return {[MILK] = 500000}, 70000000 end}}
|
||
local tankProducts = ADSources.getProducts(adEnv, tankSource, 1)
|
||
check("S14c tom tank viser puljens mælk", tankProducts[1] and tankProducts[1].level, 500000)
|
||
check("S14c kapacitet = puljens", tankProducts[1] and tankProducts[1].capacity, 70000000)
|
||
|
||
-- S14d: generelt lager (separatorhal): kilde via læssestationen, varer = stationens niveauer
|
||
local DIGESTATE = 30
|
||
DESC[DIGESTATE] = {index = DIGESTATE, name = "DIGESTATE", title = "Digestat"}
|
||
local separator = {rootNode = {x = 7000, z = 0}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Separator Hall" end, spec_manureSeparator = {}}
|
||
local sepStation = {owningPlaceable = separator, supportedFillTypes = {[DIGESTATE] = true}, getAllFillLevels = function() return {[DIGESTATE] = 42000}, 200000 end}
|
||
addMarker(77, "Digestate pickup", 7000, 10); loadAt[77] = sepStation
|
||
local sepSource = ADSources.identify(adEnv, 77, 1)
|
||
check("S14d separator = lager-kilde", sepSource and sepSource.kind, "storage")
|
||
local sepProducts = sepSource and ADSources.getProducts(adEnv, sepSource, 1) or {}
|
||
check("S14d digestat fra stationen", sepProducts[1] and sepProducts[1].fillType, DIGESTATE)
|
||
check("S14d mængde", sepProducts[1] and sepProducts[1].level, 42000)
|
||
|
||
-- S14e: hønsehus — æg kommer som PALLER fra staldens egen pallespawner (spec_husbandryPallets), ingen
|
||
-- læssestation ved æggene: markøren ved spawneren er en staldkilde, æggene er pallevarer
|
||
local EGGS = 31
|
||
DESC[EGGS] = {index = EGGS, name = "EGG", title = "Æg", isPallet = true}
|
||
local coopSpawner = {spawnPlaces = {{startNode = {x = 8000, z = 0}}}}
|
||
local coop = {rootNode = {x = 8040, z = 0}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Chicken Coop" end,
|
||
getHusbandryFillLevel = function() return 0 end,
|
||
spec_husbandryPallets = {fillTypeIndexToPalletSpawner = {[EGGS] = coopSpawner}, activeFillTypes = {EGGS}, fillLevels = {[EGGS] = 0}, capacities = {[EGGS] = 5000}}}
|
||
table.insert(g_currentMission.placeableSystem.placeables, coop)
|
||
addPallet(EGGS, 1000, 8003, 2); addPallet(EGGS, 1000, 8006, 2); addPallet(EGGS, 800, 8009, 2)
|
||
addMarker(78, "Egg Pickup", 8000, 12)
|
||
local coopSource = ADSources.identify(adEnv, 78, 1)
|
||
check("S14e hønsehus-kilde via pallespawner", coopSource and coopSource.kind, "husbandry")
|
||
local coopProducts = coopSource and ADSources.getProducts(adEnv, coopSource, 1) or {}
|
||
local eggs = nil
|
||
for _, item in ipairs(coopProducts) do if item.fillType == EGGS then eggs = item end end
|
||
check("S14e æg som pallevare", eggs and eggs.isPallet, true)
|
||
check("S14e æg på paller ved spawneren", eggs and eggs.available, 2800)
|
||
check("S14e tre paller", eggs and eggs.palletCount, 3)
|
||
check("S14e isPalletAt æg", coopSource and ADSources.isPalletAt(coopSource, EGGS), true)
|
||
|
||
-- S15: forklaring af en markør til advarslen (hvad opslaget ser)
|
||
check("S15 forklaring stald", ADSources.explainMarker(adEnv, 10, 1), "læssestation ved markøren hører til 'Kostald' (stald)")
|
||
check("S15 forklaring ingen station", ADSources.explainMarker(adEnv, 4, 1), "ingen læssestation ved markøren, og ingen fabrik/objektlager inden for 40 m")
|
||
loadAt[11] = {owningPlaceable = nil}
|
||
wayPoints[11] = {id = 11, x = 2000, z = 2000}; table.insert(markers, {id = 11, markerIndex = #markers + 1, name = "løs", group = "g"})
|
||
check("S15 station uden placeable", ADSources.explainMarker(adEnv, 11, 1), "læssestation ved markøren uden bygning (owningPlaceable = nil)")
|
||
|
||
-- S16: strengt opslag fejler, løst opslag (40 m, uanset retning) finder mælketanken -> stald; en SILO
|
||
-- accepteres aldrig løst (tætte rækker -> nabosilo)
|
||
local looseAt = {}
|
||
ADSmartPickup.getLoadStationNearWayPointId = function(_, id, farmId, maxDistance) return looseAt[id] end
|
||
addMarker(12, "cow 2 milk", 1600, 1600)
|
||
looseAt[12] = milkStation
|
||
check("S16 stald via løst opslag", ADSources.identify(adEnv, 12, 1).kind, "husbandry")
|
||
addMarker(13, "silo løst", 1700, 1700)
|
||
looseAt[13] = siloStation
|
||
check("S16 silo aldrig via løst opslag", ADSources.identify(adEnv, 13, 1), nil)
|
||
check("S16 forklaring nævner den løse station", ADSources.explainMarker(adEnv, 13, 1):find("silo", 1, true) ~= nil, true)
|
||
|
||
-- S17: stald med ÉN station og TO læssepunkter (mælk i den ene ende, gylle i den anden): hver markør
|
||
-- giver kun de varer dens nærmeste læssepunkt udleverer (in-game 24/9, LargerAnimalBarns cowBarnBig)
|
||
local SLURRY = 13
|
||
DESC[SLURRY] = {index = SLURRY, name = "LIQUIDMANURE", title = "Gylle"}
|
||
barnLevels[SLURRY] = 9000
|
||
local twoEndBarn = {
|
||
rootNode = {x = 2500, z = 2500}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Stor kostald" end,
|
||
getHusbandryFillLevel = function(self, ft) return barnLevels[ft] or 0 end,
|
||
getHusbandryCapacity = function() return 25000 end,
|
||
}
|
||
local twoEndStation = {owningPlaceable = twoEndBarn, supportedFillTypes = {[MILK] = true, [SLURRY] = true},
|
||
loadTriggers = {{triggerNode = {x = 2500, z = 2470}, fillTypes = {[MILK] = true}}, {triggerNode = {x = 2500, z = 2530}, fillTypes = {[SLURRY] = true}}}}
|
||
addMarker(40, "Cow Milk", 2500, 2465); loadAt[40] = twoEndStation
|
||
addMarker(41, "Cow Slurry", 2500, 2535); loadAt[41] = twoEndStation
|
||
local milkEnd = ADSources.getProducts(adEnv, ADSources.identify(adEnv, 40, 1), 1)
|
||
check("S17 mælke-enden: én vare", #milkEnd, 1)
|
||
check("S17 mælke-enden: mælk", milkEnd[1].fillType, MILK)
|
||
local slurryEnd = ADSources.getProducts(adEnv, ADSources.identify(adEnv, 41, 1), 1)
|
||
check("S17 gylle-enden: én vare", #slurryEnd, 1)
|
||
check("S17 gylle-enden: gylle", slurryEnd[1].fillType, SLURRY)
|
||
-- læssepunkt uden fillTypes-tabel: stationens varer som før
|
||
twoEndStation.loadTriggers[1].fillTypes = nil
|
||
check("S17 uden punkt-varer: stationens varer", #ADSources.getProducts(adEnv, ADSources.identify(adEnv, 40, 1), 1), 2)
|
||
|
||
-- S18: gårdens forbrug og produktion pr. døgn (fabrikker + stalde) og bedste markedspris
|
||
tmrFactory.spec_productionPoint.productionPoint.getIsProductionEnabled = function(self, id) return id == "tmr3" end
|
||
tmrFactory.spec_productionPoint.productionPoint.productions[1].outputs = {{type = FORAGE, amount = 240}}
|
||
cowBarn.spec_husbandryWater.automaticWaterSupply = false
|
||
local rates = ADSources.getFarmRates(adEnv, 1)
|
||
-- TMR-fabrik: 45 l roer × 200/60 cyklus/min × 1440 = 216.000 l/døgn; TMR ud 240 × 200/60 × 1440 = 1.152.000
|
||
check("S18 roer forbrug", math.floor(rates[BEET].consumption + 0.5), 216000)
|
||
check("S18 TMR produktion", math.floor(rates[FORAGE].production + 0.5), 1152000)
|
||
check("S18 halm i stald 500 l/t", rates[STRAW].consumption, 12000)
|
||
check("S18 vand 100 l/t", rates[WATER].consumption, 2400)
|
||
check("S18 anden farm tæller ikke", rates[STRAW].consumption, 12000)
|
||
-- pris: bedste salgssted der tager varen; top = prisen ved 100 % af kurven
|
||
g_currentMission.storageSystem = {getUnloadingStations = function() return {sellStation, {isa = function() return true end, isSellingPoint = true, owningPlaceable = {}, acceptedFillTypes = {[SUGAR] = true}, getEffectiveFillTypePrice = function() return 2.0 end}} end}
|
||
sellStation.getEffectiveFillTypePrice = function() return 1.5 end
|
||
g_currentMission.environment = {currentPeriod = 1}
|
||
DESC[SUGAR].economy = {factors = {0.8, 1.0}}
|
||
local quote = ADSources.getMarketQuote(SUGAR)
|
||
check("S18 bedste pris", quote.price, 2.0)
|
||
check("S18 top ved 80 % af kurven", quote.top, 2.5)
|
||
check("S18 intet salgssted -> nil", ADSources.getMarketQuote(FORAGE), nil)
|
||
|
||
-- S19: staldenes produktion pr. døgn fra dyrenes output-kurver (liter pr. dyr pr. døgn efter alder)
|
||
local function curve(value) return {get = function(_, age) return age >= 12 and value or 0 end} end
|
||
g_currentMission.animalSystem = {getSubTypeByIndex = function(_, index)
|
||
if index == 1 then return {output = {milk = {fillType = MILK, curve = curve(360)}, liquidManure = curve(500)}} end
|
||
end}
|
||
g_fillTypeManager.getFillTypeIndexByName = function(_, name) for index, desc in pairs(DESC) do if desc.name == name then return index end end end
|
||
local producingBarn = {
|
||
rootNode = {x = 5000, z = 5000}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Malkestald" end,
|
||
getHusbandryFillLevel = function() return 0 end,
|
||
getClusters = function() return {
|
||
{getSubTypeIndex = function() return 1 end, getAge = function() return 24 end, getNumAnimals = function() return 10 end},
|
||
{getSubTypeIndex = function() return 1 end, getAge = function() return 6 end, getNumAnimals = function() return 5 end}, -- kalve: 0
|
||
} end,
|
||
}
|
||
table.insert(g_currentMission.placeableSystem.placeables, producingBarn)
|
||
local rates2 = ADSources.getFarmRates(adEnv, 1)
|
||
check("S19 mælk 10 køer × 360", rates2[MILK].production, 3600)
|
||
check("S19 gylle via navn", rates2[SLURRY].production, 5000)
|
||
|
||
-- S19b: andre dyretyper — høns: æg som "pallets" med fillType-indeks + gødning via navn
|
||
local EGG, MANURE_FT = 21, 22
|
||
DESC[EGG] = {index = EGG, name = "EGG", title = "Æg"}
|
||
DESC[MANURE_FT] = {index = MANURE_FT, name = "MANURE", title = "Gødning"}
|
||
local baseGetSubType = g_currentMission.animalSystem.getSubTypeByIndex
|
||
g_currentMission.animalSystem.getSubTypeByIndex = function(system, index)
|
||
if index == 2 then return {output = {pallets = {fillType = EGG, curve = curve(30)}, manure = curve(10)}} end
|
||
return baseGetSubType(system, index)
|
||
end
|
||
table.insert(g_currentMission.placeableSystem.placeables, {
|
||
rootNode = {x = 6000, z = 6000}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Hønsehus" end,
|
||
getHusbandryFillLevel = function() return 0 end,
|
||
getClusters = function() return {{subTypeIndex = 2, age = 12, numAnimals = 100}} end, -- felter i stedet for metoder
|
||
})
|
||
local rates3 = ADSources.getFarmRates(adEnv, 1)
|
||
check("S19b æg 100 høns × 30", rates3[EGG] and rates3[EGG].production, 3000)
|
||
check("S19b gødning via navn", rates3[MANURE_FT] and rates3[MANURE_FT].production, 1000)
|
||
check("S19b mælk uændret", rates3[MILK].production, 3600)
|
||
|
||
-- S20: statistik tæller kun produktioner der KØRER (ikke "mangler input"/slukket), og rater
|
||
-- ganges med spillets tidsjustering (1 / dage pr. periode)
|
||
ProductionPoint = {PROD_STATUS = {INACTIVE = 0, RUNNING = 1, MISSING_INPUTS = 2}}
|
||
local tmrProduction = tmrFactory.spec_productionPoint.productionPoint.productions[1]
|
||
tmrProduction.status = ProductionPoint.PROD_STATUS.MISSING_INPUTS
|
||
local idle = ADSources.getFarmRates(adEnv, 1)
|
||
check("S20 fabrik der mangler input tæller ikke", idle[FORAGE], nil)
|
||
tmrProduction.status = ProductionPoint.PROD_STATUS.RUNNING
|
||
g_currentMission.environment = {timeAdjustment = 0.5}
|
||
local running = ADSources.getFarmRates(adEnv, 1)
|
||
check("S20 kørende fabrik halveret ved 2 dage/periode", math.floor(running[FORAGE].production + 0.5), 576000)
|
||
check("S20 stald halveret", running[STRAW].consumption, 6000)
|
||
g_currentMission.environment, ProductionPoint = nil, nil
|
||
|
||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||
os.exit(failures == 0 and 0 or 1)
|