-- 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) -- 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 -- 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)