diff --git a/CHANGELOG.md b/CHANGELOG.md index 743a279..7d3ce02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ står i [docs/BRUGERMANUAL.md](docs/BRUGERMANUAL.md) (dansk) og [docs/USER_MANUA ## 1.61 — Produktionskæder +- **1.61.11** Markørvalg ved bygninger: når to markører står inden for 20 m af hinanden, afgør navnet — pålæsning foretrækker *Pickup/Hent/Læs/Load*, aflæsning *Unload/Drop/Aflæs*. Før vandt den nærmeste (Sell Egg kørte til "Chicken Storage Unload" i stedet for "Egg Storage Pickup"). - **1.61.10** Markflådens puljeliste viser korte maskinnavne (uden " Unrealistic" og parenteser som "(+ Custom Crops)"), så lange linjer ikke ombrydes med traktorens nummer alene på næste linje. - **1.61.9** *Sælg fra* i udkørselsflows har valget **Altid (uanset pris)** øverst: flowet sælger, så snart der er noget at køre med, uden at vente på en god pris. Resumé og status viser *sælg altid*. - **1.61.8** Kæderne regner **læs i vogne og høstertanke** med som lager (afgrøder og markvarer), og der kommer ingen forslag eller automatiske markskift for en afgrøde, mens den høstes. Klik på en varelinje i fanen **Kæder** åbner flowet, der kører varen, i redigeringsvinduet (så en stoppet kæde kan få traktor og vogn). diff --git a/FS25_ADSmartPickup/adBuildings.lua b/FS25_ADSmartPickup/adBuildings.lua index 2cc741f..94417c6 100644 --- a/FS25_ADSmartPickup/adBuildings.lua +++ b/FS25_ADSmartPickup/adBuildings.lua @@ -251,12 +251,43 @@ local function markerCandidates(adEnv, nodes) return found end +-- Markørnavnets rolle: "unload" (unload/drop/aflæs/aflever/indkast/tip) eller "load" (pickup/hent/læs/load) — +-- aflæsning tjekkes først ("unload" og "aflæs" indeholder "load"/"læs"). nil = neutralt navn. +local UNLOAD_WORDS = {"unload", "drop", "aflæs", "aflev", "indkast", "tip"} +local LOAD_WORDS = {"pickup", "pick up", "hent", "læs", "load"} +function ADBuildings.nameRole(name) + local lower = tostring(name or ""):lower() + for _, word in ipairs(UNLOAD_WORDS) do if lower:find(word, 1, true) then return "unload" end end + for _, word in ipairs(LOAD_WORDS) do if lower:find(word, 1, true) then return "load" end end + return nil +end + +-- Når to markører står tæt (inden for NAME_WINDOW_M af den nærmeste), afgør navnet: den første med den ønskede rolle +-- flyttes forrest. Ellers urørt (nærmeste først). (in-game 30/9: Sell Egg tog "Chicken Storage Unload" 17 m frem for +-- "Egg Storage Pickup" 27 m ved Æglageret) +ADBuildings.NAME_WINDOW_M = 20 +function ADBuildings.preferByName(candidates, wantRole) + local list = candidates or {} + if #list < 2 then return list end + local limit = (list[1].distance or 0) + ADBuildings.NAME_WINDOW_M + if ADBuildings.nameRole(list[1].name) == wantRole then return list end + for index, candidate in ipairs(list) do + if (candidate.distance or math.huge) > limit then break end + if ADBuildings.nameRole(candidate.name) == wantRole then + local reordered = {candidate} + for other, item in ipairs(list) do if other ~= index then table.insert(reordered, item) end end + return reordered + end + end + return list +end + -- Læssemarkør for én læssegruppe. En pallespawner (upræcist startpunkt) får aldrig aflæsningens nærmeste markør — -- den tager sin næstnærmeste. Rigtige læssetriggere beholder markøren (Sugarbeet Crusher: pickup står tættere på -- aflæsningstriggeren end drop). Gælder alle bygningstyper. (in-game 27/9 fårestald: spawner 9 m fra "Sheep Food", -- foderindkast 5 m -> Goat Food fik "Sheep Milk"; i stald 3 og 5 stod spawneren endda tættest, 5 mod 9 m) function ADBuildings.pickLoadMarker(candidates, unloadBest, yieldsToUnload) - for _, candidate in ipairs(candidates or {}) do + for _, candidate in ipairs(ADBuildings.preferByName(candidates, "load")) do local isUnloads = yieldsToUnload and unloadBest ~= nil and candidate.id == unloadBest.id if not isUnloads then return {id = candidate.id, name = candidate.name, distance = math.floor(candidate.distance + 0.5)} @@ -314,7 +345,7 @@ local function unloadMarkerFor(adEnv, nodes, loadMarkers, allowSkipLoad) local x, z = getNodePosition(node) if x ~= nil then table.insert(positions, {x = x, z = z}) end end - local best, bestOther = nil, nil + local best, bestOther, nearbyAll = nil, nil, {} for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do if not ADSupplyPlanner.isWaitMarker(marker) then local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id) @@ -323,6 +354,7 @@ local function unloadMarkerFor(adEnv, nodes, loadMarkers, allowSkipLoad) local dx, dz = wayPoint.x - position.x, wayPoint.z - position.z local distance = math.sqrt(dx * dx + dz * dz) if distance < ADBuildings.MAX_MARKER_DISTANCE then + table.insert(nearbyAll, {marker = marker, distance = distance}) if best == nil or distance < best.distance then best = {marker = marker, distance = distance} end if not isLoad[marker.id] and (bestOther == nil or distance < bestOther.distance) then bestOther = {marker = marker, distance = distance} @@ -338,6 +370,16 @@ local function unloadMarkerFor(adEnv, nodes, loadMarkers, allowSkipLoad) if allowSkipLoad and bestOther ~= nil and bestOther.distance <= ADBuildings.MAX_DROP_DISTANCE then chosen = bestOther end + -- navnet afgør mellem tætte markører: en "Unload/Drop"-markør frem for en "Pickup"-markør (in-game 30/9) + table.sort(nearbyAll, function(a, b) return a.distance < b.distance end) + if chosen ~= nil and ADBuildings.nameRole(chosen.marker.name) == "load" then + for _, entry in ipairs(nearbyAll) do + if entry.distance <= chosen.distance + ADBuildings.NAME_WINDOW_M and ADBuildings.nameRole(entry.marker.name) == "unload" then + chosen = entry + break + end + end + end if chosen == nil then return nil end diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 1f74be0..17ee958 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.61.10.0 + 1.61.11.0 <en>AD Smart Pickup</en>