extends SceneTree const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd") var checks := 0 var failures := 0 func expect(ok: bool, message: String) -> void: checks += 1 if not ok: failures += 1; push_error(message) func _initialize() -> void: call_deferred("run") func run() -> void: var runtime: Variant = root.get_node("SimulationRuntime") var clock: Variant = root.get_node("GameClock") var state: Variant = root.get_node("GameState") clock.reset(1,6,0); state.reset(); runtime.initialize(clock,state,42601); clock.set_paused(true) root.size = Vector2i(1280,720) var main: Control = load("res://scenes/main/main.tscn").instantiate() var path := "user://tests/anri-recruitment-%d" % Time.get_ticks_usec() main.manual_save_path = path root.add_child(main) runtime.configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false}) await process_frame; await process_frame var before: Dictionary = runtime.create_snapshot() var economy_before: Dictionary = runtime.economy_service.create_snapshot() main.staff_candidate_toggle_button.pressed.emit() var button: Button = main.staff_candidate_buttons.get(&"heroine_anri") expect(button != null and button.text == "無料で加入" and button.is_visible_in_tree(), "normal staff screen offers Anri free recruitment") clock.set_paused(false) button.pressed.emit() clock.set_paused(true) expect(button.disabled and not runtime.staff_service.has_staff(&"heroine_anri"), "running game queues recruitment without premature joining") button.pressed.emit() expect(runtime.command_queue.create_snapshot()["pending"].size() == 1, "repeated UI action does not duplicate recruitment") main.call("_save_manual") expect(SaveService.load_snapshot(path)[&"ok"], "pending Anri recruitment saves through normal UI") expect(runtime.restore_snapshot(before), "restore control before loading pending recruitment") main.call("_load_manual") clock.advance_one_minute() var anri: StaffRuntime = runtime.staff_service.get_staff(&"heroine_anri") expect(anri != null and anri.role_id == &"innkeeper" and anri.employment_kind == StaffRuntime.EmploymentKind.UNIQUE, "restored request creates canonical unique innkeeper") expect(runtime.economy_service.create_snapshot() == economy_before and anri.daily_wage == 0, "joining costs no cash and creates no daily wage") expect(button.disabled and button.text == "加入済み", "joined unique cannot be recruited twice in UI") main.staff_management_toggle_button.pressed.emit() var panel: StaffManagementPanel = main.find_child("StaffManagementPanel",true,false) panel.select_staff(&"heroine_anri") expect(panel.staff_detail_label.text.contains("アンリ") and panel.staff_detail_label.text.contains("女将") and panel.staff_detail_label.text.contains("日給 G0"), "staff screen uses unique name role and zero upkeep") main.call("_save_manual") var joined: Dictionary = runtime.create_snapshot() expect(runtime.restore_snapshot(before), "restore pre-join control") main.call("_load_manual") expect(runtime.staff_service.has_staff(&"heroine_anri") and runtime.get_hired_staff_candidate_ids().has(&"heroine_anri"), "normal load restores unique identity and recruitment history") expect(not runtime.staff_service.retire_staff(&"heroine_anri").is_success(), "recruited Anri cannot retire") var invalid := joined.duplicate(true) for row: Dictionary in invalid[&"systems"][&"runtime"][&"staff"][&"staff"]: if row[&"staff_id"] == "heroine_anri": row[&"employment_kind"] = "FREE_HIRE" var intact: Dictionary = runtime.create_snapshot() expect(not runtime.restore_snapshot(invalid) and runtime.create_snapshot() == intact, "save cannot downgrade Anri to removable generic employment") # Place the recruited manager through the normal staff controls. for build: Array in [[&"reception",Vector3i(-6,0,0)],[&"public_bath",Vector3i(1,0,0)]]: main.call("_select_build_definition", build[0]) main.call("_on_map_cell_clicked", build[1]) clock.advance_minutes(runtime.definition_registry.get_facility(build[0]).build_minutes) var reception: StringName = &"" var bath: StringName = &"" for facility: FacilityInstance in runtime.facility_service.get_instances(): if facility.definition_id==&"reception": reception=facility.instance_id if facility.definition_id==&"public_bath": bath=facility.instance_id expect(not reception.is_empty() and not bath.is_empty(), "normal UI builds manager workplace and same-floor service") panel.refresh(); panel.select_staff(&"heroine_anri") for i in panel.facility_option.item_count: if panel.facility_option.get_item_metadata(i)==reception: panel.facility_option.select(i); panel.facility_option.item_selected.emit(i) panel.apply_button.pressed.emit() expect(runtime.staff_service.get_work_assignment(&"heroine_anri").get(&"facility_id")==reception, "normal staff controls place unique innkeeper") var reception_instance: FacilityInstance=runtime.facility_service.get_instance(reception) expect(reception_instance.active_staff_ids.is_empty(), "Anri does not meet the receptionist staffing requirement") expect(not main.opening_guide._has_reception_assignment(reception_instance), "opening guide does not mistake innkeeper placement for receptionist coverage") var manager_only: Dictionary=runtime.create_snapshot() main.call("_hire_staff_candidate", &"staff_akane") panel.refresh();panel.select_staff(&"staff_akane") for i in panel.facility_option.item_count: if panel.facility_option.get_item_metadata(i)==reception: panel.facility_option.select(i);panel.facility_option.item_selected.emit(i) panel.apply_button.pressed.emit() expect(main.opening_guide._has_reception_assignment(reception_instance), "actual receptionist placement satisfies opening guide") expect(runtime.restore_snapshot(manager_only), "restore manager-only workplace after receptionist comparison") expect(not main.opening_guide._has_reception_assignment(runtime.facility_service.get_instance(reception)), "loading manager-only placement restores unsatisfied receptionist guidance") main.navigation_buttons[&"business"].pressed.emit() var business: BusinessManagementPanel = main.find_child("BusinessManagementPanel",true,false) business.refresh() for i in business.facility_option.item_count: if business.facility_option.get_item_metadata(i)==bath: business.facility_option.select(i); business.facility_option.item_selected.emit(i) expect("24G" in business.quote_label.text and "アンリ配置フロア" in business.effect_label.text, "normal business screen explains current20percent floor price") for i in business.price_option.item_count: if business.price_option.get_item_metadata(i)==&"expensive": business.price_option.select(i); business.price_option.item_selected.emit(i) business.refresh() expect("設定後 36G" in business.quote_label.text, "draft150percent policy combines with Anri120percent consistently") if OS.get_environment("THE_TREE_ANRI_CAPTURE") == "1": if not panel.visible: main.staff_management_toggle_button.pressed.emit() panel.select_staff(&"heroine_anri") expect(panel.is_visible_in_tree(), "recruited staff panel visible for rendered inspection") await process_frame; await RenderingServer.frame_post_draw expect(root.get_texture().get_image().save_png(ProjectSettings.globalize_path("res://artifacts/facility-dimensions-2026-09-29/anri-floor-assigned.png")) == OK, "capture recruited Anri") SaveService.delete_save(path) var cleanup: Dictionary = await FixtureCleanup.free_owner_and_wait(self, main) if not bool(cleanup.get(&"passed", false)): push_error("Anri recruitment ordinary owner cleanup failed: %s" % str(cleanup)) quit(96) return print("Anri recruitment UI: %d checks, %d failures" % [checks,failures]); quit(failures)