Record original-alignment implementation and traceability checkpoint
Capture current source, content data, tests, asset licenses, and original-specification traceability. Original implementation remains incomplete. The accepted matching UI generation passed 154 suites and 12,253 checks, with eight rendered staff-contract screens reviewed. Latest native Windows and full-original acceptance remain outstanding.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
class_name InnOpeningGuide
|
||||
extends PanelContainer
|
||||
|
||||
const LayerSkin := preload("res://scripts/ui/layer_interface_skin.gd")
|
||||
|
||||
## Read-only guidance. Every action goes back through the normal dashboard.
|
||||
signal action_requested(action: StringName)
|
||||
|
||||
@@ -15,7 +17,7 @@ var _sale_economy_id := 0
|
||||
var _first_sale_minute := -1
|
||||
|
||||
|
||||
func setup(runtime: Variant, clock: Variant) -> void:
|
||||
func setup(runtime: Variant, clock: Variant, layer := 0) -> void:
|
||||
_runtime = runtime
|
||||
_clock = clock
|
||||
name = "InnOpeningGuide"
|
||||
@@ -25,6 +27,7 @@ func setup(runtime: Variant, clock: Variant) -> void:
|
||||
skin.border_color = Color("b58a45")
|
||||
skin.set_border_width_all(1)
|
||||
skin.set_content_margin_all(8)
|
||||
LayerSkin.register_style(skin, &"panel_leather", layer)
|
||||
add_theme_stylebox_override("panel", skin)
|
||||
var column := VBoxContainer.new()
|
||||
column.add_theme_constant_override("separation", 5)
|
||||
@@ -32,7 +35,8 @@ func setup(runtime: Variant, clock: Variant) -> void:
|
||||
_heading = Button.new()
|
||||
_heading.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
_heading.add_theme_font_size_override("font_size", 14)
|
||||
_heading.pressed.connect(func() -> void: _body.visible = not _body.visible)
|
||||
_heading.pressed.connect(_toggle_body)
|
||||
_style_button(_heading, layer)
|
||||
column.add_child(_heading)
|
||||
_body = VBoxContainer.new()
|
||||
column.add_child(_body)
|
||||
@@ -41,14 +45,33 @@ func setup(runtime: Variant, clock: Variant) -> void:
|
||||
_detail.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_detail.add_theme_font_size_override("font_size", 13)
|
||||
_detail.add_theme_color_override("font_color", Color("fff0cf"))
|
||||
LayerSkin.register_text(_detail, layer)
|
||||
_body.add_child(_detail)
|
||||
_action = Button.new()
|
||||
_action.add_theme_font_size_override("font_size", 13)
|
||||
_style_button(_action, layer)
|
||||
_action.pressed.connect(func() -> void: action_requested.emit(StringName(_progress.get(&"action", &""))))
|
||||
_body.add_child(_action)
|
||||
refresh()
|
||||
|
||||
|
||||
func _toggle_body() -> void:
|
||||
_body.visible = not _body.visible
|
||||
reset_size.call_deferred()
|
||||
|
||||
|
||||
func _style_button(button: Button, layer: int) -> void:
|
||||
button.add_theme_color_override("font_color", Color("fff0cf"))
|
||||
for state_name: StringName in [&"normal", &"hover", &"pressed", &"focus", &"disabled"]:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = Color("30261b") if state_name == &"normal" else Color("51402a")
|
||||
style.border_color = Color("b58a45")
|
||||
style.set_border_width_all(1)
|
||||
style.set_content_margin_all(4)
|
||||
LayerSkin.register_style(style, StringName("button_"+String(state_name if state_name != &"focus" else &"pressed")), layer)
|
||||
button.add_theme_stylebox_override(state_name, style)
|
||||
|
||||
|
||||
func refresh() -> void:
|
||||
if _runtime == null or _heading == null:
|
||||
return
|
||||
@@ -70,14 +93,14 @@ func _read_progress() -> Dictionary:
|
||||
if first_sale >= 0 and _runtime.operations_coordinator != null:
|
||||
for summary: Dictionary in _runtime.operations_coordinator.get_day_summaries():
|
||||
if int(summary.get(&"closed_at", -1)) > first_sale:
|
||||
return _step(&"complete", "初日の営業を達成", "宿泊売上と翌朝の決算を確認できました。帳簿を見ながら、客室と従業員を少しずつ増やしましょう。", &"ledger", "決算を見る")
|
||||
return _step(&"complete", "初日の営業を達成", "宿泊売上と日次決算を確認できました。帳簿を見ながら、客室と従業員を少しずつ増やしましょう。", &"ledger", "決算を見る")
|
||||
var reception: FacilityInstance
|
||||
var rooms: Array[FacilityInstance] = []
|
||||
for facility: FacilityInstance in _runtime.facility_service.get_instances():
|
||||
if facility.definition_id == &"reception":
|
||||
if reception == null or _reception_score(facility) > _reception_score(reception):
|
||||
reception = facility
|
||||
elif facility.definition_id == &"standard_room":
|
||||
elif _is_guest_lodging(facility.definition_id):
|
||||
rooms.append(facility)
|
||||
if reception == null:
|
||||
return _build_step(&"reception", &"reception", "1/6 受付をつくる", "表の地表階に受付を配置します。完成した受付の上に客室を増築できます。", &"build_reception")
|
||||
@@ -95,7 +118,7 @@ func _read_progress() -> Dictionary:
|
||||
return _step(&"staff", "4/6 受付係を配属", "従業員から受付係を雇い、雇用済み一覧でこの受付と勤務帯を選び「配属・勤務帯を変更」を押します。", &"staff", "従業員を開く")
|
||||
if first_sale < 0:
|
||||
return _step(&"sale", "5/6 最初の宿泊売上", "時間を進めて、お客さまの到着と宿泊を見守りましょう。売上は現在のサービスが完了すると記帳されます。", &"resume" if _clock.paused else &"ledger", "時間を進める" if _clock.paused else "帳簿を見る")
|
||||
return _step(&"close", "6/6 翌朝の決算へ", "最初の宿泊売上が入りました。06:00に営業日が締まり、給与・利益・未払いを帳簿で確認できます。", &"resume" if _clock.paused else &"ledger", "時間を進める" if _clock.paused else "帳簿を見る")
|
||||
return _step(&"close", "6/6 深夜の決算へ", "最初の宿泊売上が入りました。00:00に営業日が締まり、給与・利益・未払いを帳簿で確認できます。", &"resume" if _clock.paused else &"ledger", "時間を進める" if _clock.paused else "帳簿を見る")
|
||||
|
||||
|
||||
func _can_reach_facility(facility: FacilityInstance) -> bool:
|
||||
@@ -103,6 +126,8 @@ func _can_reach_facility(facility: FacilityInstance) -> bool:
|
||||
return false
|
||||
# Runtime uses the same public entrance and access cells as real guests.
|
||||
# Component-only guide fixtures retain their explicit availability flags.
|
||||
if _runtime.has_method(&"is_facility_reachable"):
|
||||
return bool(_runtime.call(&"is_facility_reachable", facility.instance_id))
|
||||
if _runtime.has_method(&"get_facility_access_report"):
|
||||
var report: Dictionary = _runtime.call(&"get_facility_access_report", facility.instance_id)
|
||||
return bool(report.get(&"reachable", false))
|
||||
@@ -114,18 +139,37 @@ func _reception_score(facility: FacilityInstance) -> int:
|
||||
|
||||
|
||||
func _has_reception_assignment(reception: FacilityInstance) -> bool:
|
||||
var assigned := not reception.active_staff_ids.is_empty()
|
||||
# A repeating plan remains valid off-duty. Historical or cancelled shifts
|
||||
# cannot conceal a deliberate unassignment made before the first sale.
|
||||
var definition: FacilityDefinition = _runtime.definition_registry.get_facility(reception.definition_id)
|
||||
if definition == null:
|
||||
return false
|
||||
var unplanned_staff: Dictionary = {}
|
||||
# Repeating plans remain valid off-duty; explicit plans take precedence
|
||||
# over historical shifts. Management placement is not receptionist work.
|
||||
for staff: StaffRuntime in _runtime.staff_service.get_staff_members():
|
||||
if not definition.required_roles.is_empty() and staff.role_id not in definition.required_roles:
|
||||
continue
|
||||
if staff.staff_id in reception.active_staff_ids:
|
||||
return true
|
||||
var plan: Dictionary = _runtime.staff_service.get_work_assignment(staff.staff_id)
|
||||
if not plan.is_empty():
|
||||
assigned = assigned or StringName(plan.get(&"facility_id", &"")) == reception.instance_id
|
||||
continue
|
||||
for shift: ShiftInstance in _runtime.staff_service.get_shifts():
|
||||
if shift.staff_id == staff.staff_id and not shift.cancelled and shift.end_at > _clock.absolute_minute and shift.assigned_facility_id == reception.instance_id:
|
||||
assigned = true
|
||||
return assigned
|
||||
if StringName(plan.get(&"facility_id", &"")) == reception.instance_id:
|
||||
return true
|
||||
else:
|
||||
unplanned_staff[staff.staff_id] = true
|
||||
if unplanned_staff.is_empty():
|
||||
return false
|
||||
# Enumerate/sort the historical shifts once, not once per employee.
|
||||
for shift: ShiftInstance in _runtime.staff_service.get_shifts():
|
||||
if unplanned_staff.has(shift.staff_id) and not shift.cancelled and shift.end_at > _clock.absolute_minute and shift.assigned_facility_id == reception.instance_id:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _is_guest_lodging(definition_id: StringName) -> bool:
|
||||
var definition: FacilityDefinition = _runtime.definition_registry.get_facility(definition_id)
|
||||
return definition != null and definition.layer == FacilityDefinition.ViewLayer.FRONT and (
|
||||
definition.service_types.has(&"lodging") or definition.tags.has(&"lodging")
|
||||
)
|
||||
|
||||
|
||||
func _first_lodging_sale() -> int:
|
||||
@@ -139,10 +183,10 @@ func _first_lodging_sale() -> int:
|
||||
return _first_sale_minute
|
||||
var room_ids: Dictionary = {}
|
||||
for job: ConstructionJob in _runtime.construction_service.get_jobs():
|
||||
if job.definition_id == &"standard_room" and not job.facility_instance_id.is_empty():
|
||||
if _is_guest_lodging(job.definition_id) and not job.facility_instance_id.is_empty():
|
||||
room_ids[job.facility_instance_id] = true
|
||||
for facility: FacilityInstance in _runtime.facility_service.get_instances():
|
||||
if facility.definition_id == &"standard_room":
|
||||
if _is_guest_lodging(facility.definition_id):
|
||||
room_ids[facility.instance_id] = true
|
||||
if room_ids.is_empty():
|
||||
return -1
|
||||
@@ -154,7 +198,7 @@ func _first_lodging_sale() -> int:
|
||||
|
||||
func _build_step(stage: StringName, definition_id: StringName, title: String, detail: String, action: StringName) -> Dictionary:
|
||||
for job: ConstructionJob in _runtime.construction_service.get_jobs():
|
||||
if job.definition_id == definition_id and job.state not in [ConstructionJob.State.COMPLETED, ConstructionJob.State.CANCELLED]:
|
||||
if (job.definition_id == definition_id or (stage == &"room" and _is_guest_lodging(job.definition_id))) and job.state not in [ConstructionJob.State.COMPLETED, ConstructionJob.State.CANCELLED]:
|
||||
return _step(stage, title, "工事中 %d%%。時間を進めると完成します。" % (job.progress / 100), &"resume" if _clock.paused else &"", "時間を進める")
|
||||
var definition: FacilityDefinition = _runtime.definition_registry.get_facility(definition_id)
|
||||
if definition != null:
|
||||
|
||||
Reference in New Issue
Block a user