227 lines
6.3 KiB
GDScript
227 lines
6.3 KiB
GDScript
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||
# Date: 2026-09-11(2026-09-12 code-review 修复批重构)
|
||
# 测试用角色数值调整板(模拟天赋树属性提升——仅测试,正式侧归元进度)。
|
||
# 纯视图边界(规范 1.3):本类只承载滑杆 UI 与生效值预览;加成应用 / 重置落表 / 批量模拟编排
|
||
# 全部经信号外发由组合根承接(apply_requested / reset_requested / simulate_requested / closed),
|
||
# 模拟进度与报告经 setter 注入——视图零核心写、零 smoke 脚本依赖、不拼报告文案(装配归 presenter)。
|
||
# 探针接缝(ADR-0004"合成输入走真实翻译出口"口径):press_apply_for_probe 等三键 = 按钮真实信号路径。
|
||
class_name TunePanel
|
||
extends Control
|
||
|
||
signal apply_requested(atk_pct: int, hp_pct: int) # 应用并关闭——加成落表归组合根单一应用路径
|
||
signal reset_requested() # 重置为 0——视图自清滑杆,落表归组合根
|
||
signal simulate_requested(count: int) # 批量模拟编排归组合根(表基线复位 + 单路径施加)
|
||
signal closed
|
||
|
||
var _db
|
||
var _base_atk := 0
|
||
var _base_hp := 0
|
||
var _atk: HSlider
|
||
var _hp: HSlider
|
||
var _atk_val: Label
|
||
var _hp_val: Label
|
||
var _eff: Label
|
||
var _sim_count: SpinBox
|
||
var _sim_btn: Button
|
||
var _sim_out: RichTextLabel
|
||
|
||
|
||
func _init(db_ref, base_atk: int, base_hp: int) -> void:
|
||
_db = db_ref
|
||
_base_atk = base_atk
|
||
_base_hp = base_hp
|
||
_build()
|
||
_sync_labels()
|
||
|
||
|
||
# ---- 对外语义面(组合根/探针)----
|
||
|
||
func atk_pct() -> int:
|
||
return int(_atk.value)
|
||
|
||
|
||
func hp_pct() -> int:
|
||
return int(_hp.value)
|
||
|
||
|
||
func set_sliders(atk: int, hp: int) -> void:
|
||
_atk.value = atk
|
||
_hp.value = hp
|
||
|
||
|
||
func reset_sliders() -> void:
|
||
_atk.value = 0
|
||
_hp.value = 0
|
||
_sync_labels()
|
||
|
||
|
||
func effect_text() -> String:
|
||
return _eff.text
|
||
|
||
|
||
func set_sim_count(n: int) -> void:
|
||
_sim_count.value = n
|
||
|
||
|
||
func is_running() -> bool:
|
||
return _sim_btn.disabled
|
||
|
||
|
||
func set_sim_running(running: bool) -> void:
|
||
_sim_btn.disabled = running
|
||
_sim_btn.text = "模拟中…" if running else "运行模拟"
|
||
|
||
|
||
func set_sim_progress(text: String) -> void:
|
||
_sim_out.text = text
|
||
|
||
|
||
func set_sim_report(text: String) -> void:
|
||
_sim_out.text = text
|
||
|
||
|
||
func output_text() -> String:
|
||
return _sim_out.get_parsed_text()
|
||
|
||
|
||
# ---- 探针接缝(真实翻译出口——按钮 pressed 信号路径,非直调组合根)----
|
||
|
||
func press_apply_for_probe() -> void:
|
||
_apply_btn_pressed()
|
||
|
||
|
||
func press_reset_for_probe() -> void:
|
||
_reset_btn_pressed()
|
||
|
||
|
||
func press_simulate_for_probe() -> void:
|
||
_sim_btn.pressed.emit()
|
||
|
||
|
||
# ---- 内部(信号 → 外发)----
|
||
|
||
func _apply_btn_pressed() -> void:
|
||
apply_requested.emit(atk_pct(), hp_pct())
|
||
|
||
|
||
func _reset_btn_pressed() -> void:
|
||
reset_sliders()
|
||
reset_requested.emit()
|
||
|
||
|
||
func effective_atk() -> int:
|
||
return _scaled(_base_atk, atk_pct())
|
||
|
||
|
||
func effective_max_hp() -> int:
|
||
return _scaled(_base_hp, hp_pct())
|
||
|
||
|
||
# ---- 内部构建 ----
|
||
|
||
func _build() -> void:
|
||
var dim := ColorRect.new()
|
||
dim.color = UiKit.BG_OVERLAY
|
||
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 box := VBoxContainer.new()
|
||
box.custom_minimum_size = Vector2(640, 0)
|
||
box.add_theme_constant_override("separation", 8)
|
||
center.add_child(box)
|
||
|
||
var title := UiKit.label("测试用 · 角色数值调整板", 26, true)
|
||
title.add_theme_color_override("font_color", UiKit.WARM)
|
||
box.add_child(title)
|
||
var desc := UiKit.label(
|
||
"模拟玩家在循环中解锁天赋获得的属性提升(仅测试工具,不落盘)。\n百分比叠加基础值:攻击 %d / 生命 %d。影响所有模式(手动与模拟)。" % [_base_atk, _base_hp],
|
||
13, false)
|
||
desc.add_theme_color_override("font_color", UiKit.WARM_SOFT)
|
||
box.add_child(desc)
|
||
box.add_child(HSeparator.new())
|
||
|
||
var atk_row := _slider_row(box, "攻击加成")
|
||
_atk = atk_row.slider
|
||
_atk_val = atk_row.value_label
|
||
var hp_row := _slider_row(box, "生命加成")
|
||
_hp = hp_row.slider
|
||
_hp_val = hp_row.value_label
|
||
_eff = UiKit.label("", 14, false)
|
||
box.add_child(_eff)
|
||
|
||
var btn_row := HBoxContainer.new()
|
||
box.add_child(btn_row)
|
||
var apply_btn := UiKit.button("应用并关闭")
|
||
apply_btn.pressed.connect(_apply_btn_pressed)
|
||
btn_row.add_child(apply_btn)
|
||
var reset_btn := UiKit.button("重置为 0")
|
||
reset_btn.pressed.connect(_reset_btn_pressed)
|
||
btn_row.add_child(reset_btn)
|
||
# 减动效开关已转正迁出(迭代 8 卡④——设置面唯一入口,本面板退役该开关;motion_scale 引擎态由设置面承载)
|
||
box.add_child(HSeparator.new())
|
||
|
||
var sim_row := HBoxContainer.new()
|
||
box.add_child(sim_row)
|
||
sim_row.add_child(UiKit.label("批量模拟第一关", 15, false))
|
||
_sim_count = SpinBox.new()
|
||
_sim_count.min_value = 10
|
||
_sim_count.max_value = 200
|
||
_sim_count.step = 10
|
||
_sim_count.value = 30
|
||
_sim_count.custom_minimum_size = Vector2(90, 0)
|
||
sim_row.add_child(_sim_count)
|
||
sim_row.add_child(UiKit.label("次(理性玩家策略,含面板当前加成)", 13, false))
|
||
_sim_btn = UiKit.button("运行模拟")
|
||
_sim_btn.pressed.connect(_emit_simulate_requested)
|
||
sim_row.add_child(_sim_btn)
|
||
_sim_out = RichTextLabel.new()
|
||
_sim_out.bbcode_enabled = true
|
||
_sim_out.custom_minimum_size = Vector2(0, 300)
|
||
box.add_child(_sim_out)
|
||
|
||
var close_btn := UiKit.button("关闭")
|
||
close_btn.pressed.connect(_emit_closed)
|
||
box.add_child(close_btn)
|
||
|
||
|
||
func _slider_row(box: VBoxContainer, title: String) -> Dictionary:
|
||
var row := HBoxContainer.new()
|
||
box.add_child(row)
|
||
row.add_child(UiKit.label(title, 15, false))
|
||
var s := HSlider.new()
|
||
s.min_value = 0
|
||
s.max_value = 300
|
||
s.step = 5
|
||
s.custom_minimum_size = Vector2(320, 24)
|
||
row.add_child(s)
|
||
var v := UiKit.label("+0%", 15, true)
|
||
v.custom_minimum_size = Vector2(70, 0)
|
||
row.add_child(v)
|
||
s.value_changed.connect(_on_slider_value_changed)
|
||
return {"slider": s, "value_label": v}
|
||
|
||
|
||
func _sync_labels() -> void:
|
||
_atk_val.text = "+%d%%" % atk_pct()
|
||
_hp_val.text = "+%d%%" % hp_pct()
|
||
_eff.text = "生效值:攻击 %d → %d · 生命 %d → %d" % [
|
||
_base_atk, effective_atk(), _base_hp, effective_max_hp()]
|
||
|
||
|
||
func _scaled(base: int, pct: int) -> int:
|
||
return maxi(1, int(round(float(base) * (100.0 + float(pct)) / 100.0)))
|
||
|
||
|
||
func _emit_simulate_requested() -> void:
|
||
simulate_requested.emit(int(_sim_count.value))
|
||
|
||
|
||
func _emit_closed() -> void:
|
||
closed.emit()
|
||
|
||
|
||
func _on_slider_value_changed(_value: float) -> void:
|
||
_sync_labels()
|