Files
spellforge/addons/game_designer/status_tab.gd
T
2026-07-20 10:56:52 +08:00

111 lines
3.8 KiB
GDScript

## 状态效果编辑器标签 — DoT/层数/持续时间/VFX
@tool
extends VBoxContainer
const UI = preload("res://addons/game_designer/designer_ui.gd")
const PATH = "res://data/status_effects.json"
const STACK = ["REFRESH 刷新", "INTENSITY 叠层", "INDEPENDENT 独立"]
var _data: Dictionary = {}
var _cur: String = ""
var _id: SpinBox
var _name: LineEdit
var _dur: SpinBox
var _tick: SpinBox
var _stack: OptionButton
var _max: SpinBox
var _dot: SpinBox
var _vfx: LineEdit
var _combo: CheckBox
var _list: ItemList
var _status: Label
func _ready() -> void:
add_child(UI.header("🔥 状态效果 — 燃烧/中毒/连击等 DoT 与叠层"))
_load()
_list = ItemList.new()
_list.custom_minimum_size = Vector2(0, 80)
_list.item_selected.connect(_on_select)
add_child(_list)
var brow := HBoxContainer.new(); add_child(brow)
brow.add_child(UI.btn("➕新增", _on_new))
brow.add_child(UI.btn("🗑删除", _on_delete))
add_child(HSeparator.new())
_id = _row("状态 ID(整数,1=燃烧 3=中毒…)", UI.spin(1, 999, 1, 9))
_name = _row("名称", UI.line(""))
_dur = _row("持续时间(s)", UI.spin(0.1, 999, 0.5, 3.0))
_tick = _row("跳字间隔(s)", UI.spin(0.1, 999, 0.5, 1.0))
_stack = _row("叠层模式", UI.opt(STACK, 0))
_max = _row("最大层数(0=无限)", UI.spin(0, 999, 1, 1))
_dot = _row("每跳伤害", UI.spin(0, 9999, 0.5, 0.0))
_vfx = _row("VFX ID", UI.line("", "status_burn"))
_combo = CheckBox.new(); _combo.text = "连击标记追踪器"
add_child(_combo)
add_child(HSeparator.new())
var srow := HBoxContainer.new(); add_child(srow)
srow.add_child(UI.btn("✓应用", _on_apply))
srow.add_child(UI.btn("💾保存 status_effects.json", _save))
_status = UI.status_label(); add_child(_status)
_refresh()
func _row(label: String, ctrl: Control) -> Control:
var h := HBoxContainer.new(); h.add_child(UI.cell_label(label)); h.add_child(ctrl); add_child(h)
return ctrl
func _load() -> void:
var d = UI.load_json(PATH)
_data = d if d is Dictionary else {}
func _refresh() -> void:
_list.clear()
var ids: Array = _data.keys(); ids.sort()
for k in ids:
_list.add_item("[%s] %s" % [k, _data[k].get("name", "")])
_list.set_item_metadata(_list.item_count - 1, k)
func _on_select(idx: int) -> void:
_cur = String(_list.get_item_metadata(idx))
var d: Dictionary = _data[_cur]
_id.value = float(int(_cur))
_name.text = String(d.get("name", ""))
_dur.value = float(d.get("duration", 3.0))
_tick.value = float(d.get("tick_interval", 1.0))
_stack.selected = int(d.get("stack_mode", 0))
_max.value = float(d.get("max_stacks", 1))
_dot.value = float(d.get("dot_damage", 0.0))
_vfx.text = String(d.get("vfx_id", ""))
_combo.button_pressed = bool(d.get("is_combo_tracker", false))
func _on_apply() -> void:
var sid := str(int(_id.value))
if _cur != "" and _cur != sid and _data.has(_cur):
_data.erase(_cur)
_data[sid] = {
"name": _name.text, "duration": _dur.value, "tick_interval": _tick.value,
"stack_mode": _stack.selected, "max_stacks": int(_max.value),
"dot_damage": _dot.value, "dot_damage_type": 0,
"vfx_id": _vfx.text, "is_combo_tracker": _combo.button_pressed,
}
_cur = sid
_refresh()
UI.set_status(_status, "✓ 已应用 ID %s(记得保存)" % sid)
func _on_new() -> void:
var sid := 9
while _data.has(str(sid)): sid += 1
_data[str(sid)] = {"name": "新状态", "duration": 3.0, "tick_interval": 1.0,
"stack_mode": 0, "max_stacks": 1, "dot_damage": 0.0, "dot_damage_type": 0,
"vfx_id": "", "is_combo_tracker": false}
_refresh()
func _on_delete() -> void:
if _cur != "" and _data.has(_cur):
_data.erase(_cur); _cur = ""; _refresh()
UI.set_status(_status, "已删除(记得保存)")
func _save() -> void:
if UI.save_json(PATH, _data):
UI.set_status(_status, "💾 已保存 %d 个状态(重启 F5 生效)" % _data.size())
else:
UI.set_status(_status, "✗ 保存失败", true)