feat: v1.12.1.0 — prisregel via sæsonkurven, reserve til gårdens eget forbrug, paller til palleskur, fanen Lagre (idéer fra Distribution Redux)
This commit is contained in:
@@ -394,6 +394,25 @@ ADOutbound.beforeLoadUpdate(adEnv, task16, 100)
|
||||
ADOutbound.beforeLoadUpdate(adEnv, task16, 100)
|
||||
check("O16 næste spawn via fyldniveau", sources[3].spawnCalls, 2)
|
||||
|
||||
-- O17 (reserve + paller til lager): buildPlanInput henter reserve og palle-lager fra ADSources
|
||||
local demandCalls = {}
|
||||
ADSources.getFarmDemand = function(_, ft, farmId, excluded) table.insert(demandCalls, ft) return {liters = ft == SUGAR and 4000 or 0, consumers = {"TMR-fabrik"}} end
|
||||
local palletStoreMarker = nil
|
||||
ADSources.findPalletStore = function(_, vehicle, ft, excluded, isReachable, farmId) return palletStoreMarker end
|
||||
local v17 = newVehicle("Reserve", 0, 0, 20000)
|
||||
runs[v17] = outboundRun(17, {1}, {{fillType = "SUGAR", policy = "sell"}})
|
||||
local input17 = ADOutbound.buildPlanInput(adEnv, runs[v17], v17)
|
||||
check("O17 reserve på salgsvare", input17.products[1].reserve, 4000)
|
||||
check("O17 reserveret til", input17.products[1].reservedFor[1], "TMR-fabrik")
|
||||
local v18 = newVehicle("PalletStore", 100, 0, 8000, true)
|
||||
runs[v18] = outboundRun(18, {3}, {{fillType = "STRAW_BASKET", policy = "store"}})
|
||||
palletStoreMarker = {wayPointId = 40, name = "Palleskur", free = 100}
|
||||
sources[3].stored[BASKET] = 4
|
||||
products[3][1].available, products[3][1].level, products[3][1].capacity = 4000, 3900, 4000
|
||||
local input18 = ADOutbound.buildPlanInput(adEnv, runs[v18], v18)
|
||||
check("O18 palle-lager som store-mål", input18.products[1].store ~= nil and input18.products[1].store.wayPointId, 40)
|
||||
check("O18 reserve spørges ikke for lager-politik", demandCalls[#demandCalls] ~= BASKET, true)
|
||||
|
||||
-- O10: install wrapper: fejl i hook stopper ikke AD
|
||||
local calls = {}
|
||||
adEnv.LoadAtDestinationTask.update = function(self, dt) calls.update = (calls.update or 0) + 1 end
|
||||
|
||||
@@ -109,5 +109,26 @@ check("P12 storageHigh", e.storageHigh, true)
|
||||
check("P12 fullLoad", e.fullLoad, true)
|
||||
check("P12 priceOk", e.priceOk, true)
|
||||
|
||||
-- P13 (reserve): det gårdens fabrikker/stalde skal bruge, sælges ikke
|
||||
local BEET = 10
|
||||
local withReserve = product("SUGARBEET", BEET, "sell", {{wayPointId = 3, available = 268000, level = 268000, capacity = 12000000}}, quoteS, nil)
|
||||
withReserve.reserve, withReserve.reservedFor = 196000, {"TMR-fabrik"}
|
||||
local trip13 = P.plan(input({withReserve}))
|
||||
check("P13 fuldt læs uden om reserven -> salg", trip13 ~= nil and trip13.kind, "sell")
|
||||
withReserve.reserve = 260000 -- kun 8.000 til overs: mindre end et læs
|
||||
local trip13b, reasons13b = P.plan(input({withReserve}))
|
||||
check("P13 reserven ville blive rørt -> ingen tur", trip13b, nil)
|
||||
check("P13 begrundelse", reasons13b[1], "SUGARBEET: 260.0k reserveret til TMR-fabrik")
|
||||
withReserve.reserve = 300000 -- alt reserveret
|
||||
check("P13 alt reserveret -> ingen tur", P.plan(input({withReserve})), nil)
|
||||
withReserve.reserve = 0
|
||||
check("P13 reserve 0 -> salg uanset mængde", P.plan(input({withReserve})).kind, "sell")
|
||||
-- lager-politik ignorerer reserven (varen bliver på gården)
|
||||
local storeReserve = product("SUGARBEET", BEET, "store", {{wayPointId = 3, available = 268000, level = 11000000, capacity = 12000000}}, nil, storeSilo)
|
||||
storeReserve.reserve = 300000
|
||||
check("P13 lager rører ikke reserven", P.plan(input({storeReserve})).kind, "store")
|
||||
local e13 = P.evaluate(withReserve, input({}, {capacity = 20000}))
|
||||
check("P13 evaluate sellable", e13.sellable, 268000)
|
||||
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
|
||||
+16
-4
@@ -42,17 +42,29 @@ local station = {
|
||||
}
|
||||
local quote = ADPrices.getQuote(station, SUGAR)
|
||||
check("P4 pris", quote.price, 470)
|
||||
check("P4 top", quote.top, 625)
|
||||
check("P4 top (pris ved 100 %)", math.floor(quote.top + 0.5), 627)
|
||||
check("P4 procent", quote.percent, 75)
|
||||
check("P4 er salgssted", ADPrices.isSellingStation(station), true)
|
||||
check("P4 skjult = ikke salgssted", ADPrices.isSellingStation({isa = function() return true end, isSellingPoint = true, hideFromPricesMenu = true}), false)
|
||||
check("P4 fabrik-station = ikke salgssted", ADPrices.isSellingStation({isa = function() return true end, isSellingPoint = false}), false)
|
||||
|
||||
-- P5: uden stationens grundpris: pricePerLiter × faktor nu × sværhedsgrad
|
||||
-- P5: uden stationens grundpris: kun kurven tæller (faktor nu ÷ faktor max)
|
||||
local bare = {getEffectiveFillTypePrice = function() return 470 end}
|
||||
local quote2 = ADPrices.getQuote(bare, SUGAR)
|
||||
check("P5 top fra pricePerLiter", quote2.top, 500)
|
||||
check("P5 procent", quote2.percent, 94)
|
||||
check("P5 procent = kurven alene", quote2.percent, 80)
|
||||
check("P5 top = effektiv ÷ kurve", math.floor(quote2.top + 0.5), 588)
|
||||
-- P7: kurven er grundlaget (Distribution Redux-metoden): faktor nu ÷ årets max, uafhængigt af sværhedsgrad
|
||||
check("P7 curvePercent", ADPrices.curvePercent({1.0, 1.25, 0.9}, 1), 80)
|
||||
check("P7 curvePercent ved top", ADPrices.curvePercent({1.0, 1.25, 0.9}, 2), 100)
|
||||
check("P7 flad kurve = 100", ADPrices.curvePercent({1.0, 1.01, 1.0}, 3), 100)
|
||||
check("P7 ingen kurve = 100", ADPrices.curvePercent(nil, 1), 100)
|
||||
check("P7 ukendt periode = 100", ADPrices.curvePercent({1.0, 1.25}, nil), 100)
|
||||
-- P8: stor efterspørgsel ganger stationens egen faktor på: 500 grundpris, 700 effektiv, kurve 80 % -> 112
|
||||
local demandStation = {fillTypePrices = {[SUGAR] = 500}, getEffectiveFillTypePrice = function() return 700 end}
|
||||
check("P8 stor efterspørgsel > 100", ADPrices.getQuote(demandStation, SUGAR).percent, 112)
|
||||
-- P9: sværhedsgraden påvirker ikke procenten (begge priser skaleres ens)
|
||||
local hardStation = {fillTypePrices = {[SUGAR] = 250}, getEffectiveFillTypePrice = function() return 235 end}
|
||||
check("P9 uafhængig af sværhedsgrad", ADPrices.getQuote(hardStation, SUGAR).percent, 75)
|
||||
check("P5 fejlende station -> nil", ADPrices.getQuote({getEffectiveFillTypePrice = function() error("x") end}, SUGAR), nil)
|
||||
|
||||
-- P6: bedste tilbud = højeste procent, dernæst pris
|
||||
|
||||
@@ -199,5 +199,82 @@ check("S9 fabrik foretrækkes frem for objektlager i nærheden", ADSources.ident
|
||||
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)
|
||||
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
|
||||
Reference in New Issue
Block a user