feat(mana): 游戏设计器支持 mana 字段(补 Mana MVP 配套)

- Core 编辑器加「蓝上限/回蓝」两栏(_on_select 读 / _on_apply 写 / _on_new 默认),
  修复此前编辑 Core 保存会静默丢失 mana_max/mana_regen 的数据丢失洞
- 法术编辑器 4 个 meta 模板加 mana_cost,新法术默认有合理蓝耗
- handbook 07 补 Core 蓝池字段 + 法术 mana_cost 说明

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-21 10:31:01 +08:00
co-authored by Claude Opus 4.8
parent 022017e551
commit 7bc13a7be6
3 changed files with 17 additions and 6 deletions
+9 -1
View File
@@ -16,6 +16,8 @@ var _slots: SpinBox
var _topo: OptionButton var _topo: OptionButton
var _cpu: SpinBox var _cpu: SpinBox
var _interval: SpinBox var _interval: SpinBox
var _mana_max: SpinBox
var _mana_regen: SpinBox
var _feat: OptionButton var _feat: OptionButton
var _rows: SpinBox var _rows: SpinBox
var _cols: SpinBox var _cols: SpinBox
@@ -39,6 +41,8 @@ func _ready() -> void:
_topo = _row("拓扑", UI.opt(TOPO, 0)) _topo = _row("拓扑", UI.opt(TOPO, 0))
_cpu = _row("CPU 上限", UI.spin(1, 40, 1, 5)) _cpu = _row("CPU 上限", UI.spin(1, 40, 1, 5))
_interval = _row("施法间隔(s)", UI.spin(0.05, 5, 0.05, 0.5)) _interval = _row("施法间隔(s)", UI.spin(0.05, 5, 0.05, 0.5))
_mana_max = _row("蓝上限(Mana Max)", UI.spin(0, 1000, 5, 100))
_mana_regen = _row("回蓝/秒(Mana Regen)", UI.spin(0, 100, 0.5, 5))
_feat = _row("特性", UI.opt(FEAT, 0)) _feat = _row("特性", UI.opt(FEAT, 0))
_rows = _row("矩阵行(MATRIX)", UI.spin(1, 8, 1, 1)) _rows = _row("矩阵行(MATRIX)", UI.spin(1, 8, 1, 1))
_cols = _row("矩阵列(MATRIX)", UI.spin(1, 16, 1, 5)) _cols = _row("矩阵列(MATRIX)", UI.spin(1, 16, 1, 5))
@@ -81,6 +85,8 @@ func _on_select(idx: int) -> void:
_topo.selected = int(d.get("topology", 0)) _topo.selected = int(d.get("topology", 0))
_cpu.value = float(d.get("cpu_limit", 5)) _cpu.value = float(d.get("cpu_limit", 5))
_interval.value = float(d.get("cast_interval", 0.5)) _interval.value = float(d.get("cast_interval", 0.5))
_mana_max.value = float(d.get("mana_max", 100))
_mana_regen.value = float(d.get("mana_regen", 5))
_feat.selected = int(d.get("feature_tags", 0)) _feat.selected = int(d.get("feature_tags", 0))
_rows.value = float(d.get("grid_rows", 1)) _rows.value = float(d.get("grid_rows", 1))
_cols.value = float(d.get("grid_cols", 5)) _cols.value = float(d.get("grid_cols", 5))
@@ -99,6 +105,7 @@ func _on_apply() -> void:
"display_name": _name.text, "slot_count": int(_slots.value), "display_name": _name.text, "slot_count": int(_slots.value),
"topology": _topo.selected, "cpu_limit": int(_cpu.value), "topology": _topo.selected, "cpu_limit": int(_cpu.value),
"cast_interval": _interval.value, "feature_tags": _feat.selected, "cast_interval": _interval.value, "feature_tags": _feat.selected,
"mana_max": int(_mana_max.value), "mana_regen": _mana_regen.value,
"grid_rows": int(_rows.value), "grid_cols": int(_cols.value), "edges": edges, "grid_rows": int(_rows.value), "grid_cols": int(_cols.value), "edges": edges,
} }
_cur = cid _cur = cid
@@ -110,7 +117,8 @@ func _on_new() -> void:
var i := 1 var i := 1
while _data.has(cid): cid = "new_core_%d" % i; i += 1 while _data.has(cid): cid = "new_core_%d" % i; i += 1
_data[cid] = {"display_name": cid, "slot_count": 5, "topology": 0, _data[cid] = {"display_name": cid, "slot_count": 5, "topology": 0,
"cpu_limit": 5, "cast_interval": 0.5, "feature_tags": 0, "edges": []} "cpu_limit": 5, "cast_interval": 0.5, "feature_tags": 0,
"mana_max": 100, "mana_regen": 5, "edges": []}
_refresh() _refresh()
func _on_delete() -> void: func _on_delete() -> void:
+4 -4
View File
@@ -8,10 +8,10 @@ const TYPE_NAMES: Array = ["ACTION", "MODIFIER", "TRIGGER", "LOGIC"]
## meta 模板(按类型“插入模板”用) ## meta 模板(按类型“插入模板”用)
const META_TEMPLATES: Dictionary = { const META_TEMPLATES: Dictionary = {
0: '{ "base_damage": 5.0, "speed": 350.0, "lifetime": 4.0, "radius": 6.0, "damage_type": 0, "shop_cost": 20 }', 0: '{ "base_damage": 5.0, "speed": 350.0, "lifetime": 4.0, "radius": 6.0, "damage_type": 0, "mana_cost": 5, "shop_cost": 20 }',
1: '{ "damage_add": 10.0, "shop_cost": 20 }', 1: '{ "damage_add": 10.0, "mana_cost": 10, "shop_cost": 20 }',
2: '{ "base_damage": 3.0, "speed": 250.0, "lifetime": 4.0, "radius": 6.0, "damage_type": 0, "shop_cost": 30 }', 2: '{ "base_damage": 3.0, "speed": 250.0, "lifetime": 4.0, "radius": 6.0, "damage_type": 0, "mana_cost": 10, "shop_cost": 30 }',
3: '{ "logic_op": "every_n_shots", "n": 3, "reg": 0, "shop_cost": 24 }', 3: '{ "logic_op": "every_n_shots", "n": 3, "reg": 0, "mana_cost": 0, "shop_cost": 24 }',
} }
var _spells: Dictionary = {} # { id: {type, display_name, description, element_tags, meta} } var _spells: Dictionary = {} # { id: {type, display_name, description, element_tags, meta} }
+4 -1
View File
@@ -32,7 +32,8 @@
新增/编辑/删除法术,最丰富的玩法配置。详见 [06 法术编辑器](06_spell_editor.md)meta 字段速查表)。 新增/编辑/删除法术,最丰富的玩法配置。详见 [06 法术编辑器](06_spell_editor.md)meta 字段速查表)。
- 列表 → 选中编辑;➕新增 / ⧉复制 / 🗑删除 - 列表 → 选中编辑;➕新增 / ⧉复制 / 🗑删除
- 字段:ID / 类型(ACTION/MODIFIER/TRIGGER/LOGIC) / 显示名 / 描述 / 元素标签 / meta(JSON) - 字段:ID / 类型(ACTION/MODIFIER/TRIGGER/LOGIC) / 显示名 / 描述 / 元素标签 / meta(JSON)
- 「插入该类型 meta 模板」一键填入起始参数 - 「插入该类型 meta 模板」一键填入起始参数(模板已含 `mana_cost` 蓝耗、`shop_cost` 售价)
- 💧 **蓝耗**:每个法术的 `meta.mana_cost` 决定施放消耗的魔力(0=免蓝);权威数值见 `numerical_design §2`
### 👾 敌人(enemies.json ### 👾 敌人(enemies.json
6 种敌人原型的数值表格,**直接拖动数字框**调整: 6 种敌人原型的数值表格,**直接拖动数字框**调整:
@@ -70,6 +71,8 @@
| 拓扑 | LINEAR(线性) / MATRIX(矩阵邻接) / CIRCUIT(电路分叉) | | 拓扑 | LINEAR(线性) / MATRIX(矩阵邻接) / CIRCUIT(电路分叉) |
| CPU 上限 | 单次施法最大执行步数 | | CPU 上限 | 单次施法最大执行步数 |
| 施法间隔 | 自动施法冷却(s) | | 施法间隔 | 自动施法冷却(s) |
| 蓝上限(Mana Max) | 法杖蓝池上限(基础 100) |
| 回蓝/秒(Mana Regen) | 每秒回复的魔力(基础 5) |
| 特性 | 无 / PERSISTENT_MEMORY(寄存器跨帧) / … | | 特性 | 无 / PERSISTENT_MEMORY(寄存器跨帧) / … |
| 矩阵行·列 | MATRIX 专用网格尺寸 | | 矩阵行·列 | MATRIX 专用网格尺寸 |
| 电路边 | CIRCUIT 专用,JSON 有向边 `[{"from":0,"to":1}]` | | 电路边 | CIRCUIT 专用,JSON 有向边 `[{"from":0,"to":1}]` |