Workbench bill editor — tap a workbench, see/edit bills

Tap-to-select chain extended to workbenches (pawn always wins on shared
tile). Mutually exclusive with pawn selection via EventBus —
selecting one clears the other.

New WorkbenchPanel (scenes/ui/workbench_panel.gd, ~432 LOC, layer 18,
right-anchored 360 px) mirrors PawnDetailPanel shape. Bill rows expose
recipe name, mode (FOREVER / COUNT / UNTIL_N), target count, completed
progress, pause, and remove. Add-bill popup filters RecipeCatalog.all()
by accepted_skill so a Hearth only offers cooking recipes.

Supporting plumbing:
- EventBus.workbench_selected / workbench_deselected signals.
- Workbench.remove_bill() — interrupts mid-craft cleanly via
  on_craft_interrupted() before erasing.
- RecipeCatalog.all() static enumerator + Recipe.display_name() helper.
- World.workbench_at_tile() lookup.
- i18n keys ui.bill.* and ui.workbench.* in strings.gd.

Closes the deferred Phase 17 "Bill UI for workbenches" item. Player-
built workbenches are now functionally configurable; before this
landed, only world.gd-hardcoded bills worked.
This commit is contained in:
megaproxy 2026-05-16 00:29:46 +01:00
parent e5f3693ad9
commit bdd435202d
9 changed files with 551 additions and 10 deletions

View file

@ -19,6 +19,7 @@ const LOAD_MENU_SCRIPT: Script = preload("res://scenes/ui/load_menu.
const RESUME_TOAST_SCRIPT: Script = preload("res://scenes/ui/resume_toast.gd")
# Phase 17 — PawnDetailPanel (layer 18) and SettingsMenu (layer 26).
const PAWN_DETAIL_PANEL_SCRIPT: Script = preload("res://scenes/ui/pawn_detail_panel.gd")
const WORKBENCH_PANEL_SCRIPT: Script = preload("res://scenes/ui/workbench_panel.gd")
const SETTINGS_MENU_SCRIPT: Script = preload("res://scenes/ui/settings_menu.gd")
# Phase 17 (Agent B) — BuildDrawer bottom-sheet (layer 16).
const BUILD_DRAWER_SCRIPT: Script = preload("res://scenes/ui/build_drawer.gd")
@ -79,6 +80,13 @@ func _ready() -> void:
pawn_detail_panel.name = "PawnDetailPanel"
add_child(pawn_detail_panel)
# Bill-editor bottom-sheet for workbenches. Same shape as PawnDetailPanel
# (right-anchored 360 px, layer 18); mutually exclusive with it via Selection.
var workbench_panel := CanvasLayer.new()
workbench_panel.set_script(WORKBENCH_PANEL_SCRIPT)
workbench_panel.name = "WorkbenchPanel"
add_child(workbench_panel)
var settings_menu := CanvasLayer.new()
settings_menu.set_script(SETTINGS_MENU_SCRIPT)
settings_menu.name = "SettingsMenu"
@ -91,7 +99,7 @@ func _ready() -> void:
if top_bar.has_method("_add_settings_btn"):
top_bar._add_settings_btn()
Audit.log("main", "Phase 17 — PawnDetailPanel + SettingsMenu mounted.")
Audit.log("main", "Phase 17 — PawnDetailPanel + WorkbenchPanel + SettingsMenu mounted.")
# Phase 17 (Agent B) — BuildDrawer bottom-sheet (layer 16).
# Must mount AFTER the World node is ready (World._ready seeds designation_ctl).