Save The Tree implementation and acceptance work in progress

Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
This commit is contained in:
Takeshi
2026-10-11 15:58:00 +09:00
parent 39f6068461
commit b84bade045
235 changed files with 495831 additions and 312 deletions
+32 -1
View File
@@ -29,6 +29,7 @@ var result_label: Label
var selected_staff_id: StringName = &""
var _runtime: Variant
var _audio_submitter := Callable()
var _style_button: Callable
var _staff_rows: Array[Dictionary] = []
var _facility_rows: Array[Dictionary] = []
@@ -147,6 +148,9 @@ func refresh() -> void:
_style(button)
roster_list.add_child(button)
roster_buttons[staff_id] = button
# Existing buttons may have been created in hire order. Match the
# authoritative report order on every refresh, including after Load.
roster_list.move_child(button, live_ids.size() - 1)
button.text = "%s %s%s" % [row.get(&"display_name", staff_id), _role_name(row), "・未配属" if StringName(row.get(&"assigned_facility_id", &"")).is_empty() else ""]
button.tooltip_text = "施設へドラッグして配属(選択中の勤務帯を適用)\n%s / %s" % [_facility_name(StringName(row.get(&"assigned_facility_id", &""))), _state_name(row)]
for raw_id: Variant in roster_buttons.keys():
@@ -169,6 +173,19 @@ func refresh() -> void:
_refresh_editor()
## Reset optional presentation without selecting the first roster row.
## Opening the roster still uses refresh() to choose its normal default.
func clear_selection() -> void:
selected_staff_id = &""
_draft_dirty = false
if not _built:
return
result_label.text = ""
for raw_id: Variant in roster_buttons:
(roster_buttons[raw_id] as Button).set_pressed_no_signal(false)
editor_panel.hide()
func select_staff(staff_id: StringName) -> void:
selected_staff_id = staff_id
_draft_dirty = false
@@ -273,7 +290,7 @@ func submit_assignment() -> void:
return
var key := StringName("%s%08d" % [KEY_PREFIX, _sequence])
_sequence += 1
var result: Variant = _runtime.call(&"submit_command", ASSIGNMENT_COMMAND, {
var result: Variant = _submit_ui_command(ASSIGNMENT_COMMAND, {
&"staff_id": selected_staff_id,
&"facility_id": _draft_facility_id,
&"template_id": _draft_template_id,
@@ -489,3 +506,17 @@ func assign_from_drop(data: Dictionary, facility_id: StringName) -> void:
_draft_template_id = StringName(data.get(&"template_id", &"DAY"))
_draft_dirty = true
submit_assignment()
func configure_audio(submitter: Callable) -> void:
_audio_submitter = submitter
func _submit_ui_command(
command_type: StringName, payload: Dictionary = {}, actor_id: StringName = &"player",
target_id: StringName = &"", priority := 0, execute_at := -1,
idempotency_key: StringName = &""
) -> Variant:
if _audio_submitter.is_valid():
return _audio_submitter.call(command_type, payload, actor_id, target_id, priority, execute_at, idempotency_key)
return _runtime.call(&"submit_command", command_type, payload, actor_id, target_id, priority, execute_at, idempotency_key)