feat(gui): guiden "Opsæt mark" — markfanen får oversigt med resumé (klik på en linje = ret ét trin), trin-for-trin-guide på fælles guide-ramme (ADGuide/ADFieldGuide) og egen markflåde-visning (v1.31.0.0)

This commit is contained in:
2026-09-26 20:20:56 +02:00
parent 7cbd8fb878
commit 92af260a79
17 changed files with 1953 additions and 329 deletions
+45 -21
View File
@@ -540,7 +540,7 @@ maskiner. Kræver **Courseplay** ud over AutoDrive.
### Vælg og glem: afgrøde på marken
Det nemmeste: vælg **Afgrøde på marken** (fx *Hvede*) øverst under marken. Så passer moden resten:
Det nemmeste: vælg en afgrøde (fx *Hvede*) i guidens trin **Afgrøde** (Opsæt mark). Så passer moden resten:
- **Vokser der noget nu**, får det lov at vokse færdig, bliver passet (gødning, ukrudt, kalk) og høstet
eller slået, når det er klart.
@@ -550,9 +550,8 @@ Det nemmeste: vælg **Afgrøde på marken** (fx *Hvede*) øverst under marken. S
- **Bar mark:** klargøres og tilsås, så snart det er såtid.
- Derefter kører cyklussen af sig selv: vækst → pleje → høst → klargøring → såning → …
Med en afgrøde valgt kører marken automatisk. Linjen under valget fortæller, hvad moden vil gøre. Du kan
stadig vælge ensilage/hø, halm, antal maskiner, jordbehandling og pleje. Vælg *Ingen — planlæg selv* for
at styre marken manuelt som før.
Med en afgrøde valgt kører marken automatisk. Du kan stadig vælge ensilage/hø, halm, antal maskiner,
jordbehandling og pleje i de næste trin. Vælg *Behold det der gror* for at styre marken som før.
### Opsætning
@@ -560,7 +559,7 @@ at styre marken manuelt som før.
`F109`. Maskinerne kører dertil ad vejen, før Courseplay tager over. Højst 400 m fra marken. Mangler
den, står marken med `!` og sendes ikke ud.
2. **Faste sæt.** Redskabet skal sidde på traktoren (eller være selvkørende). Moden kobler aldrig på.
3. **Markflåde.** Nederst på fanen står alle køretøjer med et markredskab, med rolle og bredde. Med
3. **Markflåde.** Knappen **Markflåde** viser alle køretøjer med et markredskab, med rolle og bredde. Med
**Brug alle ledige maskiner** = Ja (standard) finder moden selv maskinerne; med Nej bruges kun dem med
flueben. Køretøjer i et flow, køretøjer AutoDrive/Courseplay allerede kører,
og køretøjer du selv kører, bruges aldrig. En sprøjte/spreder har først en rolle, når den har fyld på
@@ -579,25 +578,50 @@ at styre marken manuelt som før.
### En mark
Klik på en mark i tabellen. Under tabellen står:
Klik på en mark i tabellen. Under tabellen står markens **resumé** — én linje pr. emne:
| Valg | Betydning |
| Linje | Eksempel |
|---|---|
| **Kørsel** | *Manuel*: marken venter på **Start nu**. *Auto*: den starter selv, når den er klar eller trænger til pleje |
| **Maskiner pr. trin** | 1–5 sæt samtidig (Courseplays multi-tool). Et trin starter først når alle sæt er ledige |
| **Plan** (slåafgrøde) | Ensilage eller Hø |
| **Riv** (slåafgrøde) | Riv skårene sammen før opsamling |
| **Aflæsningsvogne** (høst) | 1–3 vogne der følger høsteren og kører til lager |
| **Halm efter høst** (høst) | Hakkes (spredes), Samles op til silo, eller Presses til baller, som en ballesamler kører til et ballelager |
| **Stubbehakning** | Hak stubben efter høst |
| **Jordbehandling** | Auto (pløj når jorden trænger, ellers kultivér), Kultivér, Pløj eller Ingen |
| **Så bagefter** + **Afgrøde at så** | Så efter jordbehandlingen. Standard: samme afgrøde som blev høstet |
| **Tromle** | Tromle efter såning |
| **Gød / Kalk / Bekæmp ukrudt** | Pleje mens afgrøden vokser, når jorden trænger (højst to gange pr. pleje pr. vækst) |
| **Tving lager** | Vælg lagre. Uden valg: ensilage → nærmeste gæringssilo, ellers silo; hø og høst → nærmeste silo |
| **Afgrøde** | *Behold det der gror* / *-> Hvede* |
| **Afgrødens valg** | *Ensilage, river* / *halm hakkes* |
| **Klargøring** | *Automatisk* / *Pløj, kalk* |
| **Pleje** | *gødning, ukrudt* |
| **Maskiner** | *3 faste* / *ledige maskiner*, *1 ad gangen*, *1 aflæsningsvogne* |
| **Lager** | *Marksilo* / *Automatisk* / en valgt silo |
Under valgene står **Jorden trænger til** (kalk, pløjning, gødning, ukrudt), markøren og evt. slåbredde og
skår-forskydning.
**Klik på en linje** for at rette netop det (fx lageret): kun det ene trin åbnes, og **Gem** gemmer og går
tilbage. Under resuméet står hele statusteksten og markøren.
Bundknapperne: **Start nu / Stop mark**, **Opsæt mark** og **Markflåde**.
### Guiden "Opsæt mark"
**Opsæt mark** sætter marken op med ét spørgsmål ad gangen ("Trin 3 af 7 — …"). Trin, der ikke passer
til marken, springes over; en opsat mark åbner med de nuværende valg. Uden valgt mark vælger du først marken.
| Trin | Vises når | Valg |
|---|---|---|
| **Afgrøde** | altid | *Behold det der gror* eller en afgrøde at så (mål-afgrøde, se ovenfor). Høst-/bar mark: *Så samme afgrøde igen efter høst* |
| **Afgrødens valg** | slåafgrøde (nu eller som mål): Ensilage/Hø + Riv. Høstafgrøde med halm: Halm hakkes/samles/presses | |
| **Klargøring** | efter høst / bar mark / skift af afgrøde | *Automatisk (anbefalet)* eller *Vælg selv*: jordbehandling, kalk, stubhakning, tromle |
| **Pleje** | afgrøde der gror | Gødning, ukrudt (ikke på slåafgrøder); kalk her, når der ingen klargøring er |
| **Maskiner** | altid | Antal ad gangen (1–5), aflæsningsvogne ved høst (1–3), **Faste maskiner til marken?** + listen |
| **Lager** | høst/slåning | *Brug marksiloen?* (når der er en), ellers *Automatisk* eller *Vælg selv* blandt de 8 nærmeste |
| **Oversigt** | altid | Resuméet; klik på en linje for at rette. **Kør automatisk** (Auto) eller **Gem uden at starte** (Manuel) |
Knapperne: **Næste**, **Tilbage**, **Annullér**. Intet gemmes før **Kør automatisk** / **Gem uden at starte**
(eller **Gem** ved ret af én linje). Lukkes menuen, eller skifter du fane, kasseres guiden. Med en
mål-afgrøde kører marken altid automatisk. Mangler markøren, kan marken sættes op; arbejdet venter på markøren.
**Faste maskiner:** en fast maskine bruges kun på denne mark, og marken venter på sin egen hellere end at
låne en anden. Listen viser kun ledige maskiner og dem der allerede er faste her; maskiner der er faste på
andre marker står som "N maskiner er faste på andre marker (F22)".
**Markflåde** (knap): den fælles markflåde — *Brug alle ledige maskiner* og listen med flueben, "fast på
F22", "i gang på F108" og bredde-advarsler. **Til marker** går tilbage.
Moden spørger aldrig om: scanning, hvornår der høstes/slås/gødes/sprøjtes, påfyldning, tømning ved forkert
vare, ventetid ved regn, bredde-kontrol, valg af nærmeste maskine, ruter og gæringssilo ved ensilage.
En mark er **klar**, når mindst 90 % står i høstvinduet. **Start nu** starter hele kæden (eller pleje, hvis
marken vokser og trænger). På en bar mark starter den klargøring/såning. **Stop mark** stopper maskinerne.
+25 -1
View File
@@ -1,4 +1,4 @@
# Testplan — Markarbejde (fanen Marker), version 1.28.0.0
# Testplan — Markarbejde (fanen Marker), version 1.28.0.0 (+ guider v1.31/v1.32)
Stor test-session. Kør testene i rækkefølge: de første bygger opsætningen, de senere bygger på den.
Hver test har **Gør**, **Forvent** og **Log** (linjer i `log.txt`, der beviser at det virkede). Loglinjer
@@ -164,6 +164,29 @@ Afgrøde "Samme som høstet", Tromle Ja. Kalk Ja.
- [ ] **8.4 Beskeder.** Grøn besked når en mark/pleje er færdig; rød besked ved fejl (hver kun én gang i træk).
- [ ] **8.5 Ydelse.** Ingen mærkbar lag med fanen åben og mange marker (én mark scannes pr. sekund).
## 10. Guiden "Opsæt mark" (v1.31)
- [ ] **10.1 Oversigt.** Klik F22 i tabellen. Forvent: resumé-linjer (Afgrøde, …, Lager) med "[Ret]", hele
status, markør. Ingen lang detaljeliste og ingen markflåde nederst. Knapper: Start nu, Opsæt mark, Markflåde.
- [ ] **10.2 Guiden fra bunden.** Opsæt mark → "Trin 1 af N — Afgrøde". Klik Næste gennem alle trin uden at
scrolle. Tællingen passer med de viste trin (græs: ingen Klargøring; bar mark: ingen Pleje/Lager).
- [ ] **10.3 Valg gemmes.** Vælg fx Hø + Riv, 2 ad gangen, Lager: Vælg selv + en silo → Oversigt viser valgene
→ **Kør automatisk**. Forvent: tabellens Plan "Hø + riv (x2)", Kørsel "Auto". Log: `F22 guide gemt: mode=auto …`.
- [ ] **10.4 Annullér.** Åbn guiden, skift afgrøde, Annullér → intet ændret. Samme med ESC (menuen lukkes).
- [ ] **10.5 Ret én linje.** Klik "Lager: …" i oversigten → "Ret: Lager"; skift → **Gem** → tilbage i
oversigten med ændringen; Kørsel (Auto/Manuel) uændret. Tilbage i et Ret-trin fortryder.
- [ ] **10.6 Ret fra Oversigt-trinnet.** I guidens sidste trin: klik en linje → ret → **OK** → tilbage på Oversigt.
- [ ] **10.7 Mål-afgrøde skifter trin.** Kornmark: vælg Græs som afgrøde → trinnet "Afgrødens valg" viser
Ensilage/Hø; tællingen ændres. På Oversigt kun **Kør automatisk** (ingen "Gem uden at starte").
- [ ] **10.8 Faste maskiner.** Maskiner → Faste = Ja → sæt flueben ved 2 maskiner → gem. Åbn en anden mark:
de 2 vises ikke; linje "2 maskiner er faste på andre marker (F22)". Log: `guide gemt … faste=…`.
- [ ] **10.9 Marksilo.** Mark med silo inden for 150 m: Lager-trinnet spørger "Brug marksiloen?". Ja → resumé "Marksilo".
- [ ] **10.10 Uden valgt mark.** Ingen mark valgt → Opsæt mark → trin "Mark" med listen; klik en mark → Afgrøde.
Næste uden valgt mark giver "Vælg en mark først".
- [ ] **10.11 Markflåde.** Knappen Markflåde viser flåden (flueben, "fast på F22"); klik et flueben gemmes;
**Til marker** går tilbage.
- [ ] **10.12 Klik routes.** Alle Ja/Nej, valg og flueben i guiden reagerer (ingen "GUI-fejl" i statuslinjen/log).
---
## Kendte usikkerheder (første gang i spillet)
@@ -178,4 +201,5 @@ Afgrøde "Samme som høstet", Tromle Ja. Kalk Ja.
| Påfyldning | AutoDrive LOAD til den læssestation moden fandt (AutoDrives eget automatiske mål er slået fra i AutoDrive) | Sættet står ved påfyldningen og læsser ikke, eller kører ikke tilbage |
| Ukrudt | `weedSystem`-værdi ≥ 2 = tæt | Ukrudtsbehandling uden ukrudt, eller aldrig |
| Nysået som "bar" | nysået afgrøde læses som voksende | Marken står "Færdig" efter såning (ingen dobbelt-såning, men ingen næste høst-start før den er moden) |
| Halm-valg i guiden | `fruitType.hasWindrow/windrowName` = afgrøder med halm | Halm-valget mangler ved hvede eller vises ved majs |
| Ballesamler | Courseplays BALE_FINDER + AutoDrive til ballelager | Ballesamleren starter ikke, eller kører ikke fulde læs væk |
+47 -21
View File
@@ -546,7 +546,7 @@ and which machines. Requires **Courseplay** in addition to AutoDrive.
### Select and forget: crop on the field
The easiest way: pick **Crop on the field** (such as *Wheat*) at the top of the field. The mod does the rest:
The easiest way: pick a crop (such as *Wheat*) in the guide step **Crop** (Set up field). The mod does the rest:
- **Whatever grows now** is left to finish, cared for (fertilizer, weeds, lime) and harvested or mowed when
ready.
@@ -556,9 +556,8 @@ The easiest way: pick **Crop on the field** (such as *Wheat*) at the top of the
- **Bare field:** prepared and sown as soon as it is sowing time.
- After that the cycle runs by itself: growth → care → harvest → preparation → sowing → …
With a crop chosen, the field runs automatically. The line below the choice tells you what the mod will do.
You can still choose silage/hay, straw, number of machines, soil work and care. Choose *None — plan it
yourself* to run the field manually as before.
With a crop chosen, the field runs automatically. You can still choose silage/hay, straw, number of
machines, soil work and care in the following steps. Choose *Keep what grows* to run the field as before.
### Setup
@@ -566,7 +565,7 @@ yourself* to run the field manually as before.
such as `F109`. Machines drive there on the road before Courseplay takes over. At most 400 m from the
field. Without it, the field shows `!` and nothing is sent.
2. **Fixed rigs.** The implement must be attached (or self-propelled). The mod never attaches.
3. **Field fleet.** At the bottom are all vehicles with a field implement, with role and width. With
3. **Field fleet.** The **Field fleet** button shows all vehicles with a field implement, with role and width. With
**Use all free machines** = Yes (default) the mod finds the machines itself; with No only ticked ones
are used. Vehicles in a flow, vehicles AutoDrive/Courseplay are already driving, and
vehicles you drive are never used. A sprayer/spreader only has a role once it holds product
@@ -585,25 +584,52 @@ yourself* to run the field manually as before.
### A field
Click a field in the table. Below the table:
Click a field in the table. Below the table is the field's **summary** — one line per topic:
| Option | Meaning |
| Line | Example |
|---|---|
| **Mode** | *Manual*: the field waits for **Start now**. *Auto*: it starts by itself when ready or when it needs care |
| **Machines per step** | 1–5 rigs at once (Courseplay multi-tool). A step starts only when all rigs are free |
| **Plan** (mowable) | Silage or Hay |
| **Rake** (mowable) | Rake the swaths before collecting |
| **Unloading trailers** (harvest) | 1–3 trailers that follow the harvester and drive to storage |
| **Straw after harvest** (harvest) | Chopped (spread), Collected to a silo, or Baled, and a bale collector takes the bales to a bale store |
| **Mulch stubble** | Mulch the stubble after harvest |
| **Soil work** | Auto (plow when the soil needs it, else cultivate), Cultivate, Plow or None |
| **Sow afterwards** + **Crop to sow** | Sow after soil work. Default: the crop that was harvested |
| **Roll** | Roll after sowing |
| **Fertilize / Lime / Control weeds** | Care while the crop grows, when the soil needs it (at most twice per care per season) |
| **Force storage** | Pick stores. Without a choice: silage → nearest fermenting silo, else silo; hay and harvest → nearest silo |
| **Crop** | *Keep what grows* / *-> Wheat* |
| **Crop options** | *Silage, rake* / *straw chopped* |
| **Preparation** | *Automatic* / *Plow, lime* |
| **Crop care** | *fertilizer, weeds* |
| **Machines** | *3 dedicated* / *free machines*, *1 at a time*, *1 unloaders* |
| **Storage** | *Field silo* / *Automatic* / a chosen silo |
Below the options: **The soil needs** (lime, plowing, fertilizer, weeds), the marker, and mowing width and
swath offset when relevant.
**Click a line** to change just that (e.g. storage): only that step opens, and **Save** saves and returns.
Below the summary are the full status and the marker.
Buttons: **Start now / Stop field**, **Set up field** and **Field fleet**.
### The "Set up field" guide
**Set up field** sets the field up one question at a time ("Step 3 of 7 — …"). Steps that do not fit the
field are skipped; a field already set up opens with its current choices. Without a selected field you pick
the field first.
| Step | Shown when | Choices |
|---|---|---|
| **Crop** | always | *Keep what grows* or a crop to sow (target crop, see above). Harvest/bare field: *Sow the same crop again after harvest* |
| **Crop options** | mowable (now or as target): Silage/Hay + Rake. Harvest crop with straw: straw chopped/collected/baled | |
| **Preparation** | after harvest / bare field / crop change | *Automatic (recommended)* or *Choose myself*: soil work, lime, mulch, roll |
| **Crop care** | a growing crop | Fertilizer, weeds (not on mowables); lime here when there is no preparation |
| **Machines** | always | At a time (1–5), unloaders when harvesting (1–3), **Dedicated machines for this field?** + the list |
| **Storage** | harvest/mowing | *Use the field silo?* (when there is one), else *Automatic* or *Choose myself* among the 8 nearest |
| **Summary** | always | The summary; click a line to change it. **Run automatically** (Auto) or **Save without starting** (Manual) |
Buttons: **Next**, **Back**, **Cancel**. Nothing is saved before **Run automatically** / **Save without
starting** (or **Save** when editing one line). Closing the menu or switching tab discards the guide. With a
target crop the field always runs automatically. Without a marker the field can be set up; work waits for
the marker.
**Dedicated machines:** a dedicated machine only works this field, and the field waits for its own rather
than borrowing another. The list only shows free machines and those already dedicated here; machines
dedicated to other fields show as "N machines are dedicated to other fields (F22)".
**Field fleet** (button): the shared fleet — *Use all free machines* and the ticked list, "dedicated to
F22", "working on F108" and width warnings. **Back to fields** returns.
The mod never asks about: scanning, when to harvest/mow/fertilize/spray, refilling, emptying wrong cargo,
waiting for rain, width checks, choosing the nearest machine, routes, and fermenting silo for silage.
A field is **ready** when at least 90 % is in the harvest window. **Start now** starts the whole chain (or
care, when the field grows and needs it). On a bare field it starts preparation/sowing. **Stop field** stops
+174
View File
@@ -0,0 +1,174 @@
# Guider til opsætning (marker + flows) — implementeringsplan
> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:executing-plans (native; brugeren har givet fuld autonomi). Trin bruger `- [ ]`.
**Goal:** Fields- og Flows-fanen får en oversigt med resumé (klik = ret ét trin) og en trin-for-trin-guide ("Opsæt mark" / "Opsæt flow") på én fælles guide-ramme.
**Architecture:** En ren guide-motor (`adGuide.lua`) styrer trin, synlighed, tælling, næste/tilbage/spring. Oven på den to rene trin-definitioner (`adFieldGuide.lua`, `adFlowGuide.lua`) der ud fra en kladde + et `context` (det spil-afhængige, hentet af GUI'et) giver rækker (som data), valg, standarder, resumé og gem-resultat. GUI-laget (`gui/SmartPickupGuide.lua` fælles trin-skærm, `gui/SmartPickupFieldGuide.lua`, `gui/SmartPickupFlowGuide.lua`) er tyndt: bygger context, tegner rækkerne, router klik og gemmer via de eksisterende `ADFieldJobs`/`ADRunsController`-funktioner.
**Tech Stack:** Lua 5.1 (FS25), luajit til tests, FS25 GUI (klonede prefabs).
**Spec:** `docs/superpowers/specs/2026-09-26-guider-design.md`
## Global Constraints
- Lua 5.1: ingen goto, ingen coroutines, ingen `#` på tabeller med huller; pcall om spil-API.
- Gemt format (`ADSmartPickup_fields.xml`, `ADSmartPickup_runs.xml`) ændres ikke. Guiderne skriver kun via `ADFieldJobs.setTarget/setPlan` og `ADRunsController.createRun/updateRun/assignVehicle/unassignVehicle`.
- Intet gemmes før [Gem]/[Kør automatisk]/[Start flow]. [Annullér], fanebyt og lukket menu kasserer kladden.
- Rene moduler returnerer nye tabeller (kladden kopieres ved hvert valg).
- Filer under ~800 linjer; `SmartPickupFrame.lua` (971) får kun små routing-ændringer.
- Nye .lua i modDesc (rene moduler) eller `source()` i adSmartPickup.lua (GUI-filer), i rigtig rækkefølge.
- Al ny tekst i både `l10n_da.xml` og `l10n_en.xml`.
- Guide-rækker laves KUN med `ingredientPrefab` (Ja/Nej, flueben) og `productPrefab` (valg) med `kind = "guideRow"`, routet i `onClickIngredient`/`onClickProduct`; klikbare tekstlinjer via `makeRowClickable` + pendingClick. Ingen guide-rækker på `vehiclePrefab` (v1.30.4-fælden).
- Bundknapper: kun MENU_ACTIVATE, MENU_EXTRA_1, MENU_EXTRA_2, MENU_CANCEL (+ MENU_BACK) — andre findes ikke sikkert i FS25.
- Tests: `for t in tests/test_*.lua; do luajit $t | tail -1; done` — alle grønne.
## Review Focus
1. Klik på guide-rækker gemmes aldrig (forkert routing) → alle nye kinds routes via `guideRow`; testplan-punkt in-game.
2. Kladde muteres ved valg (Annullér gemmer alligevel) → test: `choose` ændrer ikke den gamle guide/kladde.
3. Trin forsvinder/dukker op efter et valg (fx mål-afgrøde græs på kornmark) → tælling og næste følger de synlige trin; test.
4. [Ret] fra oversigten må kun gemme det ene trin og bevare Auto/Manuel → test `result(guide, nil)` bevarer mode.
5. Faste maskiner: maskine fast på anden mark flyttes kun hvis brugeren vælger den (skjult i listen) → test `applyRigs`.
---
## Beslutninger (uklarheder i spec'en)
- **[Opsæt mark] uden valgt mark** vises også (åbner trin 1 "Mark"); ellers kunne trin 1 aldrig nås.
- **"Så igen bagefter"** (plan.sow uden mål-afgrøde) står i trin 2 under "Behold det der gror" for høst-/bare marker — ellers forsvinder muligheden.
- **Kalk**: i Klargøring ("Vælg selv"); når Klargøring ikke vises (ren græsmark) står Kalk i Pleje.
- **Klargøring "Automatisk"** = jord auto, kalk ja, mulch nej, tromle nej (anvendes kun når trinnet er synligt).
- **Maskiner-trinnet**: antal ad gangen + aflæsningsvogne først, så "Faste maskiner?" + listen (listen kan være lang). Aflæsningsvogne 1–3 (modellens `MAX_UNLOADERS`), ikke 1–5.
- **Mark uden markør**: gemmes med den valgte tilstand; job-løkken venter allerede på markøren (dagens regel). Oversigten viser "sæt markøren".
- **Mål-afgrøde** tvinger Auto (som i dag); på Oversigt-trinnet vises da kun [Kør automatisk].
- **[Ret] fra trin 8** vender tilbage til Oversigt-trinnet (kladden bevares); [Tilbage] i et [Ret]-trin fortryder det ene trins ændringer.
- **Flows**: bundlinjen har plads til 4 knapper → [Start/Stop] [Opsæt flow] [Nyt flow] [Slet]; Omdøb ligger på resuméets Navn-linje; Start alle/Stop alle bliver på fanen Oversigt.
- **Halm**: `context.straw` = afgrøder med halm (FS25 `fruitType.hasWindrow/windrowName`); kan det ikke aflæses (tom), vises halm-valget for alle høstafgrøder som i dag.
---
# Etape A — fælles ramme + Marker (v1.31.0.0)
### Task A1: Guide-motoren `adGuide.lua`
**Files:** Create `FS25_ADSmartPickup/adGuide.lua`, `tests/test_adGuide.lua`; Modify `modDesc.xml` (før adFieldModel.lua).
**Interfaces (Produces):**
```lua
ADGuide.new(def, draft, context, options) -> guide
-- def = {order = {stepId...}, isVisible = function(stepId, guide) -> bool}
-- options = {step = id|nil, single = bool, returnTo = "close"|"summary"}
-- guide = {def, draft, context, step, single, returnTo, snapshot}
ADGuide.visibleSteps(guide) -> {stepId...}
ADGuide.position(guide) -> index|nil, total
ADGuide.isLast(guide) -> bool
ADGuide.next(guide) -> guide, event -- event nil | "done"
ADGuide.back(guide) -> guide, event -- event nil | "cancel"
ADGuide.jump(guide, stepId, returnTo) -> guide (single, snapshot = kopi af kladden)
ADGuide.withDraft(guide, draft) / ADGuide.withContext(guide, context) -> guide
ADGuide.deepCopy(value) ; ADGuide.toggleItem(list, item, on) -> ny liste
ADGuide.labelText(label, getText) -> string -- label = {key, args} | {text}
ADGuide.lineText(line, getText) -> "Titel: del, del" -- line = {step, title = label, parts = {label...}}
```
- [ ] Test (RED): næste/tilbage springer skjulte trin over; tælling "3 af 5" over synlige; `next` på sidste = "done"; `back` på første = "cancel"; `jump(..., "summary")` + `next` lander på `summary` med single=false; `jump(..., "close")` + `next` = "done"; `back` i spring gendanner snapshot; `withDraft` returnerer ny guide (gammel urørt); trin der bliver usynligt efter et valg: `next` går til næste synlige i `order`; `toggleItem` uden dubletter; `labelText` med args og manglende args (pcall).
- [ ] Kør `luajit tests/test_adGuide.lua` → FAIL (fil mangler).
- [ ] Implementér; kør → ALLE TESTS OK.
### Task A2: Markguidens trin `adFieldGuide.lua`
**Files:** Create `FS25_ADSmartPickup/adFieldGuide.lua`, `tests/test_adFieldGuide.lua`; Modify `modDesc.xml` (efter adFieldView.lua).
**Interfaces:**
- Consumes: `ADGuide.*`, `ADFieldModel.product/MAX_RIGS/MAX_UNLOADERS`, `ADFieldFleet.visibleForField`, `ADFlowView.naturalLess`.
- Produces:
```lua
ADFieldGuide.ORDER = {"field","crop","cropChoice","prep","care","machines","store","summary"}
ADFieldGuide.open(field, context, options) -> guide -- context.info påkrævet
ADFieldGuide.openPicker(context) -> guide -- trin "field"
ADFieldGuide.pickField(guide, field, context) -> guide -- videre til trinnet efter "field"
ADFieldGuide.isVisible(stepId, guide) -> bool
ADFieldGuide.rows(guide) -> {row...}
-- row = {type="choice", id, title, options={{label, value}}, value}
-- | {type="toggle", id, title, off, on, value}
-- | {type="check", id, item, title, value}
-- | {type="text", label} | {type="link", id, value, label}
ADFieldGuide.choose(guide, id, value) -> guide
ADFieldGuide.summary(guide) -> {line...}
ADFieldGuide.result(guide, start) -> {fieldId, targetFruit, targetChanged, plan, rigIds}
ADFieldGuide.applyRigs(rigIdsByField, fieldId, rigIds) -> ny {[fieldId] = ids}
ADFieldGuide.stepKey(stepId) / hintKey(stepId) -> l10n-nøgler
```
- context: `{info, sowable={{name,title}}, mowable={[name]=true}, straw={[name]=true}|nil, rigs={{id,text,role}}, rigIdsByField, fieldSilos={{id,text}}, stores={{id,text}}|nil, storeHidden, fields={{id,text}}}`.
- kladde: `{fieldId, plan (kopi), originalTarget, prepAuto, useDedicated, storeMode ("auto"|"manual"|"fieldSilo"), storeIds, pickField}`.
- [ ] Test (RED): synlige trin for (a) græs uden mål: crop, cropChoice, care, machines, store, summary (ingen prep); (b) høst m. halm: + prep, cropChoice (halm); (c) høst uden halm (`straw` sat, afgrøden ikke med): ingen cropChoice; (d) bar mark uden mål: crop, prep, machines, summary (ingen care/store); (e) kornmark med mål græs: cropChoice (ensilage/hø) + prep; picker: kun "field". Standarder: ny mark → prepAuto, useDedicated=false, storeMode auto; plan med soil=plow → prepAuto=false; plan med rigIds → useDedicated; storeIds lig marksilo → fieldSilo. `choose` ændrer ikke gammel guide; `rigIds`-check toggler; `result`: prepAuto overskriver soil/mulch/lime/roll kun når prep er synlig; mode auto/manual efter start, uændret ved start=nil, auto ved mål; storeBuildingIds pr. storeMode; rigIds tom når useDedicated=false; targetChanged. `applyRigs` fjerner maskinen fra anden mark. Rækker: maskiner-trinnet skjuler maskiner faste på andre marker + tekst med antal; marksilo-spørgsmål kun når fieldSilos findes; "Vælg selv" viser siloerne. Resumé: linjer kun for synlige trin, med rigtige nøgler (fx `spu_guide_sum_dedicated` args {3}).
- [ ] Kør → FAIL; implementér; kør → OK. Hele suiten grøn.
### Task A3: Fælles trin-skærm `gui/SmartPickupGuide.lua`
**Files:** Create `gui/SmartPickupGuide.lua`; Modify `adSmartPickup.lua` (source efter SmartPickupFlowTab.lua), `gui/SmartPickupFrame.lua` (initGuideButtons i new, routing `guideRow` i onClickIngredient, refreshButtons → `getGuideButtons`, switchTab/onFrameClose lukker guiden, rebuild for faner med åben guide), `gui/SmartPickupOutboundTab.lua` (onClickProduct → guideRow).
**Interfaces (Produces):**
```lua
SmartPickupFrame.GUIDE_HOOKS[kind] = {model, tab, context(frame, adEnv, guide) -> context, save(frame, guide, start), choose(frame, id, value) -> handled}
SmartPickupFrame:initGuideButtons(i18n)
SmartPickupFrame:openGuide(kind, guide) SmartPickupFrame:closeGuide()
SmartPickupFrame:fillGuideRows(adEnv) -- overskrift "Trin 3 af 7 — …", forklaring, rækker
SmartPickupFrame:guideText(label) -> string
SmartPickupFrame:addLinkRow(text, action)
SmartPickupFrame:onClickGuideRow(state, data)
SmartPickupFrame:getGuideButtons() -> knapliste
SmartPickupFrame:onClickGuideNext/Back/Cancel/SaveOnly()
```
- [ ] Skriv filen; `luajit -bl` syntakstjek.
### Task A4: Marker-fanen: oversigt, markflåde, guide
**Files:** Create `gui/SmartPickupFieldGuide.lua` (context, gem, knapper for fanen); Modify `gui/SmartPickupFieldTab.lua` (fillFieldRows → oversigt/markflåde/guide; fjern den lange detaljeliste), l10n da/en.
- Oversigt: hint, tabel, for valgt mark: overskrift, resumé-linjer (klik = `ADGuide.jump(step, "close")`), fuld status, markør-linje, marksilo-advarsel. Knapper: [Opsæt mark] (EXTRA_1), [Start nu/Stop] (ACTIVATE), [Markflåde] (EXTRA_2).
- Markflåde: `fillFleetRows(adEnv, nil)` (alle maskiner). Knap [Til marker] (EXTRA_2).
- Gem: `setTarget` hvis ændret → `setPlan(plan)` → `applyRigs` → `setPlan(fid, {rigIds})` for ændrede marker.
- [ ] Skriv, syntakstjek, suiten grøn.
### Task A5: Docs + ship v1.31.0.0
- [ ] TESTPLAN-markarbejde.md: afsnit "Guider (v1.31)"; BRUGERMANUAL/USER_MANUAL: Marker-afsnit kort.
- [ ] Ship-procedure (version 1.30.4.0 → 1.31.0.0), commit `feat(gui): guide "Opsæt mark" …`, push gitea.
# Etape B — Flows på samme ramme (v1.32.0.0)
### Task B1: Flowguidens trin `adFlowGuide.lua`
**Files:** Create `FS25_ADSmartPickup/adFlowGuide.lua`, `tests/test_adFlowGuide.lua`; modDesc (efter adFlowView.lua).
**Interfaces (Produces):**
```lua
ADFlowGuide.ORDER = {"name","direction","buildings","goods","store","rules","wait","tractors","summary"}
ADFlowGuide.open(run, context, options) -> guide -- run = eksisterende run
ADFlowGuide.openNew(name, context) -> guide -- nyt flow (trin "name" synligt)
ADFlowGuide.isVisible(stepId, guide); ADFlowGuide.rows(guide); ADFlowGuide.choose(guide, id, value)
ADFlowGuide.summary(guide) -> {line...}
ADFlowGuide.result(guide) -> {isNew, runId, name, kind, changes, vehicleIds}
ADFlowGuide.vehicleChanges(oldIds, newIds) -> added, removed
ADFlowGuide.previewRun(draft) -> run-formet tabel til controllerens opslag
```
- context: `{buildings={{id,name,label,hasMarker,text}}, fillTypes={{name,title}}, products={{name,title}}, storeBuildings={{id,text}}, waitPools={{group,count}}, vehicles={{id,text,otherRunId,otherRunName,blocked}}, sellAtSteps, storeAboveSteps, returnBelowSteps, maxLoops}`.
- kladde: kopi af run-felterne + `isNew`, `showAllBuildings`, `storeAuto`.
- [ ] Test (RED): name-trin kun ved nyt flow; store-trin kun ved udkørsel med en vare på Lager/Salg-ellers-lager; retning skifter bygnings-rolle; varer: forsyning auto/vælg (ingredients toggles), udkørsel politik pr. vare (products); regler pr. retning; traktorer i andre flows/blokerede skjult + tekst; resumé pr. retning; result.changes; vehicleChanges; choose immutabelt.
- [ ] FAIL → implementér → OK.
### Task B2: Flows-fanen i GUI'et
**Files:** Create `gui/SmartPickupFlowGuide.lua`; Modify `gui/SmartPickupFrame.lua` (rebuild for Flows-fanen: tavle + resumé, statiske rækker skjult; refreshLive/refreshButtons), l10n.
- Oversigt: tavlen (`fillOverviewRows`), valgt flow: resumé (klik = ret ét trin; Navn-linjen = omdøb-dialog), status-linje (live). Knapper: [Start/Stop] (ACTIVATE), [Opsæt flow] (EXTRA_1), [Nyt flow] (EXTRA_2), [Slet] (CANCEL).
- Gem: nyt → `createRun`; `updateRun(changes)`; traktorer via `vehicleChanges` + `assignVehicle/unassignVehicle`; `resolveMarkers`; `save()`; [Start flow] → `startRun`.
- [ ] Skriv, syntakstjek, suiten grøn.
### Task B3: Docs + ship v1.32.0.0; selv-review
- [ ] TESTPLAN + manualer (Flows-afsnit), ship 1.31.0.0 → 1.32.0.0.
- [ ] Code-review-agent på hele diffen; ret CRITICAL/HIGH; evt. v1.32.1.0.