From c7646c5489ef760440a5684501d77105656946f2 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Wed, 30 Sep 2026 07:27:02 +0800 Subject: [PATCH] =?UTF-8?q?iter9-T14:=20=E5=8D=A1=E2=91=AD=20=E8=90=A5?= =?UTF-8?q?=E5=9C=B0=E7=95=8C=E9=9D=A2=E8=A7=86=E8=A7=89=E7=BB=88=E7=A8=BF?= =?UTF-8?q?=EF=BC=88=E5=AF=B9=E7=85=A7=E6=96=B9=E5=90=91=E7=A8=BF=204-camp?= =?UTF-8?q?.png=20=E9=87=8D=E6=8E=92=EF=BC=89=E2=80=94=E2=80=94=E7=9F=B3?= =?UTF-8?q?=E7=BA=B9=E5=85=A8=E5=B1=8F=E5=BA=95=EF=BC=88=E6=B5=85=20dim=20?= =?UTF-8?q?=E9=80=8F=E5=87=BA=EF=BC=89+=E9=A1=B6=E6=A0=8F=E9=93=AD?= =?UTF-8?q?=E7=89=8C=EF=BC=88=E6=A0=87=E9=A2=98+=E5=89=AF=E9=A2=98?= =?UTF-8?q?=EF=BC=89/=E9=92=A5=E7=9F=B3=E5=BE=BD=EF=BC=88=E6=9A=97?= =?UTF-8?q?=E5=BA=95=E9=87=91=E6=96=87=EF=BC=89+=E4=B8=89=E6=9F=9C?= =?UTF-8?q?=E5=8F=B0=E5=88=97=EF=BC=88=E5=B1=9E=E6=80=A7=E9=94=BB=E9=80=A0?= =?UTF-8?q?/=E9=81=93=E5=85=B7=E5=B7=A5=E5=9D=8A/=E5=A5=96=E5=8A=B1?= =?UTF-8?q?=E6=A0=BC=E5=9B=BE=E9=89=B4=EF=BC=9A=E5=A4=B4=E5=B8=A6=E6=B7=B1?= =?UTF-8?q?=E6=A3=95=20122,82,50+=E7=B1=B3=E6=9D=BF=E8=BA=AB+=E5=86=85?= =?UTF-8?q?=E5=B5=8C=E8=A1=8C=E6=9D=BF=EF=BC=8C=E6=9A=97=E5=BA=95=E6=9A=96?= =?UTF-8?q?=E7=99=BD=E6=97=8F=E2=86=92=E4=BA=AE=E6=9D=BF=E6=B7=B1=E5=A2=A8?= =?UTF-8?q?=E6=97=8F=E5=8F=8C=E8=89=B2=E5=A2=A8=E5=88=B6=EF=BC=89+?= =?UTF-8?q?=E5=BA=95=E6=A0=8F=E5=85=B3=E9=97=AD=E9=92=AE/=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=B3=A8=E8=AE=B0+=E6=9C=80=E8=BF=91=E5=86=92?= =?UTF-8?q?=E9=99=A9=E6=94=B6=E6=9D=A1=E5=B8=A6=EF=BC=9B=E8=A1=8C=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E7=9F=AD=E6=A0=BC=E5=BC=8F=EF=BC=88=E5=90=8D=20+N/?= =?UTF-8?q?=E7=BA=A7/Lv/=E4=BB=B7=E7=AD=BE=20N=20=E9=92=A5=E7=9F=B3?= =?UTF-8?q?=E2=80=94=E2=80=94=E5=88=97=E5=AE=BD=E6=94=B6=E6=95=9B=E9=98=B2?= =?UTF-8?q?=E6=BA=A2=E5=87=BA=EF=BC=8C=E8=A1=8C=E6=96=87=3D=E4=BB=A3?= =?UTF-8?q?=E6=8B=8D=E6=9D=BF=EF=BC=89=EF=BC=9B=E4=BF=A1=E5=8F=B7=E9=9D=A2?= =?UTF-8?q?/=E6=8A=95=E5=BD=B1=E5=A5=91=E7=BA=A6=E9=9B=B6=E5=8F=98?= =?UTF-8?q?=E5=8C=96=EF=BC=88buy=5Frequested/closed=E3=80=81open=5Fcamp/re?= =?UTF-8?q?fresh=5Fcamp=E3=80=81=5Fforge=5Frows=20=E8=A1=8C=E9=94=AE?= =?UTF-8?q?=E2=80=94=E2=80=94=E6=8E=A2=E9=92=88=E4=BE=9D=E8=B5=96=E9=9D=A2?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=EF=BC=89=EF=BC=9B=E9=97=B8=3D=E5=86=92?= =?UTF-8?q?=E7=83=9F=20596/0+click=20=E9=97=AE=E9=A2=98=3D0=EF=BC=88?= =?UTF-8?q?=E8=90=A5=E5=9C=B0=E8=B4=AD=E4=B9=B0=E7=9C=9F=E5=AE=9E=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=EF=BC=89+doc=20=E4=B8=89=E9=97=B8=E9=9B=B6=E6=96=B0?= =?UTF-8?q?=E5=A2=9E+=E7=86=B5=E5=A2=9E=20PASS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/presentation/views/camp_overlay_view.gd | 216 ++++++++++++------- 1 file changed, 137 insertions(+), 79 deletions(-) diff --git a/game/presentation/views/camp_overlay_view.gd b/game/presentation/views/camp_overlay_view.gd index c69141ae..7f46d85a 100644 --- a/game/presentation/views/camp_overlay_view.gd +++ b/game/presentation/views/camp_overlay_view.gd @@ -1,15 +1,13 @@ # VERTICAL SLICE - NOT FOR PRODUCTION -# Date: 2026-09-21(元进度实现批——营地覆盖层呈现) -# 营地覆盖层(模态):标题「营地 · 永久强化」+ 钥石余额 / 柜台一「属性锻造」(三行可购——显示名 · -# 当前 Lv · 每级 +flat · 下级价格 · 购买按钮余额不足禁用)/ 柜台二「道具工坊」(六行——显示名 · -# 解锁条件 · 进度 · 状态;局内效果排 Alpha 魔法道具重设计批——代拍板 3,注记一行)/ 柜台三 -# 「奖励格图鉴」(占位锁定行——内容排 Alpha 地图战斗资源差异化批——代拍板 4)/「最近冒险」列表 -# (recent_summaries 投影:结果/通关数/钥石合计/种子)/ 关闭按钮。 -# 挂接方式:仿 ShopOverlay(dim + CenterContainer + box);开合与开始层互斥仿 TunePanel 先例 -# (开始覆盖层非模态且树序在后——打开本层前由组合根隐藏开始层,规范 2.3 遮挡纪律)。 +# Date: 2026-09-21(元进度实现批——营地覆盖层呈现;2026-09-30 迭代 9 卡⑭ 视觉终稿——对照营地屏 +# 方向稿 artwork/mockups/v3-draft-2026-09-29/4-camp.png 重排:石纹全屏底 + 顶栏铭牌/钥石徽 + +# 三柜台列(属性锻造/道具工坊/奖励格图鉴,头带深棕+米色板身+内嵌行板,暗底→亮板双色墨制)+ +# 底栏关闭钮/操作注记;最近冒险收底栏条带。信号面/投影契约零变化:buy_requested(attr)/closed、 +# open_camp(data)/refresh_camp(data)、_forge_rows 行结构 {attr,level_l,price_l,btn}(探针依赖)。 +# 挂接方式:开合与开始层互斥仿 TunePanel 先例(开始覆盖层非模态且树序在后——打开本层前由组合根 +# 隐藏开始层,规范 2.3 遮挡纪律)。 # 高内聚边界:纯视图 setter 面——账本快照经组合根喂入(MetaProgression 只读投影),购买/关闭 -# 意图经信号外发——零核心写调用、零 MetaProgression 持有。视觉 = ui_kit 程序占位 -#(代拍板 8——视觉终稿以表现层样张过审为前置,归 HUD 协作批)。 +# 意图经信号外发——零核心写调用、零 MetaProgression 持有。 class_name CampOverlay extends Control @@ -17,6 +15,10 @@ signal buy_requested(attr: String) signal closed const ATTR_LABELS := {"atk": "攻击", "max_hp": "生命上限", "armor_class": "护甲"} # 档位文案轴(数据契约 attr 词表,与 ShopOverlay 同款) +# 方向稿取色(4-camp.png——柜台头带深棕/行板暖米;双色墨=亮板配深墨) +const HEADER_BAND_COL := Color8(122, 82, 50) +const ROW_PLATE_COL := Color8(240, 230, 206) +const BADGE_PANEL_COL := Color8(40, 32, 24) var _balance_label: Label var _forge_holder: VBoxContainer @@ -28,81 +30,132 @@ var _recent_list: Label # 最近冒险(逐行拼接 label——只读 func _init() -> void: var dim := ColorRect.new() - dim.color = Color(0, 0, 0, 0.72) + dim.color = Color(0, 0, 0, 0.45) # 方向稿=石纹底透出(浅 dim——石纹全屏底担当氛围) dim.set_anchors_preset(Control.PRESET_FULL_RECT) add_child(dim) - var center := CenterContainer.new() - center.set_anchors_preset(Control.PRESET_FULL_RECT) - dim.add_child(center) - var frame := PanelContainer.new() - frame.add_theme_stylebox_override("panel", UiKit.frame_skinned(Vector4(26, 22, 26, 22))) # 仪式石框(T2;缺位回退暗面板) - center.add_child(frame) - var box := VBoxContainer.new() - box.add_theme_constant_override("separation", 6) - frame.add_child(box) - var title := UiKit.label("营地 · 永久强化", 24, true) - title.add_theme_color_override("font_color", UiKit.WARM) - title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - box.add_child(title) + # 石纹底噪(样张 v2 冻结件——start overlay 同款;缺位不挂即回退平 dim) + var bd_tex := UiKit.load_tex(UiKit.TEX_BACKDROP_STONE) + if bd_tex != null: + var bd := TextureRect.new() + bd.texture = bd_tex + bd.stretch_mode = TextureRect.STRETCH_TILE + bd.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST + bd.set_anchors_preset(Control.PRESET_FULL_RECT) + bd.mouse_filter = Control.MOUSE_FILTER_IGNORE + dim.add_child(bd) + + var root := MarginContainer.new() + root.set_anchors_preset(Control.PRESET_FULL_RECT) + root.add_theme_constant_override("margin_left", 16) + root.add_theme_constant_override("margin_right", 16) + root.add_theme_constant_override("margin_top", 12) + root.add_theme_constant_override("margin_bottom", 12) + dim.add_child(root) + var col := VBoxContainer.new() + col.add_theme_constant_override("separation", 8) + root.add_child(col) + + # ── 顶栏:左铭牌(标题+副题)/ 右钥石徽 ── + var top := HBoxContainer.new() + top.add_theme_constant_override("separation", 10) + col.add_child(top) + var plaque := PanelContainer.new() + plaque.add_theme_stylebox_override("panel", + UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER, 2, 1, Vector4(14, 8, 14, 8))) + top.add_child(plaque) + var plaque_col := VBoxContainer.new() + plaque.add_child(plaque_col) + var title := UiKit.label("营地 · 永久强化", 22, true) + title.add_theme_color_override("font_color", UiKit.INK_TITLE) + plaque_col.add_child(title) + var sub := UiKit.label("跨局成长账本——钥石换永久属性", 13, false) + sub.add_theme_color_override("font_color", UiKit.STONE) + plaque_col.add_child(sub) + var spacer := Control.new() + spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL + top.add_child(spacer) + var badge := PanelContainer.new() + badge.add_theme_stylebox_override("panel", + UiKit.panel_flat(BADGE_PANEL_COL, UiKit.PANEL_BORDER, 2, 1, Vector4(14, 8, 14, 8))) + top.add_child(badge) var bal_row := HBoxContainer.new() bal_row.add_theme_constant_override("separation", 6) - bal_row.alignment = BoxContainer.ALIGNMENT_CENTER + badge.add_child(bal_row) var keystone_icon := UiKit.icon_rect(UiKit.TEX_ICON_KEYSTONE, 18) # 缺位 null → 纯文本回退 if keystone_icon != null: bal_row.add_child(keystone_icon) _balance_label = UiKit.label("钥石 0", 18, true) _balance_label.add_theme_color_override("font_color", UiKit.GOLD) bal_row.add_child(_balance_label) - box.add_child(bal_row) - box.add_child(HSeparator.new()) - box.add_child(_counter_header("属性锻造(钥石直购 · 每级 flat 整数 · 价格几何递增)", UiKit.TEX_ICON_FORGE)) + # ── 三柜台列(方向稿同构:头带深棕+米色板身)── + var mid := HBoxContainer.new() + mid.add_theme_constant_override("separation", 18) + mid.alignment = BoxContainer.ALIGNMENT_CENTER + mid.size_flags_vertical = Control.SIZE_EXPAND_FILL + col.add_child(mid) _forge_holder = VBoxContainer.new() - _forge_holder.add_theme_constant_override("separation", 4) - box.add_child(_forge_holder) - - box.add_child(_counter_header("道具工坊(累计通关次数解锁 · 局内效果排 Alpha 魔法道具重设计批)", UiKit.TEX_ICON_WORKSHOP)) + _forge_holder.add_theme_constant_override("separation", 6) + mid.add_child(_counter_panel("属性锻造", UiKit.TEX_ICON_FORGE, _forge_holder, 356)) _workshop_holder = VBoxContainer.new() - _workshop_holder.add_theme_constant_override("separation", 4) - box.add_child(_workshop_holder) - - box.add_child(_counter_header("奖励格图鉴", UiKit.TEX_ICON_ATLAS)) + _workshop_holder.add_theme_constant_override("separation", 6) + mid.add_child(_counter_panel("道具工坊", UiKit.TEX_ICON_WORKSHOP, _workshop_holder, 356)) + var atlas_holder := VBoxContainer.new() + mid.add_child(_counter_panel("奖励格图鉴", UiKit.TEX_ICON_ATLAS, atlas_holder, 356)) var lock_l := UiKit.label(" —— 柜台结构位预留:内容排 Alpha(地图战斗资源差异化批)", 13, false) - lock_l.add_theme_color_override("font_color", UiKit.WARM_FAINT) - box.add_child(lock_l) - box.add_child(HSeparator.new()) - - box.add_child(_counter_header("最近冒险")) - var scroll := ScrollContainer.new() - scroll.custom_minimum_size = Vector2(560, 96) - scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED - box.add_child(scroll) - _recent_list = UiKit.label("", 13, false) - _recent_list.add_theme_color_override("font_color", UiKit.WARM_SOFT) - _recent_list.custom_minimum_size = Vector2(544, 0) - _recent_list.autowrap_mode = TextServer.AUTOWRAP_OFF - scroll.add_child(_recent_list) + lock_l.add_theme_color_override("font_color", UiKit.STONE) + lock_l.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + lock_l.custom_minimum_size = Vector2(300, 0) + atlas_holder.add_child(lock_l) + # ── 底栏:关闭钮(左)/ 操作注记(右)+ 最近冒险条带 ── var close_btn := UiKit.button("关闭营地(回开始界面)") close_btn.pressed.connect(_emit_closed) - box.add_child(close_btn) + var bottom := HBoxContainer.new() + bottom.add_theme_constant_override("separation", 10) + bottom.add_child(close_btn) + var spacer2 := Control.new() + spacer2.size_flags_horizontal = Control.SIZE_EXPAND_FILL + bottom.add_child(spacer2) + var caption := UiKit.label("每购得一件永久强化,对应柜台亮起一格暖光 · 价格为钥石", 13, false) + caption.add_theme_color_override("font_color", UiKit.WARM_SOFT) + bottom.add_child(caption) + col.add_child(bottom) + _recent_list = UiKit.label("", 13, false) + _recent_list.add_theme_color_override("font_color", UiKit.WARM_SOFT) + _recent_list.clip_text = true + _recent_list.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + col.add_child(_recent_list) visible = false -func _counter_header(text: String, icon_path := "") -> Control: - var row := HBoxContainer.new() - row.add_theme_constant_override("separation", 6) +# 柜台列面板(方向稿同构):PanelContainer 米板身 + 头带深棕(图标+标题暖白) +func _counter_panel(title_text: String, icon_path: String, holder: VBoxContainer, min_w: int) -> PanelContainer: + var panel := PanelContainer.new() + panel.custom_minimum_size = Vector2(min_w, 0) + panel.add_theme_stylebox_override("panel", + UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER, 3, 1, Vector4(10, 10, 10, 10))) + var vbox := VBoxContainer.new() + vbox.add_theme_constant_override("separation", 8) + panel.add_child(vbox) + var band := PanelContainer.new() + band.add_theme_stylebox_override("panel", UiKit.panel_flat(HEADER_BAND_COL, UiKit.PANEL_BORDER, 2, 1, Vector4(10, 5, 10, 5))) + vbox.add_child(band) + var head := HBoxContainer.new() + head.add_theme_constant_override("separation", 6) + band.add_child(head) if icon_path != "": var ic := UiKit.icon_rect(icon_path, 16) # 缺位 null → 纯文本回退 if ic != null: - row.add_child(ic) - var l := UiKit.label(text, 15, true) - l.add_theme_color_override("font_color", UiKit.WARM_SOFT) - row.add_child(l) - return row + head.add_child(ic) + var l := UiKit.label(title_text, 16, true) + l.add_theme_color_override("font_color", UiKit.WARM) + head.add_child(l) + vbox.add_child(holder) + return panel -# ---- 柜台行构建(open_camp 重建;行结构仿 ShopOverlay 商品卡)---- +# ---- 柜台行构建(open_camp 重建;行结构仿 ShopOverlay 商品卡——亮板双色墨制)---- # 打开营地(全量重建三柜台行 + 最近冒险——数据 = 组合根 _camp_data() 投影) func open_camp(data: Dictionary) -> void: @@ -125,7 +178,7 @@ func refresh_camp(data: Dictionary) -> void: if row.is_empty(): continue card.level_l.text = "Lv %d" % int(row.get("level", 0)) - card.price_l.text = "下级价格 %d 钥石" % int(row.get("price", 0)) + card.price_l.text = "%d 钥石" % int(row.get("price", 0)) card.btn.disabled = balance < int(row.get("price", 0)) # 余额不足禁用置灰 var ws_by_id := {} for row in data.get("workshop", []): @@ -138,18 +191,19 @@ func refresh_camp(data: Dictionary) -> void: var prog := int(row.get("progress", 0)) var unlocked := bool(row.get("unlocked", false)) card.progress_l.text = "累计通关 %d / %d 次" % [prog, th] - # 迭代 7 T5——失义件(显影尘/地穴全图卷 Alpha 重定)与退役件(探宝罗盘 2026-09-29 拍板①乙)的呈现口径 + # 迭代 7 T5——失义件(显影尘/地穴全图卷 Alpha 重定)与退役件(探宝罗盘 2026-09-29 拍板①乙)呈现口径; + # 状态色随卡⑭ 亮板双色墨制(深墨族替代暖白族——亮板上暖白不可读) var st_text := "未解锁" - var st_col: Color = UiKit.WARM_FAINT + var st_col: Color = UiKit.STONE if bool(row.get("retired", false)): st_text = "已退役" - st_col = UiKit.WARM_FAINT + st_col = UiKit.STONE elif bool(row.get("deferred", false)) and unlocked: st_text = "已解锁 · 能力封存中" - st_col = UiKit.GOLD + st_col = UiKit.GOLD_DEEP elif unlocked: st_text = "已解锁" - st_col = UiKit.GOLD + st_col = UiKit.GOLD_DEEP card.status_l.text = st_text card.status_l.add_theme_color_override("font_color", st_col) @@ -164,20 +218,22 @@ func _rebuild_forge(data: Dictionary) -> void: func _build_forge_row(holder: VBoxContainer, row: Dictionary) -> Dictionary: var card := PanelContainer.new() - card.add_theme_stylebox_override("panel", UiKit.panel_flat(UiKit.BG_OVERLAY, UiKit.GOLD_DIM, 4, 1, Vector4(12, 4, 12, 4))) + card.add_theme_stylebox_override("panel", UiKit.panel_flat(ROW_PLATE_COL, UiKit.PANEL_BORDER, 2, 1, Vector4(10, 4, 10, 4))) var line := HBoxContainer.new() line.add_theme_constant_override("separation", 12) card.add_child(line) var attr := String(row.get("attr", "")) - var name_l := UiKit.label("%s(每级 %+d flat)" % [String(row.get("display_name", "")), int(row.get("flat", 0))], 14, true) - name_l.custom_minimum_size = Vector2(210, 0) + var name_l := UiKit.label("%s %+d/级" % [String(row.get("display_name", "")), int(row.get("flat", 0))], 14, true) + name_l.add_theme_color_override("font_color", UiKit.INK) + name_l.custom_minimum_size = Vector2(132, 0) line.add_child(name_l) var level_l := UiKit.label("", 14, false) - level_l.custom_minimum_size = Vector2(64, 0) + level_l.add_theme_color_override("font_color", UiKit.INK) + level_l.custom_minimum_size = Vector2(44, 0) line.add_child(level_l) var price_l := UiKit.label("", 14, false) - price_l.add_theme_color_override("font_color", UiKit.WARM_SOFT) - price_l.custom_minimum_size = Vector2(150, 0) + price_l.add_theme_color_override("font_color", UiKit.STONE) + price_l.custom_minimum_size = Vector2(64, 0) line.add_child(price_l) var btn := UiKit.button("锻造 +1 级") btn.pressed.connect(_emit_buy_requested.bind(attr)) @@ -192,18 +248,20 @@ func _rebuild_workshop(data: Dictionary) -> void: child.queue_free() for row in data.get("workshop", []): var card := PanelContainer.new() - card.add_theme_stylebox_override("panel", UiKit.panel_flat(UiKit.BG_OVERLAY, UiKit.WARM_FAINT, 4, 1, Vector4(12, 4, 12, 4))) + card.add_theme_stylebox_override("panel", UiKit.panel_flat(ROW_PLATE_COL, UiKit.PANEL_BORDER, 2, 1, Vector4(10, 4, 10, 4))) var line := HBoxContainer.new() line.add_theme_constant_override("separation", 12) card.add_child(line) var name_l := UiKit.label(String(row.get("display_name", "")), 14, true) - name_l.custom_minimum_size = Vector2(210, 0) + name_l.add_theme_color_override("font_color", UiKit.INK) + name_l.custom_minimum_size = Vector2(132, 0) line.add_child(name_l) var progress_l := UiKit.label("", 13, false) - progress_l.add_theme_color_override("font_color", UiKit.WARM_SOFT) - progress_l.custom_minimum_size = Vector2(150, 0) + progress_l.add_theme_color_override("font_color", UiKit.STONE) + progress_l.custom_minimum_size = Vector2(110, 0) line.add_child(progress_l) var status_l := UiKit.label("", 13, true) + status_l.add_theme_color_override("font_color", UiKit.STONE) line.add_child(status_l) _workshop_holder.add_child(card) _workshop_rows.append({"item_id": String(row.get("item_id", "")), "progress_l": progress_l, "status_l": status_l}) @@ -213,16 +271,16 @@ func _rebuild_recent(data: Dictionary) -> void: var lines: Array[String] = [] var recent: Array = data.get("recent", []) if recent.is_empty(): - lines.append(" (暂无冒险记录——完成或结束一次冒险后入账)") + lines.append(" 最近冒险:(暂无记录——完成或结束一次冒险后入账)") for s in recent: var verdict := "失败" if String(s.get("result", "")) == "completed": verdict = "完成" elif String(s.get("result", "")) == "abandoned": verdict = "放弃" - lines.append("%s · 通关 %d 关 · 钥石 +%d · 种子 %d" % [verdict, + lines.append("最近冒险:%s · 通关 %d 关 · 钥石 +%d · 种子 %d" % [verdict, int(s.get("levels_cleared", 0)), int(s.get("keystone_total", 0)), int(s.get("master_seed", 0))]) - _recent_list.text = "\n".join(lines) + _recent_list.text = " | ".join(lines) func _emit_closed() -> void: