diff --git a/CHANGELOG.md b/CHANGELOG.md index 81cd2e7..b3b5f4b 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.62 — Kæder slås selv til +- **1.62.7** Nyt: konsolkommandoen `spuSellBlock` slår salgssteder fra og til (pr. savegame). Et salgssted, der er slået fra, bruges hverken til udkørsel eller i priserne. Til stationer, hvor aflæsningen går i stå, fx "Market Price Liquid Fill Station". - **1.62.6** Pålæsningsdiagnosen logger kun, når en trigger med varen er inden for 20 m (køretøjer der holder ved Wait-punkter eller marker gav falske meldinger). - Manualerne understreger nu, at parkering og hentning af redskaber kun virker ved at bakke: ruten til `P ` og `Connect P ` skal slutte som en bakrute. - **1.62.5** Diagnose: står AutoDrive 30 s ved et LOAD-mål uden at fylde, skriver loggen én linje med markør, vare og for hver vogn den nærmeste AD-læssetrigger (afstand, har varen, står vognen i triggerens boks). Ingen indgreb. diff --git a/FS25_ADSmartPickup/adRunsController.lua b/FS25_ADSmartPickup/adRunsController.lua index 5f61ded..b639c0d 100644 --- a/FS25_ADSmartPickup/adRunsController.lua +++ b/FS25_ADSmartPickup/adRunsController.lua @@ -1478,6 +1478,7 @@ function ADRunsController.save() if ADFieldSilos ~= nil then pcall(ADFieldSilos.save) end -- kædens tilstand (tændte mellemled, pausede kæder, afviste forslag) — samme gem-regel som navnefilen if ADChain ~= nil and ADChain.save ~= nil then pcall(ADChain.save) end + if ADSellBlock ~= nil and ADSellBlock.save ~= nil then pcall(ADSellBlock.save) end -- navnefilen skal skrives under spillets gem: FS25 genskriver savegame-mappen, og filer ingen skriver -- under gemningen forsvinder (in-game 27/9: ADSmartPickup_names.xml blev slettet ved første gem) if ADNames ~= nil and ADNames.byId ~= nil then pcall(ADNames.save) end @@ -1498,6 +1499,7 @@ function ADRunsController.load(adEnv) pcall(ADRunsController.migrateBuildings, adEnv) if ADFieldSilos ~= nil then pcall(ADFieldSilos.load) end if ADChain ~= nil and ADChain.load ~= nil then pcall(ADChain.load) end + if ADSellBlock ~= nil and ADSellBlock.load ~= nil then pcall(ADSellBlock.load) end if ADCpResume ~= nil then pcall(ADCpResume.load) end local vehiclesById = getFarmVehiclesById(adEnv) for _, run in ipairs(store.runs) do diff --git a/FS25_ADSmartPickup/adSellBlock.lua b/FS25_ADSmartPickup/adSellBlock.lua new file mode 100644 index 0000000..813f2bf --- /dev/null +++ b/FS25_ADSmartPickup/adSellBlock.lua @@ -0,0 +1,154 @@ +-- AD Sell Block +-- Salgssteder spilleren har slået fra (in-game 30/9: "Market Price Liquid Fill Station" fra FarmFillStations gik i stå +-- ved aflæsning af gylle). Konsol: spuSellBlock viser salgsstederne; spuSellBlock slår dem fra/til. +-- Udkørsel (ADSources.findSellMarkers) og priser (ADSources.getMarketQuote) springer udelukkede over. Gemmes pr. +-- savegame i ADSmartPickup_sellblock.xml (skrives fra ADRunsController.save, som de andre filer). + +ADSellBlock = {} +ADSellBlock.FILE_NAME = "ADSmartPickup_sellblock.xml" +ADSellBlock.ROOT = "sellBlock" +ADSellBlock.blocked = {} -- {[stationId] = visningsnavn} + +-- ---- ren logik ---- + +-- stations = {{id, names = {...}}}, query = del af et navn (små/store bogstaver ligegyldige) -> matchende stationer +function ADSellBlock.match(stations, query) + local wanted = string.lower(tostring(query or "")) + local hits = {} + if wanted == "" then return hits end + for _, station in ipairs(stations or {}) do + for _, name in ipairs(station.names or {}) do + if string.find(string.lower(tostring(name)), wanted, 1, true) ~= nil then + table.insert(hits, station) + break + end + end + end + return hits +end + +-- Ny tabel: hver station skiftes (fra -> til, til -> fra). Første navn huskes til visning. +function ADSellBlock.toggle(blocked, stations) + local result = {} + for id, name in pairs(blocked or {}) do result[id] = name end + for _, station in ipairs(stations or {}) do + if result[station.id] ~= nil then + result[station.id] = nil + else + result[station.id] = tostring((station.names or {})[1] or station.id) + end + end + return result +end + +-- ---- spil ---- + +local function stationId(station) + local placeable = station ~= nil and station.owningPlaceable or nil + if placeable ~= nil and placeable.uniqueId ~= nil then return tostring(placeable.uniqueId) end + return nil +end + +function ADSellBlock.isBlocked(station) + local id = stationId(station) + return id ~= nil and ADSellBlock.blocked[id] ~= nil +end + +local function stationNames(station) + local names = {} + local placeable = station.owningPlaceable + if placeable ~= nil and placeable.getName ~= nil then + local ok, name = pcall(placeable.getName, placeable) + if ok and name ~= nil then table.insert(names, name) end + end + if station.getName ~= nil then + local ok, name = pcall(station.getName, station) + if ok and name ~= nil then table.insert(names, name) end + end + return names +end + +-- Alle salgssteder med AD-markør -> {{id, names}} (markørens navn først: det spilleren ser i AutoDrive). +local function sellStations(adEnv) + local list, byId = {}, {} + local farmId = g_currentMission:getFarmId() + for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do + local station = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId) + local id = station ~= nil and ADPrices.isSellingStation(station) and stationId(station) or nil + if id ~= nil then + if byId[id] == nil then + byId[id] = {id = id, names = {}} + table.insert(list, byId[id]) + for _, name in ipairs(stationNames(station)) do table.insert(byId[id].names, name) end + end + table.insert(byId[id].names, 1, marker.name) + end + end + table.sort(list, function(a, b) return tostring(a.names[1]) < tostring(b.names[1]) end) + return list +end + +function ADSellBlock:consoleSellBlock(...) + local query = table.concat({...}, " ") + local adEnv = FS25_AutoDrive + if adEnv == nil or adEnv.ADGraphManager == nil then return "AutoDrive ikke fundet" end + local stations = sellStations(adEnv) + if query == "" then + local lines = {"Salgssteder (spuSellBlock slår fra/til):"} + for _, station in ipairs(stations) do + table.insert(lines, string.format(" %s %s", ADSellBlock.blocked[station.id] ~= nil and "[FRA]" or "[til]", table.concat(station.names, " / "))) + end + return table.concat(lines, "\n") + end + local hits = ADSellBlock.match(stations, query) + if #hits == 0 then return string.format("Intet salgssted matcher '%s' (spuSellBlock uden navn viser listen)", query) end + ADSellBlock.blocked = ADSellBlock.toggle(ADSellBlock.blocked, hits) + local lines = {} + for _, station in ipairs(hits) do + local text = string.format("%s: %s", station.names[1], ADSellBlock.blocked[station.id] ~= nil and "slået FRA som salgssted" or "bruges igen") + table.insert(lines, text) + Logging.info("ADSmartPickup: salgssted " .. text) + end + if ADRunsController ~= nil and ADRunsController.save ~= nil then pcall(ADRunsController.save) end + return table.concat(lines, "\n") +end + +local function getPath() + local path = ADRunsStorage ~= nil and ADRunsStorage.getPath() or nil + if path == nil then return nil end + return (path:gsub(ADRunsStorage.FILE_NAME .. "$", ADSellBlock.FILE_NAME)) +end + +function ADSellBlock.save() + local path = getPath() + if path == nil then return false end + local xmlFile = XMLFile.create("ADSmartPickupSellBlock", path, ADSellBlock.ROOT) + if xmlFile == nil then return false end + local index = 0 + for id, name in pairs(ADSellBlock.blocked) do + local key = string.format("%s.station(%d)", ADSellBlock.ROOT, index) + xmlFile:setString(key .. "#id", id) + xmlFile:setString(key .. "#name", name) + index = index + 1 + end + xmlFile:save() + xmlFile:delete() + return true +end + +function ADSellBlock.load() + ADSellBlock.blocked = {} + local path = getPath() + if path == nil or not fileExists(path) then return end + local xmlFile = XMLFile.load("ADSmartPickupSellBlock", path) + if xmlFile == nil then return end + xmlFile:iterate(ADSellBlock.ROOT .. ".station", function(_, key) + local id = xmlFile:getString(key .. "#id") + if id ~= nil then ADSellBlock.blocked[id] = xmlFile:getString(key .. "#name") or id end + end) + xmlFile:delete() +end + +if addConsoleCommand ~= nil then + addConsoleCommand("spuSellBlock", "Salgssteder: uden navn = liste; spuSellBlock slår fra/til", "consoleSellBlock", ADSellBlock) +end diff --git a/FS25_ADSmartPickup/adSources.lua b/FS25_ADSmartPickup/adSources.lua index 4967052..a515dda 100644 --- a/FS25_ADSmartPickup/adSources.lua +++ b/FS25_ADSmartPickup/adSources.lua @@ -644,7 +644,12 @@ function ADSources.describeAccepted(station) return table.concat(names, ", ") end --- Markører hvis aflæsningsstation er et rigtigt salgssted: { {marker, station} }. +-- Salgssted spilleren har slået fra (spuSellBlock, ADSellBlock). +function ADSources.isSellBlocked(station) + return ADSellBlock ~= nil and ADSellBlock.isBlocked ~= nil and ADSellBlock.isBlocked(station) == true +end + +-- Markører hvis aflæsningsstation er et rigtigt salgssted (og ikke slået fra): { {marker, station} }. function ADSources.getSellMarkers(adEnv, farmId) return cacheGet("sellMarkers", tostring(farmId), 10000, function() return ADSources.findSellMarkers(adEnv, farmId) end) end @@ -653,7 +658,7 @@ function ADSources.findSellMarkers(adEnv, farmId) local result = {} for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do local station = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId) - if station ~= nil and ADPrices.isSellingStation(station) then + if station ~= nil and ADPrices.isSellingStation(station) and not ADSources.isSellBlocked(station) then table.insert(result, {marker = marker, station = station}) end end @@ -1002,7 +1007,7 @@ function ADSources.getMarketQuote(fillType) local storage = g_currentMission ~= nil and g_currentMission.storageSystem or nil local best = nil for _, station in pairs(storage ~= nil and storage:getUnloadingStations() or {}) do - if ADPrices.isSellingStation(station) and ADSources.stationAccepts(station, fillType) then + if ADPrices.isSellingStation(station) and not ADSources.isSellBlocked(station) and ADSources.stationAccepts(station, fillType) then local quote = ADPrices.getQuote(station, fillType) if quote ~= nil and (best == nil or quote.price > best.price) then best = {price = quote.price, top = quote.top} diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 82affa2..8c69ecb 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.62.6.0 + 1.62.7.0 <en>AD Smart Pickup</en> @@ -33,6 +33,7 @@ + diff --git a/docs/BRUGERMANUAL.md b/docs/BRUGERMANUAL.md index d9a6ca8..324d425 100644 --- a/docs/BRUGERMANUAL.md +++ b/docs/BRUGERMANUAL.md @@ -1206,6 +1206,7 @@ FS25 kan ikke selv omdøbe bygninger, så moden har sine egne navne. De gemmes i | `spuNameFleet` | Giver alle traktorer og lastbiler uden for flows butiksnavnet (*Fendt 942 1*, *Fendt 942 2* …) og omdøber deres egen parkering til `P `, hvis ingen anden deler den. Overskriver egne navne på de køretøjer. Gem spillet bagefter. Pas på: en eksisterende `Connect `-markør passer ikke længere | | `spuConnect` | Kobler det nærmeste redskab (inden for ca. 3 m) på den maskine, du sidder i | | `spuDetach` | Kobler redskaberne bag den maskine, du sidder i, af | +| `spuSellBlock [del af navn]` | Uden navn: viser alle salgssteder, og hvilke der er slået fra. Med navn: slår de salgssteder fra/til, hvis navn indeholder teksten (fx `spuSellBlock market price`). Et salgssted, der er slået fra, bruges hverken til udkørsel eller i priserne. Gemmes pr. savegame. Til salgssteder, hvor aflæsningen går i stå | | `spuTrip A > B > C` | Kører en tur over flere markører: Connect-markører kobler på, Afkobl eller redskabets egen parkering kobler af, og ved andre markører holdes der 10 sekunder. Mest til test | --- diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index a7b9773..4812b76 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -1244,6 +1244,7 @@ Open the game's console to use them: | `spuNameFleet` | Gives all tractors and trucks outside flows their shop name (*Fendt 942 1*, *Fendt 942 2* …) and renames their own parking spot to `P ` if nobody else shares it. Overwrites custom names on those vehicles. Save the game afterwards. Note: an existing `Connect ` marker no longer matches | | `spuConnect` | Hitches the nearest implement (within about 3 m) to the machine you are sitting in | | `spuDetach` | Detaches the implements behind the machine you are sitting in | +| `spuSellBlock [part of name]` | Without a name: lists all selling points and which ones are switched off. With a name: switches off/on the selling points whose name contains the text (e.g. `spuSellBlock market price`). A switched-off selling point is used neither for outbound trips nor in prices. Saved per savegame. For selling points where unloading keeps stalling | | `spuTrip A > B > C` | Drives a trip over several markers: Connect markers hitch, Afkobl or the implement's own parking detach, and at other markers it stops for 10 seconds. Mostly for testing | ---