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.
98 lines
6.8 KiB
GDScript
98 lines
6.8 KiB
GDScript
extends SceneTree
|
|
const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd")
|
|
var checks:=0
|
|
var failures:=0
|
|
func expect(ok:bool,label:String)->void:
|
|
checks+=1
|
|
if not ok:failures+=1;push_error(label)
|
|
func _initialize()->void:call_deferred("run")
|
|
func cleric_id() -> StringName: return &"staff_uma"
|
|
func donation_price() -> int: return 20
|
|
func recruit_cleric(main: Control, _runtime: Variant) -> void:
|
|
main.staff_candidate_buttons[cleric_id()].pressed.emit()
|
|
func verify_effect(_runtime: Variant, _chapel: FacilityInstance) -> void: pass
|
|
func verify_after_start(_runtime: Variant, _chapel: FacilityInstance) -> void: pass
|
|
func verify_completion(_runtime: Variant, _chapel: FacilityInstance, _service_id: StringName) -> void: pass
|
|
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,42607);clock.set_paused(true)
|
|
var original:Dictionary=runtime.create_snapshot()
|
|
var legacy:=original.duplicate(true)
|
|
legacy[&"systems"][&"runtime"][&"catalog_manifest"][&"manifest_version"]=1
|
|
legacy[&"systems"][&"runtime"][&"catalog_manifest"][&"staff_candidate_ids"].erase("staff_uma")
|
|
expect(runtime.restore_snapshot(legacy),"exact old twenty-candidate manifest loads without losing progress")
|
|
var malformed:=legacy.duplicate(true)
|
|
malformed[&"systems"][&"runtime"][&"catalog_manifest"][&"staff_candidate_ids"].erase("staff_akane")
|
|
var intact:Dictionary=runtime.create_snapshot()
|
|
expect(not runtime.restore_snapshot(malformed) and runtime.create_snapshot()==intact,"arbitrary incomplete legacy catalog is rejected atomically")
|
|
malformed=legacy.duplicate(true)
|
|
malformed[&"systems"][&"runtime"][&"staff"][&"staff"]=[42]
|
|
expect(not runtime.restore_snapshot(malformed) and runtime.create_snapshot()==intact,"legacy malformed staff rows are rejected without a script type error")
|
|
var main:Control=load("res://scenes/main/main.tscn").instantiate();root.add_child(main)
|
|
runtime.configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false})
|
|
await process_frame;await process_frame
|
|
expect(main.MVP_FACILITY_IDS.has(&"chapel"),"chapel is exposed in normal construction palette")
|
|
main.call("_select_build_definition",&"chapel");main.call("_on_map_cell_clicked",Vector3i(-6,0,0));clock.advance_minutes(180)
|
|
var chapel:FacilityInstance
|
|
for f:FacilityInstance in runtime.facility_service.get_instances():
|
|
if f.definition_id==&"chapel":chapel=f
|
|
expect(chapel!=null,"normal construction UI creates chapel")
|
|
if chapel==null:
|
|
var early_cleanup: Dictionary = await FixtureCleanup.free_owner_and_wait(self, main)
|
|
if not bool(early_cleanup.get(&"passed", false)):
|
|
push_error("Chapel ordinary owner cleanup failed: %s" % str(early_cleanup))
|
|
quit(96)
|
|
return
|
|
quit(failures)
|
|
return
|
|
expect(chapel.state==FacilityInstance.State.NO_STAFF,"chapel waits for cleric")
|
|
recruit_cleric(main, runtime)
|
|
expect(runtime.staff_service.has_staff(cleric_id()),"normal hire control recruits cleric")
|
|
var panel:StaffManagementPanel=main.find_child("StaffManagementPanel",true,false)
|
|
panel.refresh();panel.select_staff(cleric_id())
|
|
expect(panel.staff_detail_label.text.contains("聖職者"),"staff UI labels new role")
|
|
for i in panel.facility_option.item_count:
|
|
if panel.facility_option.get_item_metadata(i)==chapel.instance_id:
|
|
panel.facility_option.select(i);panel.facility_option.item_selected.emit(i)
|
|
panel.apply_button.pressed.emit();clock.advance_minutes(20)
|
|
expect(chapel.active_staff_ids.has(cleric_id()) and chapel.state==FacilityInstance.State.OPEN,"assigned cleric walks to workplace and opens chapel")
|
|
verify_effect(runtime, chapel)
|
|
expect(runtime.submit_command(&"spawn_guest",{&"guest_id":&"worship_walker",&"guest_type_id":&"traveler",&"gold":100,&"options":{&"current_cell":Vector3i(-7,0,0),&"state":GuestRuntime.State.DECIDING,&"planned_exit_at":clock.absolute_minute+300,&"needs":{&"sleep":0,&"hunger":0,&"hygiene":0,&"medical":0,&"leisure":100,&"intimacy":0}}}).is_success(),"controlled arrival without forced destination or service")
|
|
var service_id:StringName=&""
|
|
for minute in 30:
|
|
clock.advance_one_minute()
|
|
var g:GuestRuntime=runtime.guest_service.get_guest(&"worship_walker")
|
|
if g!=null and not g.current_service_id.is_empty():service_id=g.current_service_id;break
|
|
expect(not service_id.is_empty(),"guest autonomously selects, reaches and begins worship")
|
|
if not service_id.is_empty():
|
|
verify_after_start(runtime, chapel)
|
|
var midpoint:Dictionary=runtime.create_snapshot()
|
|
expect(runtime.restore_snapshot(midpoint),"normal cleric, visitor and worship save together")
|
|
for minute in 61:
|
|
clock.advance_one_minute()
|
|
if runtime.facility_service.get_service(service_id).state==ServiceInstance.State.COMPLETED:break
|
|
var completed := int(runtime.facility_service.get_instance(chapel.instance_id).lifetime_statistics.get(&"services_completed", 0))
|
|
expect(runtime.facility_service.get_service(service_id).state==ServiceInstance.State.COMPLETED and completed>0 and state.get_resource(&"faith")==completed and runtime.progression_service.metrics[&"faith_lifetime"]==completed,"each completed worship contributes exactly one Faith, including other autonomous visitors")
|
|
expect(runtime.economy_service.get_balance(&"GUEST_WALLET:worship_walker")==100-donation_price(),"actual worshipper pays quoted donation exactly once")
|
|
verify_completion(runtime, chapel, service_id)
|
|
expect(runtime.restore_snapshot(runtime.create_snapshot()),"completed chapel gameplay remains saveable")
|
|
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)==chapel.instance_id:
|
|
business.facility_option.select(i);business.facility_option.item_selected.emit(i)
|
|
expect(business.quote_label.text.contains("%dG" % donation_price()) and business.effect_label.text.contains("信仰+1"),"business UI explains donation price and per-completion faith")
|
|
if OS.get_environment("THE_TREE_CHAPEL_CAPTURE")=="1":
|
|
root.size=Vector2i(1440,900)
|
|
await process_frame;await process_frame;await RenderingServer.frame_post_draw
|
|
expect(root.get_texture().get_image().save_png(ProjectSettings.globalize_path(OS.get_environment("THE_TREE_CHAPEL_CAPTURE_PATH") if not OS.get_environment("THE_TREE_CHAPEL_CAPTURE_PATH").is_empty() else "res://artifacts/facility-dimensions-2026-09-29/chapel-gameplay.png"))==OK,"capture native chapel business screen")
|
|
var cleanup: Dictionary = await FixtureCleanup.free_owner_and_wait(self, main)
|
|
if not bool(cleanup.get(&"passed", false)):
|
|
push_error("Chapel ordinary owner cleanup failed: %s" % str(cleanup))
|
|
quit(96)
|
|
return
|
|
print("Chapel gameplay: %d checks, %d failures"%[checks,failures]);quit(failures)
|