卡②T2b(呈现层结构收敛批): u8–u17——u9 battle_stage_view(_init拆背景/光柱/世界/文本半区[轮次牌/中段行]/伴随件六族+_enemy_portrait_tex查表化+_spawn_enemy_standee循环提函数)+u10 curio_pick(_init拆顶条/主体两域+_icon_for_id映射表化)+u11 settings(_build拆头部/音量/全屏/演出/返回五行域)+u12 battle_log_view(_format_row按行型拆九私有格式化函数[effect/damage/ineffective/seal_miss/verdict/simple三型/default]+dispatch出参聚合)+u14 ap_bar(_init拆AP计量/RAP/确认/图例刷新四域)+u15 board_zone(_init拆视图/角标+棋盘子件域)+u16 board_fx(光带循环提_spawn_sweep_band)+u17 legend(行构建提_legend_row)+u8 ui_assembler(build_start_overlay拆双列/左列/右列/单立绘四族);gdstyle基线内45→28键
This commit is contained in:
1 parent
123d7c7832
commit
525529ad88
8 files changed
+318
-176
No files matched your search
@@ -104,28 +104,8 @@ static func build_start_overlay(host: Control, db: ConfigDb = null) -> Dictionar
|
|||||||
overlay.add_child(UiKit._beams_rect())
|
overlay.add_child(UiKit._beams_rect())
|
||||||
overlay.add_child(UiKit.vignette_rect())
|
overlay.add_child(UiKit.vignette_rect())
|
||||||
# 双列骨架:左=操作列 56% / 右=舞台(立绘看台)
|
# 双列骨架:左=操作列 56% / 右=舞台(立绘看台)
|
||||||
var cols := HBoxContainer.new()
|
var cols := _start_columns(overlay)
|
||||||
cols.set_anchors_preset(Control.PRESET_FULL_RECT)
|
var box := _start_left_column(cols)
|
||||||
cols.add_theme_constant_override("separation", 32)
|
|
||||||
var pad := MarginContainer.new()
|
|
||||||
pad.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
||||||
for side in ["margin_left", "margin_right", "margin_top", "margin_bottom"]:
|
|
||||||
pad.add_theme_constant_override(side, 56)
|
|
||||||
cols.add_child(pad)
|
|
||||||
overlay.add_child(cols)
|
|
||||||
var box := VBoxContainer.new()
|
|
||||||
box.name = "start_box"
|
|
||||||
box.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
||||||
box.size_flags_stretch_ratio = 1.4
|
|
||||||
box.add_theme_constant_override("separation", 10)
|
|
||||||
pad.add_child(box)
|
|
||||||
|
|
||||||
var title := UiKit.label("Dungeon Sweeper",UiKit.FS_H1, true, UiKit.INK_ON_DEEP)
|
|
||||||
box.add_child(title)
|
|
||||||
box.add_child(HSeparator.new())
|
|
||||||
|
|
||||||
# 三入口(主菜单三入口化——营地交互重做卡②,用户裁决 1:进入存档/设置/退出游戏;
|
|
||||||
# 组帽双撤——冒险组帽组内零钮退化态不留、「营地与系统」帽指称失义,追认单留痕)
|
|
||||||
var entersavebtn := UiKit.primary_button("进入存档") # 主操作钮(唯一进度入口)
|
var entersavebtn := UiKit.primary_button("进入存档") # 主操作钮(唯一进度入口)
|
||||||
entersavebtn.tooltip_text = "选择一个存档位进入(新档 / 进档 / 删档)"
|
entersavebtn.tooltip_text = "选择一个存档位进入(新档 / 进档 / 删档)"
|
||||||
box.add_child(entersavebtn)
|
box.add_child(entersavebtn)
|
||||||
@@ -135,12 +115,45 @@ static func build_start_overlay(host: Control, db: ConfigDb = null) -> Dictionar
|
|||||||
# 退出游戏与设置同层并行——只在一级菜单出现(行为零变化——契约 2)
|
# 退出游戏与设置同层并行——只在一级菜单出现(行为零变化——契约 2)
|
||||||
var quitbtn := UiKit.button("退出游戏")
|
var quitbtn := UiKit.button("退出游戏")
|
||||||
box.add_child(quitbtn)
|
box.add_child(quitbtn)
|
||||||
|
|
||||||
# 调试入口收浮层角标;boot 菜单优先不开
|
# 调试入口收浮层角标;boot 菜单优先不开
|
||||||
# 浮窗,调试入口=UI 最顶层全局浮层角标(build_debug_badge——LAYER_CONTRACT 末位、
|
# 浮窗,调试入口=UI 最顶层全局浮层角标(build_debug_badge——LAYER_CONTRACT 末位、
|
||||||
# ModalStack 登记外,任何 UI 不遮挡;本层不设屏内调试角标,全局浮层全场景承载)
|
# ModalStack 登记外,任何 UI 不遮挡;本层不设屏内调试角标,全局浮层全场景承载)
|
||||||
|
_start_right_column(cols)
|
||||||
|
return {"overlay": overlay, "box": box,
|
||||||
|
"entersavebtn": entersavebtn,
|
||||||
|
"settingsbtn": settingsbtn, "quitbtn": quitbtn}
|
||||||
|
|
||||||
# 右列:立绘看台(三张立绘 + 标题底座;界面禁玩法文字墙,故无速览牌)
|
|
||||||
|
## 双列骨架域:左=操作列 56% / 右=舞台(立绘看台)——全屏锚+56px 四边衬距
|
||||||
|
static func _start_columns(overlay: Control) -> HBoxContainer:
|
||||||
|
var cols := HBoxContainer.new()
|
||||||
|
cols.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
|
cols.add_theme_constant_override("separation", 32)
|
||||||
|
var pad := MarginContainer.new()
|
||||||
|
pad.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
|
for side in ["margin_left", "margin_right", "margin_top", "margin_bottom"]:
|
||||||
|
pad.add_theme_constant_override(side, 56)
|
||||||
|
cols.add_child(pad)
|
||||||
|
overlay.add_child(cols)
|
||||||
|
return cols
|
||||||
|
|
||||||
|
|
||||||
|
## 左操作列域:标题+三入口(主菜单三入口化——营地交互重做卡②,用户裁决 1:
|
||||||
|
## 进入存档/设置/退出游戏;组帽双撤——冒险组帽组内零钮退化态不留、「营地与系统」帽指称失义,追认单留痕)
|
||||||
|
static func _start_left_column(cols: HBoxContainer) -> VBoxContainer:
|
||||||
|
var box := VBoxContainer.new()
|
||||||
|
box.name = "start_box"
|
||||||
|
box.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
box.size_flags_stretch_ratio = 1.4
|
||||||
|
box.add_theme_constant_override("separation", 10)
|
||||||
|
(cols.get_child(0) as MarginContainer).add_child(box)
|
||||||
|
box.add_child(UiKit.label("Dungeon Sweeper",UiKit.FS_H1, true, UiKit.INK_ON_DEEP))
|
||||||
|
box.add_child(HSeparator.new())
|
||||||
|
return box
|
||||||
|
|
||||||
|
|
||||||
|
## 右列域:立绘看台(三张立绘 + 标题底座;界面禁玩法文字墙,故无速览牌)
|
||||||
|
static func _start_right_column(cols: HBoxContainer) -> void:
|
||||||
var right := VBoxContainer.new()
|
var right := VBoxContainer.new()
|
||||||
right.name = "start_right"
|
right.name = "start_right"
|
||||||
right.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
right.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
@@ -153,17 +166,7 @@ static func build_start_overlay(host: Control, db: ConfigDb = null) -> Dictionar
|
|||||||
foe_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
foe_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
foe_row.add_theme_constant_override("separation", 36)
|
foe_row.add_theme_constant_override("separation", 36)
|
||||||
for cfg in [[UiKit.TEX_ENEMY_GOBLIN, 46, 96], [UiKit.TEX_HERO_PORTRAIT, 138, 144], [UiKit.TEX_ENEMY_OGRE_CHIEF, 80, 96]]:
|
for cfg in [[UiKit.TEX_ENEMY_GOBLIN, 46, 96], [UiKit.TEX_HERO_PORTRAIT, 138, 144], [UiKit.TEX_ENEMY_OGRE_CHIEF, 80, 96]]:
|
||||||
var tr := TextureRect.new()
|
foe_row.add_child(_start_portrait(cfg))
|
||||||
var tex := UiKit.load_tex(cfg[0])
|
|
||||||
if tex != null:
|
|
||||||
tr.texture = tex
|
|
||||||
tr.custom_minimum_size = Vector2(cfg[1], cfg[2])
|
|
||||||
tr.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
|
||||||
tr.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
|
||||||
tr.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
|
||||||
if cfg[0] != UiKit.TEX_HERO_PORTRAIT:
|
|
||||||
tr.modulate = Color(0.7, 0.7, 0.7, 0.4) # 敌影剪影退后(§6.1 立绘>背景)
|
|
||||||
foe_row.add_child(tr)
|
|
||||||
stage.add_child(foe_row)
|
stage.add_child(foe_row)
|
||||||
var pedestal := Panel.new()
|
var pedestal := Panel.new()
|
||||||
var ped_sb := UiKit.panel_flat(UiKit.TITLE_PEDESTAL, UiKit.BG_ROOT, 17, 2)
|
var ped_sb := UiKit.panel_flat(UiKit.TITLE_PEDESTAL, UiKit.BG_ROOT, 17, 2)
|
||||||
@@ -173,9 +176,20 @@ static func build_start_overlay(host: Control, db: ConfigDb = null) -> Dictionar
|
|||||||
stage.add_child(pedestal)
|
stage.add_child(pedestal)
|
||||||
right.add_child(stage)
|
right.add_child(stage)
|
||||||
|
|
||||||
return {"overlay": overlay, "box": box,
|
|
||||||
"entersavebtn": entersavebtn,
|
## 单立绘域(循环体提函数——像素过滤居中;敌影剪影退后 §6.1 立绘>背景)
|
||||||
"settingsbtn": settingsbtn, "quitbtn": quitbtn}
|
static func _start_portrait(cfg: Array) -> TextureRect:
|
||||||
|
var tr := TextureRect.new()
|
||||||
|
var tex := UiKit.load_tex(cfg[0])
|
||||||
|
if tex != null:
|
||||||
|
tr.texture = tex
|
||||||
|
tr.custom_minimum_size = Vector2(cfg[1], cfg[2])
|
||||||
|
tr.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
tr.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
tr.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||||
|
if cfg[0] != UiKit.TEX_HERO_PORTRAIT:
|
||||||
|
tr.modulate = Color(0.7, 0.7, 0.7, 0.4)
|
||||||
|
return tr
|
||||||
|
|
||||||
|
|
||||||
# 调试浮层入口角标(UI 最顶层浮层,任何 UI 不遮挡)——main 直接子层、
|
# 调试浮层入口角标(UI 最顶层浮层,任何 UI 不遮挡)——main 直接子层、
|
||||||
|
|||||||
@@ -145,71 +145,122 @@ func _format_row(row: Dictionary, agg_count := -1) -> String:
|
|||||||
var src := _source_label(String(row.get("source_class", "")))
|
var src := _source_label(String(row.get("source_class", "")))
|
||||||
var round_no: int = int(row.get("round_index", 0))
|
var round_no: int = int(row.get("round_index", 0))
|
||||||
var prefix := " [color=#%s]R%d%s[/color] " % [UiKit.HEX_LOG_ROUND, round_no, ("·" + src) if src != "" else ""]
|
var prefix := " [color=#%s]R%d%s[/color] " % [UiKit.HEX_LOG_ROUND, round_no, ("·" + src) if src != "" else ""]
|
||||||
var hl := String(row.get("highlight", ""))
|
|
||||||
var v: int = int(row.get("value", 0))
|
|
||||||
var name_: String = String(row.get("display_name", ""))
|
|
||||||
var target := String(row.get("target", ""))
|
|
||||||
var tail := " → %s" % target if target != "" else ""
|
|
||||||
var suffix := "(%s)" % src if src != "" else ""
|
var suffix := "(%s)" % src if src != "" else ""
|
||||||
match String(row.get("type", "")):
|
var kind := String(row.get("type", ""))
|
||||||
|
var body := ""
|
||||||
|
match kind:
|
||||||
"effect":
|
"effect":
|
||||||
# GP 型效果行:「GP 袋 +3」兑付反馈——value = 本行 ±power,
|
body = _fmt_effect(row, prefix, suffix)
|
||||||
# escrow = 战斗内缓冲现值(入钱包在战斗末一次上抛——呈现语义与增益池分账)
|
|
||||||
if String(row.get("effect_id", "")) in ["gp_gain", "gp_loss"]:
|
|
||||||
var gp_col := UiKit.HEX_LOG_GAIN if v > 0 else UiKit.HEX_LOG_LOSS
|
|
||||||
var gp_body := "%s %+d(战斗暂存 %+d)%s" % [name_, v, int(row.get("escrow", 0)), suffix]
|
|
||||||
return prefix + (_gold_frame(gp_body) if hl != "" else "[color=%s]%s[/color]" % [gp_col, gp_body])
|
|
||||||
# 效果行 value = 单次贡献值,pool_value = 池合成值——禁相加呈现(战斗结算 呈现细则)
|
|
||||||
var pool: int = int(row.get("pool_value", 0))
|
|
||||||
var col := UiKit.HEX_LOG_HEAL if v > 0 else UiKit.HEX_LOG_LOSS
|
|
||||||
var body := "%s 单次%+d(池 %+d)%s" % [name_, v, pool, suffix]
|
|
||||||
return prefix + (_gold_frame(body) if hl != "" else "[color=%s]%s[/color]" % [col, body])
|
|
||||||
"damage":
|
"damage":
|
||||||
# 伤害行无行上拆行文案——行上归因读数只剩掷点档位随行
|
body = _fmt_damage(row, prefix, suffix)
|
||||||
# 护甲等级掷点留档(掷点读数与档位随行可读;吃掷点分量恒带,棋盘来源行不带)
|
"heal", "cast", "decay":
|
||||||
var roll_txt := ""
|
body = _fmt_simple(kind, row, prefix, suffix)
|
||||||
if row.get("roll", null) != null:
|
|
||||||
roll_txt = "〔掷 %d vs 护甲 %d" % [int(row.roll), int(row.ac)]
|
|
||||||
if bool(row.get("crit", false)):
|
|
||||||
roll_txt += " · 暴击×%d" % int(_db.combat.settlement.damage_roll.crit_multiplier)
|
|
||||||
elif int(row.tier) < 100:
|
|
||||||
roll_txt += " · ×%d%%" % int(row.tier)
|
|
||||||
roll_txt += "〕"
|
|
||||||
var kill := " ⚔击杀!" if row.get("killed", false) else ""
|
|
||||||
# 伤害数字不明显——伤害值放大加色独立于行文(朱红大一号——数字即信息主角,非同字号色温微差)
|
|
||||||
var body := "%s [color=#%s][size=17]-%d[/size][/color]%s%s%s%s" % [name_, UiKit.HEX_LOG_DMG_NUM, v, roll_txt, tail, kill, suffix]
|
|
||||||
var body_col := UiKit.HEX_LOG_DMG_KILL if row.get("killed", false) else (UiKit.HEX_LOG_ROUND if v == 0 else UiKit.HEX_LOG_DMG_BODY)
|
|
||||||
if bool(row.get("crit", false)):
|
|
||||||
return prefix + _gold_frame(body) # nat 最大面暴击 = 金框高亮行
|
|
||||||
return prefix + "[color=%s]%s[/color]" % [body_col, body]
|
|
||||||
"heal":
|
|
||||||
return prefix + "[color=#%s]%s +%d%s%s[/color]" % [UiKit.HEX_LOG_HEAL, name_, v, tail, suffix]
|
|
||||||
"reward_ineffective":
|
"reward_ineffective":
|
||||||
# 未生效类行:⚠ icon + 划线形状冗余(非色相独载)+ 聚合计数
|
body = _fmt_ineffective(row, prefix, suffix, agg_count)
|
||||||
var n := (" ×%d" % agg_count) if agg_count > 1 else ""
|
|
||||||
return prefix + "[s][color=#%s]⚠ %s%s[/color][/s]%s" % [UiKit.HEX_LOG_VOIDED, name_, n, suffix]
|
|
||||||
"seal_miss":
|
"seal_miss":
|
||||||
var miss_note := ""
|
body = _fmt_seal_miss(row, prefix)
|
||||||
if hl == "perfect_broken":
|
"verdict":
|
||||||
miss_note = "(本图完美封印已破——清图奖励不再加倍)"
|
body = _fmt_verdict(row)
|
||||||
elif hl == "":
|
_:
|
||||||
miss_note = "(首次封印落空已豁免——不计入完美封印判定)"
|
body = _fmt_default(row, prefix, suffix)
|
||||||
var body := "✗ %s%s" % [name_, miss_note]
|
return body
|
||||||
return prefix + (_gold_frame(body) if hl == "perfect_broken" else "[color=#%s]%s[/color]" % [UiKit.HEX_LOG_ROUND, body])
|
|
||||||
|
|
||||||
|
## 简单行域(heal/cast/decay 三型——单行单墨直排)
|
||||||
|
func _fmt_simple(kind: String, row: Dictionary, prefix: String, suffix: String) -> String:
|
||||||
|
var name_: String = String(row.get("display_name", ""))
|
||||||
|
match kind:
|
||||||
|
"heal":
|
||||||
|
return prefix + "[color=#%s]%s +%d%s%s[/color]" % [UiKit.HEX_LOG_HEAL, name_, int(row.get("value", 0)), _tail_of(row), suffix]
|
||||||
"cast":
|
"cast":
|
||||||
# 施放行:增益技 0 伤害施放,具名技能
|
# 施放行:增益技 0 伤害施放,具名技能
|
||||||
return prefix + "[color=#%s]✦ %s%s[/color]" % [UiKit.HEX_LOG_CAST, name_, suffix]
|
return prefix + "[color=#%s]✦ %s%s[/color]" % [UiKit.HEX_LOG_CAST, name_, suffix]
|
||||||
"decay":
|
"decay":
|
||||||
return prefix + "[color=#%s]状态衰减 ×%d[/color]" % [UiKit.HEX_LOG_DECAY, v]
|
return prefix + "[color=#%s]状态衰减 ×%d[/color]" % [UiKit.HEX_LOG_DECAY, int(row.get("value", 0))]
|
||||||
"verdict":
|
return ""
|
||||||
if int(row.value) == 1:
|
|
||||||
return "[color=#%s][b]◆ %s[/b][/color]" % [UiKit.HEX_LOG_WIN, name_]
|
|
||||||
return "[color=#%s][b]◆ %s[/b][/color]" % [UiKit.HEX_LOG_GAIN, name_]
|
## 默认行域(未知型/高亮星标——未知型=名行直排)
|
||||||
"highlight":
|
func _fmt_default(row: Dictionary, prefix: String, suffix: String) -> String:
|
||||||
return prefix + _gold_frame("★ %s" % name_)
|
var name_: String = String(row.get("display_name", ""))
|
||||||
|
if String(row.get("type", "")) == "highlight":
|
||||||
|
return prefix + _gold_frame("★ %s" % name_)
|
||||||
return prefix + name_ + suffix
|
return prefix + name_ + suffix
|
||||||
|
|
||||||
|
|
||||||
|
## 尾注域:目标格指向(行文附加)
|
||||||
|
func _tail_of(row: Dictionary) -> String:
|
||||||
|
var target := String(row.get("target", ""))
|
||||||
|
return " → %s" % target if target != "" else ""
|
||||||
|
|
||||||
|
|
||||||
|
## GP 型效果行域:「GP 袋 +3」兑付反馈——value = 本行 ±power,
|
||||||
|
## escrow = 战斗内缓冲现值(入钱包在战斗末一次上抛——呈现语义与增益池分账)
|
||||||
|
func _fmt_effect(row: Dictionary, prefix: String, suffix: String) -> String:
|
||||||
|
var v: int = int(row.get("value", 0))
|
||||||
|
var hl := String(row.get("highlight", ""))
|
||||||
|
var name_: String = String(row.get("display_name", ""))
|
||||||
|
if String(row.get("effect_id", "")) in ["gp_gain", "gp_loss"]:
|
||||||
|
var gp_col := UiKit.HEX_LOG_GAIN if v > 0 else UiKit.HEX_LOG_LOSS
|
||||||
|
var gp_body := "%s %+d(战斗暂存 %+d)%s" % [name_, v, int(row.get("escrow", 0)), suffix]
|
||||||
|
return prefix + (_gold_frame(gp_body) if hl != "" else "[color=%s]%s[/color]" % [gp_col, gp_body])
|
||||||
|
# 效果行 value = 单次贡献值,pool_value = 池合成值——禁相加呈现(战斗结算 呈现细则)
|
||||||
|
var pool: int = int(row.get("pool_value", 0))
|
||||||
|
var col := UiKit.HEX_LOG_HEAL if v > 0 else UiKit.HEX_LOG_LOSS
|
||||||
|
var body := "%s 单次%+d(池 %+d)%s" % [name_, v, pool, suffix]
|
||||||
|
return prefix + (_gold_frame(body) if hl != "" else "[color=%s]%s[/color]" % [col, body])
|
||||||
|
|
||||||
|
|
||||||
|
## 伤害行域:行上归因读数只剩掷点档位随行(护甲等级掷点留档——掷点读数与档位随行可读;
|
||||||
|
## 吃掷点分量恒带,棋盘来源行不带)。伤害数字不明显——伤害值放大加色独立于行文(朱红大一号)
|
||||||
|
func _fmt_damage(row: Dictionary, prefix: String, suffix: String) -> String:
|
||||||
|
var v: int = int(row.get("value", 0))
|
||||||
|
var name_: String = String(row.get("display_name", ""))
|
||||||
|
var tail := _tail_of(row)
|
||||||
|
var roll_txt := ""
|
||||||
|
if row.get("roll", null) != null:
|
||||||
|
roll_txt = "〔掷 %d vs 护甲 %d" % [int(row.roll), int(row.ac)]
|
||||||
|
if bool(row.get("crit", false)):
|
||||||
|
roll_txt += " · 暴击×%d" % int(_db.combat.settlement.damage_roll.crit_multiplier)
|
||||||
|
elif int(row.tier) < 100:
|
||||||
|
roll_txt += " · ×%d%%" % int(row.tier)
|
||||||
|
roll_txt += "〕"
|
||||||
|
var kill := " ⚔击杀!" if row.get("killed", false) else ""
|
||||||
|
var body := "%s [color=#%s][size=17]-%d[/size][/color]%s%s%s%s" % [name_, UiKit.HEX_LOG_DMG_NUM, v, roll_txt, tail, kill, suffix]
|
||||||
|
if bool(row.get("crit", false)):
|
||||||
|
return prefix + _gold_frame(body) # nat 最大面暴击 = 金框高亮行
|
||||||
|
var body_col := UiKit.HEX_LOG_DMG_KILL if row.get("killed", false) else (UiKit.HEX_LOG_ROUND if v == 0 else UiKit.HEX_LOG_DMG_BODY)
|
||||||
|
return prefix + "[color=%s]%s[/color]" % [body_col, body]
|
||||||
|
|
||||||
|
|
||||||
|
## 未生效行域:⚠ icon + 划线形状冗余(非色相独载)+ 聚合计数
|
||||||
|
func _fmt_ineffective(row: Dictionary, prefix: String, suffix: String, agg_count: int) -> String:
|
||||||
|
var name_: String = String(row.get("display_name", ""))
|
||||||
|
var n := (" ×%d" % agg_count) if agg_count > 1 else ""
|
||||||
|
return prefix + "[s][color=#%s]⚠ %s%s[/color][/s]%s" % [UiKit.HEX_LOG_VOIDED, name_, n, suffix]
|
||||||
|
|
||||||
|
|
||||||
|
## 封印落空行域:完美破/首失豁免两注记分档(金框=破完美/普通墨=豁免)
|
||||||
|
func _fmt_seal_miss(row: Dictionary, prefix: String) -> String:
|
||||||
|
var hl := String(row.get("highlight", ""))
|
||||||
|
var name_: String = String(row.get("display_name", ""))
|
||||||
|
var miss_note := ""
|
||||||
|
if hl == "perfect_broken":
|
||||||
|
miss_note = "(本图完美封印已破——清图奖励不再加倍)"
|
||||||
|
elif hl == "":
|
||||||
|
miss_note = "(首次封印落空已豁免——不计入完美封印判定)"
|
||||||
|
var body := "✗ %s%s" % [name_, miss_note]
|
||||||
|
return prefix + (_gold_frame(body) if hl == "perfect_broken" else "[color=#%s]%s[/color]" % [UiKit.HEX_LOG_ROUND, body])
|
||||||
|
|
||||||
|
|
||||||
|
## 裁定行域:胜金/负绿双墨(粗体菱形头)
|
||||||
|
func _fmt_verdict(row: Dictionary) -> String:
|
||||||
|
var name_: String = String(row.get("display_name", ""))
|
||||||
|
if int(row.value) == 1:
|
||||||
|
return "[color=#%s][b]◆ %s[/b][/color]" % [UiKit.HEX_LOG_WIN, name_]
|
||||||
|
return "[color=#%s][b]◆ %s[/b][/color]" % [UiKit.HEX_LOG_GAIN, name_]
|
||||||
|
|
||||||
|
|
||||||
func _strip_bb(bb: String) -> String:
|
func _strip_bb(bb: String) -> String:
|
||||||
var out := ""
|
var out := ""
|
||||||
var in_tag := false
|
var in_tag := false
|
||||||
|
|||||||
@@ -26,18 +26,28 @@ var world: Node2D # StageWorld(preload 脚本实例——Node2D 世
|
|||||||
|
|
||||||
func _init(db_ref) -> void:
|
func _init(db_ref) -> void:
|
||||||
custom_minimum_size = Vector2(0, 252)
|
custom_minimum_size = Vector2(0, 252)
|
||||||
# 面板底(圣经 v3.5 §6.1 舞台正面目标:B 区=地窟看台,世界底层暗背景
|
_build_backdrop()
|
||||||
# =方向稿 render_battle_screen 取值(值单点收 UiKit.STAGE_BG);描边=PANEL_BORDER 同方向稿)
|
_build_world_stage()
|
||||||
|
_build_text_half(db_ref)
|
||||||
|
_build_companion_layer(db_ref)
|
||||||
|
|
||||||
|
|
||||||
|
## 背景域(圣经 v3.5 §6.1 舞台正面目标:B 区=地窟看台,世界底层暗背景
|
||||||
|
## =方向稿 render_battle_screen 取值(值单点收 UiKit.STAGE_BG);描边=PANEL_BORDER 同方向稿)
|
||||||
|
func _build_backdrop() -> void:
|
||||||
var bg := Panel.new()
|
var bg := Panel.new()
|
||||||
var sb := UiKit.panel_flat(UiKit.STAGE_BG, UiKit.PANEL_BORDER, 0, 1)
|
var sb := UiKit.panel_flat(UiKit.STAGE_BG, UiKit.PANEL_BORDER, 0, 1)
|
||||||
bg.add_theme_stylebox_override("panel", sb)
|
bg.add_theme_stylebox_override("panel", sb)
|
||||||
bg.set_anchors_preset(Control.PRESET_FULL_RECT)
|
bg.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
bg.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
bg.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
add_child(bg)
|
add_child(bg)
|
||||||
|
_build_beams_layer()
|
||||||
|
|
||||||
# 顶光柱氛围层(§6.1 光源氛围——方向稿四柱:x 基准 110/900/1055/1210@1280,暖光(值单点收
|
|
||||||
# UiKit.BEAM_LIGHT——T4 裸色收口)自顶向下 60 段渐宽窄渐隐〔顶 α26→0〕;绘制在暗底之上/
|
## 顶光柱氛围层域(§6.1 光源氛围——方向稿四柱:x 基准 110/900/1055/1210@1280,暖光(值单点收
|
||||||
# 世界站桩之下——层序=bg < 光柱 < 世界)
|
## UiKit.BEAM_LIGHT——T4 裸色收口)自顶向下 60 段渐宽窄渐隐〔顶 α26→0〕;绘制在暗底之上/
|
||||||
|
## 世界站桩之下——层序=bg < 光柱 < 世界)
|
||||||
|
func _build_beams_layer() -> void:
|
||||||
var beams := Control.new()
|
var beams := Control.new()
|
||||||
beams.set_anchors_preset(Control.PRESET_FULL_RECT)
|
beams.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
beams.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
beams.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
@@ -45,7 +55,9 @@ func _init(db_ref) -> void:
|
|||||||
beams.resized.connect(beams.queue_redraw)
|
beams.resized.connect(beams.queue_redraw)
|
||||||
add_child(beams)
|
add_child(beams)
|
||||||
|
|
||||||
# ── Node2D 舞台半区(战斗舞台迁移批 Phase B 同构;stretch 1:1 无缩放系数——C2/C5)──
|
|
||||||
|
## Node2D 舞台半区域(战斗舞台迁移批 Phase B 同构;stretch 1:1 无缩放系数——C2/C5)
|
||||||
|
func _build_world_stage() -> void:
|
||||||
_svp_container = SubViewportContainer.new()
|
_svp_container = SubViewportContainer.new()
|
||||||
_svp_container.stretch = true # 容器尺寸 = 视口逻辑分辨率,恒 1:1
|
_svp_container.stretch = true # 容器尺寸 = 视口逻辑分辨率,恒 1:1
|
||||||
_svp_container.mouse_filter = Control.MOUSE_FILTER_IGNORE # 世界零输入(tooltip 归壳层伴随件)
|
_svp_container.mouse_filter = Control.MOUSE_FILTER_IGNORE # 世界零输入(tooltip 归壳层伴随件)
|
||||||
@@ -61,7 +73,9 @@ func _init(db_ref) -> void:
|
|||||||
world = _STAGE_WORLD.new()
|
world = _STAGE_WORLD.new()
|
||||||
_viewport.add_child(world)
|
_viewport.add_child(world)
|
||||||
|
|
||||||
# ── Control 文本半区(round_label / stage_center / log_view 原样保留——C1 永久 Control)──
|
|
||||||
|
## Control 文本半区域(round_label / stage_center / log_view 原样保留——C1 永久 Control)
|
||||||
|
func _build_text_half(db_ref) -> void:
|
||||||
var vb := VBoxContainer.new()
|
var vb := VBoxContainer.new()
|
||||||
vb.add_theme_constant_override("separation", 4)
|
vb.add_theme_constant_override("separation", 4)
|
||||||
vb.set_anchors_preset(Control.PRESET_FULL_RECT)
|
vb.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
@@ -70,8 +84,14 @@ func _init(db_ref) -> void:
|
|||||||
vb.offset_right = -_CONTENT_MARGINS.size.x
|
vb.offset_right = -_CONTENT_MARGINS.size.x
|
||||||
vb.offset_bottom = -_CONTENT_MARGINS.size.y
|
vb.offset_bottom = -_CONTENT_MARGINS.size.y
|
||||||
add_child(vb)
|
add_child(vb)
|
||||||
|
_build_narr_row(vb)
|
||||||
|
_build_center_row(vb)
|
||||||
|
log_view = BattleLogView.new(db_ref)
|
||||||
|
vb.add_child(log_view)
|
||||||
|
|
||||||
# M8(UI 落码批):轮次牌 plate9 素牌化(demo ⑦——墨字上亮牌 12.3:1,暗底暖字退役)
|
|
||||||
|
## 轮次牌域(M8 UI 落码批:plate9 素牌化——demo ⑦,墨字上亮牌 12.3:1,暗底暖字退役)
|
||||||
|
func _build_narr_row(vb: VBoxContainer) -> void:
|
||||||
var narr_plate := PanelContainer.new()
|
var narr_plate := PanelContainer.new()
|
||||||
narr_plate.add_theme_stylebox_override("panel", UiKit.panel_skinned(Vector4(12, 4, 12, 4)))
|
narr_plate.add_theme_stylebox_override("panel", UiKit.panel_skinned(Vector4(12, 4, 12, 4)))
|
||||||
narr_plate.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
narr_plate.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||||
@@ -80,12 +100,14 @@ func _init(db_ref) -> void:
|
|||||||
round_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
round_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
narr_plate.add_child(round_label)
|
narr_plate.add_child(round_label)
|
||||||
|
|
||||||
|
|
||||||
|
## 中段行域:提示语居中+敌站桩壳层伴随件容器(明细带展开/收起改行高——世界布局随动)
|
||||||
|
func _build_center_row(vb: VBoxContainer) -> void:
|
||||||
_row = HBoxContainer.new()
|
_row = HBoxContainer.new()
|
||||||
_row.add_theme_constant_override("separation", 10)
|
_row.add_theme_constant_override("separation", 10)
|
||||||
_row.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
_row.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
vb.add_child(_row)
|
vb.add_child(_row)
|
||||||
_row.resized.connect(_on_row_resized) # 明细带展开/收起改行高——世界布局随动
|
_row.resized.connect(_on_row_resized)
|
||||||
|
|
||||||
var center := CenterContainer.new()
|
var center := CenterContainer.new()
|
||||||
center.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
center.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
center.mouse_filter = Control.MOUSE_FILTER_IGNORE # 行内只剩文本——鼠标全放行给壳层伴随件
|
center.mouse_filter = Control.MOUSE_FILTER_IGNORE # 行内只剩文本——鼠标全放行给壳层伴随件
|
||||||
@@ -96,21 +118,17 @@ func _init(db_ref) -> void:
|
|||||||
stage_center.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
stage_center.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
center_col.add_child(stage_center)
|
center_col.add_child(stage_center)
|
||||||
_row.add_child(center)
|
_row.add_child(center)
|
||||||
|
|
||||||
enemy_box = Control.new() # 站桩壳层伴随件容器(T3 语义改写)
|
enemy_box = Control.new() # 站桩壳层伴随件容器(T3 语义改写)
|
||||||
enemy_box.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
enemy_box.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
_row.add_child(enemy_box)
|
_row.add_child(enemy_box)
|
||||||
|
|
||||||
log_view = BattleLogView.new(db_ref)
|
|
||||||
vb.add_child(log_view)
|
|
||||||
|
|
||||||
# ── 壳层伴随件层(最顶——世界站桩之上的 Control 触达面)──
|
## 壳层伴随件层域(最顶——世界站桩之上的 Control 触达面)+主角站桩注册(世界)+ 状态行伴随件(壳层)
|
||||||
|
func _build_companion_layer(db_ref) -> void:
|
||||||
_companion_layer = Control.new()
|
_companion_layer = Control.new()
|
||||||
_companion_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
|
_companion_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
_companion_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
_companion_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
add_child(_companion_layer)
|
add_child(_companion_layer)
|
||||||
|
|
||||||
# 主角站桩本体(世界)+ 状态行伴随件(壳层)
|
|
||||||
hero_standee = _STANDEE_BODY.new("hero")
|
hero_standee = _STANDEE_BODY.new("hero")
|
||||||
var hero_tex := UiKit.load_tex(UiKit.TEX_HERO_PORTRAIT)
|
var hero_tex := UiKit.load_tex(UiKit.TEX_HERO_PORTRAIT)
|
||||||
hero_standee.set_portrait_texture(hero_tex, true) # B 区立绘 48px 档·normal 态朝右(素材缺位 null 回退字形「人」)
|
hero_standee.set_portrait_texture(hero_tex, true) # B 区立绘 48px 档·normal 态朝右(素材缺位 null 回退字形「人」)
|
||||||
@@ -230,26 +248,24 @@ func enemy_body_at(i: int) -> Node2D:
|
|||||||
# 素材装载属组合点职责(主角侧同款先例 _init TEX_HERO_PORTRAIT),StandeeBody 保持纯收 tex 面。
|
# 素材装载属组合点职责(主角侧同款先例 _init TEX_HERO_PORTRAIT),StandeeBody 保持纯收 tex 面。
|
||||||
# 素材缺位 load_tex→null→set_portrait_texture 字形回退(表现与素材批前逐位一致);未录键返回 null
|
# 素材缺位 load_tex→null→set_portrait_texture 字形回退(表现与素材批前逐位一致);未录键返回 null
|
||||||
# 走默认字形「敌」(与 StandeeBody._portrait_glyph 默认档同口径)——数据表扩键先补此处映射。
|
# 走默认字形「敌」(与 StandeeBody._portrait_glyph 默认档同口径)——数据表扩键先补此处映射。
|
||||||
|
## 敌像 id→纹理键映射表(查表+回退——映射语义零变化;未知 id=null 回退字形)
|
||||||
func _enemy_portrait_tex(enemy_id: String) -> Texture2D:
|
func _enemy_portrait_tex(enemy_id: String) -> Texture2D:
|
||||||
match enemy_id:
|
var table := {"goblin": UiKit.TEX_ENEMY_GOBLIN, "bugbear": UiKit.TEX_ENEMY_BUGBEAR,
|
||||||
"goblin":
|
"ogre_chief": UiKit.TEX_ENEMY_OGRE_CHIEF, "giant_spider": UiKit.TEX_ENEMY_GIANT_SPIDER,
|
||||||
return UiKit.load_tex(UiKit.TEX_ENEMY_GOBLIN)
|
"drider": UiKit.TEX_ENEMY_DRIDER, "duergar": UiKit.TEX_ENEMY_DUERGAR,
|
||||||
"bugbear":
|
"hook_horror": UiKit.TEX_ENEMY_HOOK_HORROR, "duergar_king": UiKit.TEX_ENEMY_DUERGAR_KING}
|
||||||
return UiKit.load_tex(UiKit.TEX_ENEMY_BUGBEAR)
|
return UiKit.load_tex(String(table.get(enemy_id, ""))) if table.has(enemy_id) else null
|
||||||
"ogre_chief":
|
|
||||||
return UiKit.load_tex(UiKit.TEX_ENEMY_OGRE_CHIEF)
|
|
||||||
"giant_spider":
|
## 单敌站桩构建域(循环体提函数——世界本体+壳层伴随件+敌种立绘接线〔仅重建拍装载一次;
|
||||||
return UiKit.load_tex(UiKit.TEX_ENEMY_GIANT_SPIDER)
|
## flip=false——八敌像素源核证朝左/正面,呈现即朝主角无误;反向朝向源换代时翻转义务归素材批〕)
|
||||||
"drider":
|
func _spawn_enemy_standee(d: Dictionary) -> Node2D:
|
||||||
return UiKit.load_tex(UiKit.TEX_ENEMY_DRIDER)
|
var body: Node2D = _STANDEE_BODY.new("enemy")
|
||||||
"duergar":
|
world.add_child(body)
|
||||||
return UiKit.load_tex(UiKit.TEX_ENEMY_DUERGAR)
|
body.slot_row = _make_slot_companion(enemy_box)
|
||||||
"hook_horror":
|
body.set_data(d)
|
||||||
return UiKit.load_tex(UiKit.TEX_ENEMY_HOOK_HORROR)
|
body.set_portrait_texture(_enemy_portrait_tex(String(d.get("enemy_id", ""))), false)
|
||||||
"duergar_king":
|
return body
|
||||||
return UiKit.load_tex(UiKit.TEX_ENEMY_DUERGAR_KING)
|
|
||||||
_:
|
|
||||||
return null
|
|
||||||
|
|
||||||
|
|
||||||
# 敌方站桩投影更新:数量不变 = 就地更新(死亡灰化/受击闪烁等站桩上动画不被逐行刷新重置——禁瞬消纪律);
|
# 敌方站桩投影更新:数量不变 = 就地更新(死亡灰化/受击闪烁等站桩上动画不被逐行刷新重置——禁瞬消纪律);
|
||||||
@@ -263,14 +279,7 @@ func set_enemies(cards_data: Array) -> void:
|
|||||||
c.queue_free()
|
c.queue_free()
|
||||||
_cards.clear()
|
_cards.clear()
|
||||||
for d in cards_data:
|
for d in cards_data:
|
||||||
var body: Node2D = _STANDEE_BODY.new("enemy")
|
_cards.append(_spawn_enemy_standee(d))
|
||||||
world.add_child(body)
|
|
||||||
body.slot_row = _make_slot_companion(enemy_box)
|
|
||||||
body.set_data(d)
|
|
||||||
# 敌种立绘接线(仅重建拍装载一次;flip=false——八敌像素源核证朝左/正面,
|
|
||||||
# 呈现即朝主角无误;反向朝向源换代时翻转义务归素材批)
|
|
||||||
body.set_portrait_texture(_enemy_portrait_tex(String(d.get("enemy_id", ""))), false)
|
|
||||||
_cards.append(body)
|
|
||||||
_sync_layout.call_deferred()
|
_sync_layout.call_deferred()
|
||||||
return
|
return
|
||||||
for i in cards_data.size():
|
for i in cards_data.size():
|
||||||
|
|||||||
@@ -89,19 +89,24 @@ func play_boss_shadow() -> void:
|
|||||||
|
|
||||||
# 完美封印:金光带加倍扫射 + 横幅占位(§2.2 最高档)
|
# 完美封印:金光带加倍扫射 + 横幅占位(§2.2 最高档)
|
||||||
func play_perfect_sweep() -> void:
|
func play_perfect_sweep() -> void:
|
||||||
for i in 2:
|
for i in 3:
|
||||||
var band := ColorRect.new()
|
_spawn_sweep_band(i, size)
|
||||||
band.color = Color(COL_GOLD, 0.35)
|
|
||||||
band.size = Vector2(size.x, 14.0 + 10.0 * i)
|
|
||||||
band.position = Vector2(-size.x, size.y * 0.3 + 40.0 * i)
|
|
||||||
band.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
||||||
add_child(band)
|
|
||||||
var tw := band.create_tween()
|
|
||||||
tw.tween_property(band, "position:x", size.x + 8.0, UiKit.motion(0.5 + 0.15 * i))
|
|
||||||
tw.tween_callback(band.queue_free)
|
|
||||||
_show_banner("完美封印 ×2")
|
_show_banner("完美封印 ×2")
|
||||||
|
|
||||||
|
|
||||||
|
## 单光带域(循环体提函数——自左掠过渐出)
|
||||||
|
func _spawn_sweep_band(i: int, size: Vector2) -> void:
|
||||||
|
var band := ColorRect.new()
|
||||||
|
band.color = Color(COL_GOLD, 0.35)
|
||||||
|
band.size = Vector2(size.x, 14.0 + 10.0 * i)
|
||||||
|
band.position = Vector2(-size.x, size.y * 0.3 + 40.0 * i)
|
||||||
|
band.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
add_child(band)
|
||||||
|
var tw := band.create_tween()
|
||||||
|
tw.tween_property(band, "position:x", size.x + 8.0, UiKit.motion(0.5 + 0.15 * i))
|
||||||
|
tw.tween_callback(band.queue_free)
|
||||||
|
|
||||||
|
|
||||||
# 封印命中:封印化暴击弹道加重占位(自棋盘上缘飞向 B 区敌人卡方向——越界即收)
|
# 封印命中:封印化暴击弹道加重占位(自棋盘上缘飞向 B 区敌人卡方向——越界即收)
|
||||||
func play_seal_hit_projectile(heavy: bool) -> void:
|
func play_seal_hit_projectile(heavy: bool) -> void:
|
||||||
var shot := ColorRect.new()
|
var shot := ColorRect.new()
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ func _init() -> void:
|
|||||||
var vb := VBoxContainer.new()
|
var vb := VBoxContainer.new()
|
||||||
vb.add_theme_constant_override("separation", 4)
|
vb.add_theme_constant_override("separation", 4)
|
||||||
add_child(vb)
|
add_child(vb)
|
||||||
|
_build_views(vb)
|
||||||
|
_build_status_corner()
|
||||||
|
|
||||||
|
|
||||||
|
## 视图三件域:AP 条+棋盘区(含动效与 toast 叠层)
|
||||||
|
func _build_views(vb: VBoxContainer) -> void:
|
||||||
ap_bar = ApBarView.new()
|
ap_bar = ApBarView.new()
|
||||||
vb.add_child(ap_bar)
|
vb.add_child(ap_bar)
|
||||||
var board_area := Control.new()
|
var board_area := Control.new()
|
||||||
@@ -31,6 +37,11 @@ func _init() -> void:
|
|||||||
vb.add_child(board_area)
|
vb.add_child(board_area)
|
||||||
_board_area = board_area
|
_board_area = board_area
|
||||||
board_area.resized.connect(_on_board_area_resized)
|
board_area.resized.connect(_on_board_area_resized)
|
||||||
|
_build_board_children(board_area)
|
||||||
|
|
||||||
|
|
||||||
|
## 棋盘子件域:视图+动效+toast 三叠层挂接
|
||||||
|
func _build_board_children(board_area: Control) -> void:
|
||||||
board_view = BoardView.new()
|
board_view = BoardView.new()
|
||||||
board_view.set_anchors_preset(Control.PRESET_FULL_RECT)
|
board_view.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
board_area.add_child(board_view)
|
board_area.add_child(board_view)
|
||||||
|
|||||||
@@ -30,7 +30,14 @@ func _init() -> void:
|
|||||||
# bcard 三竖卡(D1 232×352)+ 底部确认主钮与免费选择注记。差异白名单=免费选择/✓章/无价签。
|
# bcard 三竖卡(D1 232×352)+ 底部确认主钮与免费选择注记。差异白名单=免费选择/✓章/无价签。
|
||||||
# 状态机不变:pick→result。M7 同构裁决遗产保留。
|
# 状态机不变:pick→result。M7 同构裁决遗产保留。
|
||||||
var page: Dictionary[Variant, Variant] = UiKit.page_shell(self, false)
|
var page: Dictionary[Variant, Variant] = UiKit.page_shell(self, false)
|
||||||
var top: HBoxContainer = page.top_row
|
_build_top_row(page.top_row)
|
||||||
|
var box: VBoxContainer = page.box
|
||||||
|
_build_body(box)
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
## 顶条域:标题+刷新图标钮(44×44 豁免宽度基准+角标叠加)+刷新余量行
|
||||||
|
func _build_top_row(top: HBoxContainer) -> void:
|
||||||
top.add_child(UiKit.label("战利品三选一",UiKit.FS_TITLE, true, UiKit.WARM))
|
top.add_child(UiKit.label("战利品三选一",UiKit.FS_TITLE, true, UiKit.WARM))
|
||||||
var top_sp := Control.new()
|
var top_sp := Control.new()
|
||||||
top_sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
top_sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
@@ -51,7 +58,32 @@ func _init() -> void:
|
|||||||
_refresh_l = UiKit.label("",UiKit.FS_CAPTION, false, UiKit.WARM_SOFT)
|
_refresh_l = UiKit.label("",UiKit.FS_CAPTION, false, UiKit.WARM_SOFT)
|
||||||
_refresh_l.visible = false
|
_refresh_l.visible = false
|
||||||
top.add_child(_refresh_l)
|
top.add_child(_refresh_l)
|
||||||
var box: VBoxContainer = page.box
|
|
||||||
|
|
||||||
|
## 主体域:入账信息行+三竖卡列+底部确认/继续钮与免费选择注记
|
||||||
|
func _build_body(box: VBoxContainer) -> void:
|
||||||
|
_label = UiKit.label("",UiKit.FS_BODY, false, UiKit.WARM_SOFT)
|
||||||
|
_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
box.add_child(_label)
|
||||||
|
_choice_box = HBoxContainer.new()
|
||||||
|
_choice_box.add_theme_constant_override("separation", 26) # demo .cards gap 26(T7 对齐)
|
||||||
|
_choice_box.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
|
_choice_box.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
|
box.add_child(_choice_box)
|
||||||
|
var foot := HBoxContainer.new()
|
||||||
|
foot.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
|
foot.add_theme_constant_override("separation", 16)
|
||||||
|
box.add_child(foot)
|
||||||
|
_confirm_btn = UiKit.primary_button("确认选择")
|
||||||
|
_confirm_btn.pressed.connect(_on_confirm_pressed)
|
||||||
|
_confirm_btn.visible = false
|
||||||
|
foot.add_child(_confirm_btn)
|
||||||
|
_continue_btn = UiKit.button("继续")
|
||||||
|
_continue_btn.pressed.connect(_emit_continue_pressed)
|
||||||
|
_continue_btn.visible = false
|
||||||
|
foot.add_child(_continue_btn)
|
||||||
|
_foot_hint = UiKit.label("免费选择 · 刷新不消耗 AP",UiKit.FS_HINT, false, UiKit.WARM_FAINT)
|
||||||
|
foot.add_child(_foot_hint)
|
||||||
_label = UiKit.label("",UiKit.FS_BODY, false, UiKit.WARM_SOFT)
|
_label = UiKit.label("",UiKit.FS_BODY, false, UiKit.WARM_SOFT)
|
||||||
_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
box.add_child(_label)
|
box.add_child(_label)
|
||||||
@@ -189,19 +221,15 @@ func _emit_continue_pressed() -> void:
|
|||||||
|
|
||||||
|
|
||||||
# M7:id → 手绘图标键(子串映射容错 id 词表演进;缺位=BCard 空图标槽不炸)
|
# M7:id → 手绘图标键(子串映射容错 id 词表演进;缺位=BCard 空图标槽不炸)
|
||||||
|
## 图标映射表(id 子串→图标键——判定序 heal/blast/gp/attack/armor/ap 缺省钱袋逐字)
|
||||||
func _icon_for_id(idl: String) -> String:
|
func _icon_for_id(idl: String) -> String:
|
||||||
if idl.contains("heal"):
|
var rules := [[["heal"], UiKit.TEX_ICON_MEDKIT], [["blast", "magic"], UiKit.TEX_ICON_BLAST],
|
||||||
return UiKit.TEX_ICON_MEDKIT
|
[["gp", "coin"], UiKit.TEX_ICON_COINBAG], [["attack"], UiKit.TEX_ICON_SWORD],
|
||||||
if idl.contains("blast") or idl.contains("magic"):
|
[["armor"], UiKit.TEX_ICON_SHIELD], [["ap", "action"], UiKit.TEX_ICON_POUCH]]
|
||||||
return UiKit.TEX_ICON_BLAST
|
for rule in rules:
|
||||||
if idl.contains("gp") or idl.contains("coin"):
|
for kw in (rule[0] as Array):
|
||||||
return UiKit.TEX_ICON_COINBAG
|
if idl.contains(String(kw)):
|
||||||
if idl.contains("attack"):
|
return String(rule[1])
|
||||||
return UiKit.TEX_ICON_SWORD
|
|
||||||
if idl.contains("armor"):
|
|
||||||
return UiKit.TEX_ICON_SHIELD
|
|
||||||
if idl.contains("ap") or idl.contains("action"):
|
|
||||||
return UiKit.TEX_ICON_POUCH
|
|
||||||
return UiKit.TEX_ICON_COINBAG
|
return UiKit.TEX_ICON_COINBAG
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,17 +32,7 @@ func _init(rap_cost: int = -1) -> void:
|
|||||||
box.add_child(title)
|
box.add_child(title)
|
||||||
box.add_child(HSeparator.new())
|
box.add_child(HSeparator.new())
|
||||||
for e in ENTRIES:
|
for e in ENTRIES:
|
||||||
var row := HBoxContainer.new()
|
box.add_child(_legend_row(e))
|
||||||
row.add_theme_constant_override("separation", 8)
|
|
||||||
var chip := ColorRect.new()
|
|
||||||
chip.custom_minimum_size = Vector2(18, 18)
|
|
||||||
chip.color = Color(e[0])
|
|
||||||
row.add_child(chip)
|
|
||||||
var lab := UiKit.label("%s —— %s" % [e[1], e[2]], 13, false, UiKit.INK_LABEL) # 亮底墨字(§7.2 数据素面)
|
|
||||||
lab.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
||||||
lab.custom_minimum_size = Vector2(440, 0)
|
|
||||||
row.add_child(lab)
|
|
||||||
box.add_child(row)
|
|
||||||
box.add_child(HSeparator.new())
|
box.add_child(HSeparator.new())
|
||||||
# RAP 行(表值驱动,禁字面量:刷新代价读行动经济表)
|
# RAP 行(表值驱动,禁字面量:刷新代价读行动经济表)
|
||||||
if _rap_cost >= 0:
|
if _rap_cost >= 0:
|
||||||
@@ -64,6 +54,24 @@ func _init(rap_cost: int = -1) -> void:
|
|||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 单行域(循环体提函数——色块 chip+词条 18px 网格对齐)
|
||||||
|
func _legend_row(e: Array) -> HBoxContainer:
|
||||||
|
var row := HBoxContainer.new()
|
||||||
|
row.add_theme_constant_override("separation", 8)
|
||||||
|
var chip := ColorRect.new()
|
||||||
|
chip.custom_minimum_size = Vector2(18, 18)
|
||||||
|
chip.color = Color(e[0])
|
||||||
|
row.add_child(chip)
|
||||||
|
var lab := UiKit.label("%s —— %s" % [e[1], e[2]], 13, false, UiKit.INK_LABEL) # 亮底墨字(§7.2 数据素面)
|
||||||
|
lab.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
|
lab.custom_minimum_size = Vector2(440, 0)
|
||||||
|
row.add_child(lab)
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func is_open() -> bool:
|
func is_open() -> bool:
|
||||||
return visible
|
return visible
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,15 @@ func _build() -> void:
|
|||||||
var shell: Dictionary[Variant, Variant] = UiKit.modal_shell(self, UiKit.BG_BRIGHT, Vector2(560, 0), 8,
|
var shell: Dictionary[Variant, Variant] = UiKit.modal_shell(self, UiKit.BG_BRIGHT, Vector2(560, 0), 8,
|
||||||
UiKit.panel_skinned(Vector4(20, 16, 20, 16)))
|
UiKit.panel_skinned(Vector4(20, 16, 20, 16)))
|
||||||
var box: VBoxContainer = shell.box
|
var box: VBoxContainer = shell.box
|
||||||
|
_build_head(box)
|
||||||
|
_build_volume_row(box)
|
||||||
|
_build_fullscreen_row(box)
|
||||||
|
_build_motion_row(box)
|
||||||
|
_build_close_row(box)
|
||||||
|
|
||||||
|
|
||||||
|
## 头部域(设置项零增减——只有主音量;减动效与结算演出动画=同一设置,一行承载)
|
||||||
|
func _build_head(box: VBoxContainer) -> void:
|
||||||
var title := UiKit.label("设置",UiKit.FS_TITLE, true, UiKit.INK_TITLE)
|
var title := UiKit.label("设置",UiKit.FS_TITLE, true, UiKit.INK_TITLE)
|
||||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
box.add_child(title)
|
box.add_child(title)
|
||||||
@@ -46,7 +54,9 @@ func _build() -> void:
|
|||||||
box.add_child(hint)
|
box.add_child(hint)
|
||||||
box.add_child(HSeparator.new())
|
box.add_child(HSeparator.new())
|
||||||
|
|
||||||
# 音量(master bus 实时生效——入口归设置、生效口径归 音频.md)
|
|
||||||
|
## 音量行(master bus 实时生效——入口归设置、生效口径归 音频.md)
|
||||||
|
func _build_volume_row(box: VBoxContainer) -> void:
|
||||||
var vol_row := HBoxContainer.new()
|
var vol_row := HBoxContainer.new()
|
||||||
vol_row.add_theme_constant_override("separation", 14)
|
vol_row.add_theme_constant_override("separation", 14)
|
||||||
box.add_child(vol_row)
|
box.add_child(vol_row)
|
||||||
@@ -66,7 +76,9 @@ func _build() -> void:
|
|||||||
_volume_val.custom_minimum_size = Vector2(60, 0)
|
_volume_val.custom_minimum_size = Vector2(60, 0)
|
||||||
vol_row.add_child(_volume_val)
|
vol_row.add_child(_volume_val)
|
||||||
|
|
||||||
# 全屏(拨杆形——SwitchToggle;状态字随行)
|
|
||||||
|
## 全屏行(拨杆形——SwitchToggle;状态字随行)
|
||||||
|
func _build_fullscreen_row(box: VBoxContainer) -> void:
|
||||||
var fs_row := HBoxContainer.new()
|
var fs_row := HBoxContainer.new()
|
||||||
fs_row.add_theme_constant_override("separation", 14)
|
fs_row.add_theme_constant_override("separation", 14)
|
||||||
box.add_child(fs_row)
|
box.add_child(fs_row)
|
||||||
@@ -79,9 +91,11 @@ func _build() -> void:
|
|||||||
_fs_st = UiKit.label("关",UiKit.FS_HINT, true, UiKit.INK_LABEL)
|
_fs_st = UiKit.label("关",UiKit.FS_HINT, true, UiKit.INK_LABEL)
|
||||||
fs_row.add_child(_fs_st)
|
fs_row.add_child(_fs_st)
|
||||||
|
|
||||||
# 结算演出动画(=减动效实称;拨杆 on=完整,off=快速时长减半。
|
|
||||||
# reduced_motion 单设置同驱 UiKit.motion_scale 与结算演播——demo「减动效」行与
|
## 结算演出动画行(=减动效实称;拨杆 on=完整,off=快速时长减半。
|
||||||
# 本行系同一设置,不另立行(拆两行=一设置双行重复)
|
## reduced_motion 单设置同驱 UiKit.motion_scale 与结算演播——demo「减动效」行与
|
||||||
|
## 本行系同一设置,不另立行(拆两行=一设置双行重复))
|
||||||
|
func _build_motion_row(box: VBoxContainer) -> void:
|
||||||
var motion_row := HBoxContainer.new()
|
var motion_row := HBoxContainer.new()
|
||||||
motion_row.add_theme_constant_override("separation", 14)
|
motion_row.add_theme_constant_override("separation", 14)
|
||||||
box.add_child(motion_row)
|
box.add_child(motion_row)
|
||||||
@@ -95,9 +109,11 @@ func _build() -> void:
|
|||||||
motion_row.add_child(_motion_st)
|
motion_row.add_child(_motion_st)
|
||||||
var why := UiKit.label("快速 = 时长减半(运动敏感 / 演示用)",UiKit.FS_CAPTION, false, UiKit.INK_HINT)
|
var why := UiKit.label("快速 = 时长减半(运动敏感 / 演示用)",UiKit.FS_CAPTION, false, UiKit.INK_HINT)
|
||||||
motion_row.add_child(why) # 内联随行(demo .why 同排)
|
motion_row.add_child(why) # 内联随行(demo .why 同排)
|
||||||
|
|
||||||
box.add_child(HSeparator.new())
|
box.add_child(HSeparator.new())
|
||||||
# 退出游戏归开始菜单——设置面不再承载(退出只在一级菜单出现)
|
|
||||||
|
|
||||||
|
## 返回钮域(退出游戏归开始菜单——设置面不再承载〔退出只在一级菜单出现〕)
|
||||||
|
func _build_close_row(box: VBoxContainer) -> void:
|
||||||
var close_row := HBoxContainer.new()
|
var close_row := HBoxContainer.new()
|
||||||
close_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
close_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
box.add_child(close_row)
|
box.add_child(close_row)
|
||||||
|
|||||||
Reference in new issue
Block a user