Enable first operating day with staff assignments, opening guide, and ledger

This commit is contained in:
Codex
2026-09-09 08:26:20 +09:00
parent 423fd6dd2e
commit 29a660aed0
28 changed files with 2451 additions and 156 deletions
+135 -7
View File
@@ -1,5 +1,8 @@
extends Control
const OpeningGuideScript := preload("res://scripts/ui/inn_opening_guide.gd")
const OperatingLedgerPanelScript := preload("res://scripts/ui/operating_ledger_panel.gd")
const StaffManagementPanelScript := preload("res://scripts/ui/staff_management_panel.gd")
const WorldPreviewScript := preload("res://scenes/main/world_preview.gd")
const DefaultVisualTheme := preload("res://assets/themes/japanese_fantasy/visual-theme-v1.tres")
const MANUAL_SAVE_PATH := "user://saves/manual_ui"
@@ -90,6 +93,7 @@ const STAFF_SKILL_NAMES := {
}
@export var visual_theme: VisualThemeProfile = DefaultVisualTheme
var manual_save_path := MANUAL_SAVE_PATH
var time_label: Label
var phase_label: Label
@@ -109,6 +113,9 @@ var dashboard_summary_label: Label
var foreground_event_panel: VBoxContainer
var foreground_event_label: Label
var foreground_event_choices: VBoxContainer
var staff_management_panel: VBoxContainer
var staff_management_toggle_button: Button
var _staff_management_panel_open := false
var staff_candidate_panel: VBoxContainer
var staff_candidate_summary_label: Label
var staff_candidate_toggle_button: Button
@@ -119,6 +126,10 @@ var selected_entity_icon: TextureRect
var build_status_label: Label
var build_buttons: Dictionary = {}
var navigation_buttons: Dictionary = {}
var opening_guide: Control
var operating_ledger_panel: VBoxContainer
var operations_controls: VBoxContainer
var _ledger_panel_open := false
var management_panel: Control
var management_toggle_button: Button
var palette_scroll: ScrollContainer
@@ -145,6 +156,7 @@ var _operations_start_report: Dictionary = {}
func _ready() -> void:
_runtime = get_node_or_null("/root/SimulationRuntime")
_pause_fresh_opening()
if _runtime != null and _runtime.has_method("enable_production_save_policy"):
_runtime.enable_production_save_policy()
if _runtime != null \
@@ -173,6 +185,24 @@ func _ready() -> void:
)
func _pause_fresh_opening() -> void:
if _runtime == null or GameClock.absolute_minute != 360:
return
if not (_runtime.get(&"latest_restore_safety_report") as Dictionary).is_empty():
return
var operations: Dictionary = _runtime.call(&"get_operations_report")
if bool(operations.get(&"enabled", false)):
return
if not _call_array(_service(&"construction_service"), &"get_facilities").is_empty() \
or not _call_array(_service(&"construction_service"), &"get_jobs").is_empty() \
or not _call_array(_service(&"staff_service"), &"get_staff_members").is_empty():
return
var queue: Variant = _runtime.get(&"command_queue")
if queue != null and not queue.get_accepted_command_metadata().is_empty():
return
GameClock.set_paused(true)
func _unhandled_key_input(event: InputEvent) -> void:
if not event.pressed or event.echo:
return
@@ -252,6 +282,12 @@ func _build_interface() -> void:
world_preview.size_flags_vertical = Control.SIZE_EXPAND_FILL
world_preview.set_visual_theme(visual_theme)
map_panel.add_child(world_preview)
opening_guide = OpeningGuideScript.new()
world_preview.add_child(opening_guide)
opening_guide.setup(_runtime, GameClock)
opening_guide.position = Vector2(8, 8)
opening_guide.size = Vector2(302, 0)
opening_guide.action_requested.connect(_on_opening_action)
# The inspector overlays the map only when requested, leaving the full
# cross-section available while watching the simulation.
management_panel = _create_side_panel()
@@ -396,6 +432,7 @@ func _create_side_panel() -> Control:
column.size_flags_horizontal = Control.SIZE_EXPAND_FILL
column.add_theme_constant_override("separation", 8)
scroll.add_child(column)
var root_column := column
var inspector_heading := HBoxContainer.new()
var inspector_title := _section_heading("運営状況")
@@ -424,12 +461,21 @@ func _create_side_panel() -> Control:
foreground_event_choices.add_theme_constant_override("separation", 5)
foreground_event_panel.add_child(foreground_event_choices)
column.add_child(HSeparator.new())
operations_controls = VBoxContainer.new()
operations_controls.name = "OperationsControls"
operations_controls.add_theme_constant_override("separation", 8)
column.add_child(operations_controls)
column = operations_controls
var candidate_heading_row := HBoxContainer.new()
candidate_heading_row.add_child(_section_heading("雇用候補"))
candidate_heading_row.add_child(_section_heading("スタッフ"))
var candidate_heading_spacer := Control.new()
candidate_heading_spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
candidate_heading_row.add_child(candidate_heading_spacer)
staff_management_toggle_button = _button("雇用済み", _toggle_staff_management_panel, 62)
staff_management_toggle_button.name = "StaffManagementToggleButton"
staff_management_toggle_button.toggle_mode = true
candidate_heading_row.add_child(staff_management_toggle_button)
staff_candidate_toggle_button = _button(
"候補を見る H",
_toggle_staff_candidate_panel,
@@ -438,6 +484,11 @@ func _create_side_panel() -> Control:
staff_candidate_toggle_button.name = "StaffCandidateToggleButton"
candidate_heading_row.add_child(staff_candidate_toggle_button)
column.add_child(candidate_heading_row)
staff_management_panel = StaffManagementPanelScript.new()
staff_management_panel.configure(_runtime, _apply_button_style)
staff_management_panel.status_requested.connect(_on_staff_management_status)
staff_management_panel.visible = false
column.add_child(staff_management_panel)
staff_candidate_panel = VBoxContainer.new()
staff_candidate_panel.name = "StaffCandidatePanel"
staff_candidate_panel.visible = false
@@ -476,6 +527,10 @@ func _create_side_panel() -> Control:
selected_detail_label.add_theme_font_size_override("font_size", 13)
selected_row.add_child(selected_detail_label)
operating_ledger_panel = OperatingLedgerPanelScript.new()
root_column.add_child(operating_ledger_panel)
operating_ledger_panel.setup(_runtime, GameClock)
operating_ledger_panel.visible = false
return panel
@@ -573,15 +628,18 @@ func _set_management_panel_open(open: bool) -> void:
management_toggle_button.set_pressed_no_signal(open)
if not open:
_set_staff_candidate_panel_open(false)
_set_staff_management_panel_open(false)
_set_ledger_panel_open(false)
func _activate_management_mode(mode: StringName) -> void:
_set_management_panel_open(mode != &"facility")
_set_ledger_panel_open(mode == &"ledger")
for raw_mode: Variant in navigation_buttons:
(navigation_buttons[raw_mode] as Button).set_pressed_no_signal(StringName(raw_mode) == mode)
match mode:
&"staff":
_set_staff_candidate_panel_open(true)
_set_staff_management_panel_open(true)
&"facility":
_set_build_palette_open(true)
_set_staff_candidate_panel_open(false)
@@ -593,7 +651,41 @@ func _activate_management_mode(mode: StringName) -> void:
&"investment":
_set_status("投資管理は一覧画面の実装準備中です。", true, true)
&"ledger":
_set_status("帳簿は06:00決算と接続する予定です。", true, true)
_set_status("本日の資金増減と、06:00に確定した営業日の損益を表示します。", true, true)
func _set_ledger_panel_open(open: bool) -> void:
_ledger_panel_open = open
if operating_ledger_panel != null:
operating_ledger_panel.visible = open
if open:
operating_ledger_panel.refresh()
if operations_controls != null:
operations_controls.visible = not open
if dashboard_summary_label != null:
dashboard_summary_label.visible = not open
if open:
_set_staff_candidate_panel_open(false)
_set_staff_management_panel_open(false)
func _on_opening_action(action: StringName) -> void:
match action:
&"build_reception", &"build_room", &"build_corridor":
_set_ledger_panel_open(false)
_set_management_panel_open(false)
_set_build_palette_open(true)
var definitions := {&"build_reception": &"reception", &"build_room": &"standard_room", &"build_corridor": &"guest_corridor"}
_select_build_definition(definitions[action])
&"staff":
_activate_management_mode(&"staff")
if _call_array(_service(&"staff_service"), &"get_staff_members").is_empty():
_set_staff_candidate_panel_open(true)
&"resume":
if GameClock.paused:
_toggle_pause()
&"ledger":
_activate_management_mode(&"ledger")
func _connect_signals() -> void:
@@ -717,6 +809,28 @@ func _staff_candidate_text(summary: Dictionary) -> String:
]
func _toggle_staff_management_panel() -> void:
_set_staff_management_panel_open(not _staff_management_panel_open)
func _set_staff_management_panel_open(open: bool) -> void:
_staff_management_panel_open = open
if staff_management_panel != null:
staff_management_panel.visible = open
if staff_management_toggle_button != null:
staff_management_toggle_button.set_pressed_no_signal(open)
if open:
_set_ledger_panel_open(false)
_set_staff_candidate_panel_open(false)
_set_management_panel_open(true)
staff_management_panel.refresh()
_set_status("従業員を選び、配属先と毎日の勤務帯を変更できます。", true, true)
func _on_staff_management_status(message: String, success: bool) -> void:
_set_status(message, success)
func _toggle_staff_candidate_panel() -> void:
_set_staff_candidate_panel_open(not _staff_candidate_panel_open)
@@ -727,6 +841,8 @@ func _set_staff_candidate_panel_open(open: bool) -> void:
staff_candidate_panel.visible = open
_refresh_staff_candidates()
if open:
_set_ledger_panel_open(false)
_set_staff_management_panel_open(false)
_set_management_panel_open(true)
_set_status("雇用候補を選んでください。契約金と日給は確定前に表示されます。", true, true)
@@ -885,6 +1001,9 @@ func _clear_build_selection(announce := true) -> void:
func _clear_active_tool() -> void:
if _staff_management_panel_open:
_set_staff_management_panel_open(false)
return
if _staff_candidate_panel_open:
_set_staff_candidate_panel_open(false)
return
@@ -1073,6 +1192,7 @@ func _excavation_idempotency_key(cell: Vector3i) -> StringName:
func _on_facility_selected(instance_id: StringName) -> void:
_set_ledger_panel_open(false)
_set_management_panel_open(true)
_set_excavation_mode(false, false)
_selected_entity_id = instance_id
@@ -1081,6 +1201,7 @@ func _on_facility_selected(instance_id: StringName) -> void:
func _on_construction_selected(job_id: StringName) -> void:
_set_ledger_panel_open(false)
_set_management_panel_open(true)
_set_excavation_mode(false, false)
_selected_entity_id = job_id
@@ -1158,6 +1279,10 @@ func _refresh_dashboard() -> void:
_refresh_staff_candidates()
_refresh_selected_entity()
_update_pause_and_speed()
if opening_guide != null:
opening_guide.refresh()
if operating_ledger_panel != null and _ledger_panel_open:
operating_ledger_panel.refresh()
func _refresh_foreground_event(event_service: Variant) -> void:
@@ -1175,6 +1300,7 @@ func _refresh_foreground_event(event_service: Variant) -> void:
foreground_event_panel.visible = false
return
foreground_event_panel.visible = true
_set_ledger_panel_open(false)
_set_management_panel_open(true)
var actors: Array[String] = []
for actor_value: Variant in foreground.actor_ids:
@@ -1539,11 +1665,11 @@ func _save_manual() -> void:
if _runtime == null or not _runtime.has_method(&"save_to_path"):
_set_status("保存サービスへ接続できません。", false)
return
var directory_error := DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path("user://saves"))
var directory_error := DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(manual_save_path).get_base_dir())
if directory_error != OK and directory_error != ERR_ALREADY_EXISTS:
_set_status("保存フォルダを作成できませんでした。", false)
return
var result: Variant = _runtime.call(&"save_to_path", MANUAL_SAVE_PATH, {&"display_name": "手動保存"})
var result: Variant = _runtime.call(&"save_to_path", manual_save_path, {&"display_name": "手動保存"})
if result is Dictionary and bool(result.get(&"ok", false)):
_set_status("手動セーブを保存しました。", true)
else:
@@ -1558,15 +1684,17 @@ func _load_manual() -> void:
_set_status("読込サービスへ接続できません。", false)
return
var result: Variant = (
_runtime.call(&"load_with_recovery", MANUAL_SAVE_PATH)
_runtime.call(&"load_with_recovery", manual_save_path)
if _runtime.has_method(&"load_with_recovery")
else _runtime.call(&"load_from_path", MANUAL_SAVE_PATH)
else _runtime.call(&"load_from_path", manual_save_path)
)
if result is Dictionary and bool(result.get(&"ok", false)):
_pending_build_commands.clear()
_pending_excavation_commands.clear()
_pending_hire_commands.clear()
_synchronize_ui_command_state()
if staff_management_panel != null:
staff_management_panel.refresh()
_selected_entity_id = &""
_selected_entity_kind = &""
world_preview.selected_entity_id = &""