fix(bygninger): markørnavn afgør mellem tætte markører (Pickup til pålæsning, Unload til aflæsning) (v1.61.11.0)

This commit is contained in:
2026-09-30 18:19:31 +02:00
parent c92c870297
commit 6b533e62eb
3 changed files with 46 additions and 3 deletions
+44 -2
View File
@@ -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