class_name WorldTreeRankDialog extends ConfirmationDialog const LayerSkin := preload("res://scripts/ui/layer_interface_skin.gd") signal status_requested(message: String, success: bool) const LABELS := { &"reputation":"評判", &"asset_gold":"所持金", &"faith_lifetime":"累計信仰", &"guest_lifetime":"累計来客数", &"underground_influence":"裏社会への影響", &"reputation_or_underground_influence":"評判または裏社会への影響", &"active_above_ground_facilities":"地上の稼働施設", &"active_underground_facilities":"地下の稼働施設", &"important_rank_5":"重要クエスト", &"main_chapter_complete":"本編の章目標", } var _runtime: Variant var _audio_submitter := Callable() var _target := -1 var _pending_id := 0 var _queue_id := 0 var _skin_styles: Array[StyleBoxFlat] = [] func configure(runtime: Variant) -> void: _runtime=runtime func _ready() -> void: name="WorldTreeRankDialog" title="世界樹ランク" get_ok_button().text="昇格する" get_cancel_button().text="閉じる" confirmed.connect(_promote) _runtime.command_completed.connect(_on_command_completed) _build_skin() apply_layer_skin(LayerSkin.active_layer(self)) func show_rank() -> void: refresh() popup_centered(Vector2i(480,260)) func refresh() -> void: var queue_id: int=_runtime.command_queue.get_instance_id() if queue_id!=_queue_id: _pending_id=0 _queue_id=queue_id for command: Dictionary in _runtime.command_queue.create_snapshot().get("pending",[]): if command.get("command_type","")=="set_world_tree_rank": _pending_id=int(command["command_id"]) break var report: Dictionary=_runtime.get_live_progression_report() var rank: int=report[&"snapshot"][&"current_rank"] var evaluation: Dictionary=report[&"evaluation"] _target=rank+1 var lines: Array[String]=["現在のランク:%d" % rank] if rank>=ProgressionService.MAX_RANK: lines.append("最高ランクに到達しています。") else: lines.append("ランク%dへの条件" % _target) for requirement: Dictionary in evaluation[&"requirements"]: var label: String=LABELS.get(StringName(requirement[&"id"]),"進行条件") var value: String="%d / %d" % [requirement[&"current"],requirement[&"required"]] if requirement[&"comparison"]==&"QUEST_COMPLETED": value="達成済み" if requirement[&"met"] else "未達成" lines.append("%s %s:%s" % ["✓" if requirement[&"met"] else "・",label,value]) if evaluation.get(&"eligible",false):lines.append("条件を満たしています。昇格すると建設範囲が広がります。") elif evaluation.get(&"reason",&"")==&"QUARANTINED":lines.append("進行データの確認が必要なため、現在は昇格できません。") if evaluation.get(&"reason",&"")==&"OPERATIONS_BLOCKED": var reason: StringName=evaluation.get(&"block_reason",&"") lines.append("未払い経費を精算するまで昇格できません。" if reason in [&"ARREARS_REMAIN",&"UNPAID_EXPENSES"] else "ゲーム終了後は昇格できません。" if reason==&"BANKRUPT" else "営業状態の復旧が必要なため、現在は昇格できません。") if evaluation.get(&"reason",&"")==&"UNAVAILABLE":lines.append("条件を確認できません。もう一度開き直してください。") if _pending_id!=0:lines.append("昇格申請を受理しました。時間更新を待っています。") dialog_text="\n\n".join(lines) get_ok_button().disabled=rank>=ProgressionService.MAX_RANK or not evaluation.get(&"eligible",false) or _pending_id!=0 func _promote() -> void: if _pending_id!=0 or _target<2:return var result: CommandResult=_submit_ui_command(&"set_world_tree_rank",{&"rank":_target,&"request_id":StringName("ui_rank_%d" % _target)}) for command: Dictionary in _runtime.command_queue.create_snapshot().get("pending",[]): if result.is_success() and int(command["command_id"])==result.command_id: _pending_id=result.command_id status_requested.emit("昇格申請を受理しました。次の時間更新で反映します。",true) return _finish(result) func _on_command_completed(result: CommandResult) -> void: if _pending_id!=0 and result.command_id==_pending_id: _pending_id=0 _finish(result) func _finish(result: CommandResult) -> void: status_requested.emit("世界樹ランクが上がりました。" if result.is_success() else "昇格できませんでした。現在の条件を確認してください。",result.is_success()) refresh() func _build_skin() -> void: # Window uses a local Theme rather than Control theme overrides. # Keep native dialog input, focus and confirmation behaviour intact. theme = Theme.new() var panel := _skin_box(Color("f4e3bd"), &"panel_parchment") theme.set_stylebox("panel", "AcceptDialog", panel) var border := _skin_box(Color("49311f"), &"panel_outer") border.expand_margin_top = 32 theme.set_stylebox("embedded_border", "Window", border) theme.set_color("title_color", "Window", Color("fff0cf")) get_label().add_theme_color_override("font_color", Color("55371e")) LayerSkin.register_text(get_label(), 0) for button: Button in [get_ok_button(), get_cancel_button()]: for key: StringName in [&"normal", &"hover", &"pressed", &"disabled", &"focus"]: var role: StringName = &"button_normal" var color := Color("65452d") if key in [&"hover", &"focus"]: role = &"button_hover"; color = Color("896139") elif key == &"pressed": role = &"button_pressed"; color = Color("49311f") elif key == &"disabled": role = &"button_disabled"; color = Color("786852") button.add_theme_stylebox_override(key, _skin_box(color, role)) for key: StringName in [&"font_color", &"font_hover_color", &"font_pressed_color", &"font_hover_pressed_color", &"font_focus_color"]: button.add_theme_color_override(key, Color("fff0cf")) button.add_theme_color_override("font_disabled_color", Color("c7bda9")) LayerSkin.register_toggle_text(button, 0) func _skin_box(background: Color, role: StringName) -> StyleBoxFlat: var style := StyleBoxFlat.new() style.bg_color = background style.border_color = Color("a96f2f") style.set_border_width_all(2) style.set_content_margin_all(10) LayerSkin.register_style(style, role, 0) _skin_styles.append(style) return style func apply_layer_skin(layer: int) -> void: for style: StyleBoxFlat in _skin_styles: LayerSkin.apply_style(style, layer) LayerSkin.register_text(get_label(), layer) for button: Button in [get_ok_button(), get_cancel_button()]: LayerSkin.register_toggle_text(button, layer) 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)