111 lines
3.8 KiB
GDScript
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)
|