feat: 新增预设库管理与一键创建英雄向导
1. 新增服务端模板持久化接口,支持触发/光环预设的读写 2. 前端新增预设库管理页面,支持增删改查触发/光环预设 3. 新增英雄创建向导,支持按职业快速生成英雄并套用预设 4. 调整本地开发端口与代理地址 5. 补充职业默认配置与攻速映射等常量定义
This commit is contained in:
132
put/server/data/templates.json
Normal file
132
put/server/data/templates.json
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"triggerPresets": [
|
||||
{
|
||||
"id": "tp-atking-fenli",
|
||||
"label": "每3次普攻·奋力一击",
|
||||
"group": "atking",
|
||||
"uuid": 6004,
|
||||
"tags": ["伤害"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "风暴打击", "t_num": 3, "overrides": { "ap": 300 }, "desc": "立刻打击{target},造成攻击力{ap}%伤害" }
|
||||
},
|
||||
{
|
||||
"id": "tp-atking-poison",
|
||||
"label": "每3次普攻·蚀骨毒箭",
|
||||
"group": "atking",
|
||||
"uuid": 6007,
|
||||
"tags": ["伤害", "持续"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "蚀骨毒箭", "t_num": 3, "overrides": { "ap": 80, "timed_debuff_id": 7005, "debuff_value": 40, "debuff_chance": 100 }, "desc": "追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒" }
|
||||
},
|
||||
{
|
||||
"id": "tp-atking-heavy-arrow",
|
||||
"label": "每3次普攻·追加重箭",
|
||||
"group": "atking",
|
||||
"uuid": 6008,
|
||||
"tags": ["伤害", "击退"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "", "t_num": 3, "overrides": { "ap": 120, "bck_chance": 50 }, "desc": "" }
|
||||
},
|
||||
{
|
||||
"id": "tp-atking-shield",
|
||||
"label": "每3次普攻·附加护盾",
|
||||
"group": "atking",
|
||||
"uuid": 6301,
|
||||
"tags": ["防御", "团队"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "圣愈之盾", "t_num": 3, "overrides": { "ap": 30 }, "desc": "{target}获得生命最大值{ap}%的护盾" }
|
||||
},
|
||||
{
|
||||
"id": "tp-atked-shield-team",
|
||||
"label": "受击3次·全队护盾",
|
||||
"group": "atked",
|
||||
"uuid": 6301,
|
||||
"tags": ["防御", "团队"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "全体圣盾", "t_num": 3, "overrides": { "ap": 10 }, "desc": "全队获得本英雄生命最大值{ap}%的护盾" }
|
||||
},
|
||||
{
|
||||
"id": "tp-atked-heal-self",
|
||||
"label": "受击3次·自我治疗",
|
||||
"group": "atked",
|
||||
"uuid": 6302,
|
||||
"tags": ["治疗"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "", "t_num": 3, "overrides": { "ap": 5 }, "desc": "为自己释放治疗,恢复生命值的{ap}%" }
|
||||
},
|
||||
{
|
||||
"id": "tp-atked-thorns",
|
||||
"label": "受击3次·荆棘反伤",
|
||||
"group": "atked",
|
||||
"uuid": 6516,
|
||||
"tags": ["反伤", "防御"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "荆棘回应", "t_num": 3, "overrides": { "timed_buff_id": 7028, "buff_value": 10 }, "desc": "凝聚荆棘护体,受击时反弹{buff_value}%所受伤害" }
|
||||
},
|
||||
{
|
||||
"id": "tp-fstart-crit-burst",
|
||||
"label": "开场·团队暴击",
|
||||
"group": "fstart",
|
||||
"uuid": 6504,
|
||||
"tags": ["增益", "团队", "暴击"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "猎杀时刻", "t_num": 1, "overrides": { "buff_value": 30 }, "desc": "战斗开始时全体友方暴击率提升{buff_value}%" }
|
||||
},
|
||||
{
|
||||
"id": "tp-fstart-armor-break",
|
||||
"label": "开场·先手破甲",
|
||||
"group": "fstart",
|
||||
"uuid": 6012,
|
||||
"tags": ["减益", "破甲"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "先手蚀甲", "t_num": 1, "overrides": { "ap": 150, "timed_debuff_id": 7008 }, "desc": "战斗开始掷出蚀甲酸瓶,必定使其破甲" }
|
||||
},
|
||||
{
|
||||
"id": "tp-fstart-lightning",
|
||||
"label": "开场·雷击先手",
|
||||
"group": "fstart",
|
||||
"uuid": 6203,
|
||||
"tags": ["伤害", "麻痹"],
|
||||
"entry": { "lv": 4, "s_lv": 1, "name": "雷击先手", "t_num": 1, "overrides": { "ap": 150, "para": 30 }, "desc": "战斗开始释放雷击,对{target}造成{ap}%伤害,{para}%概率麻痹" }
|
||||
}
|
||||
],
|
||||
"fieldPresets": [
|
||||
{
|
||||
"id": "fp-crit-master",
|
||||
"label": "暴击双光环(暴击率+暴伤)",
|
||||
"tags": ["暴击"],
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{ "uuid": 7004, "value": 0.12, "name": "剑刃风暴" },
|
||||
{ "uuid": 7005, "value": 0.2, "name": "斩魂利刃" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "fp-atk-aura",
|
||||
"label": "攻击光环 15%",
|
||||
"tags": ["增伤"],
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{ "uuid": 7002, "value": 0.15, "name": "" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "fp-atk-speed",
|
||||
"label": "攻速光环 15%",
|
||||
"tags": ["攻速"],
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{ "uuid": 7006, "value": 0.15, "name": "" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "fp-armor-pierce",
|
||||
"label": "穿透光环 10%",
|
||||
"tags": ["破甲"],
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{ "uuid": 7009, "value": 0.1, "name": "锐矛之赐" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "fp-thorns-aura",
|
||||
"label": "荆棘领域 8",
|
||||
"tags": ["反伤", "防御"],
|
||||
"lv": 4,
|
||||
"uuids": [
|
||||
{ "uuid": 7022, "value": 8, "name": "荆棘领域" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -103,6 +103,47 @@ app.post('/api/heroes', (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
const TEMPLATES_PATH = path.join(DATA_DIR, 'templates.json')
|
||||
|
||||
/** 预设库持久化:GET 读取(无文件时返回空池) */
|
||||
app.get('/api/templates', (_req, res) => {
|
||||
try {
|
||||
if (!fs.existsSync(TEMPLATES_PATH)) return res.json({ triggerPresets: [], fieldPresets: [] })
|
||||
const data = JSON.parse(fs.readFileSync(TEMPLATES_PATH, 'utf8'))
|
||||
// 兼容旧格式:若根上是 templates 数组,返回空池让前端走默认
|
||||
if (Array.isArray(data.templates)) return res.json({ triggerPresets: [], fieldPresets: [] })
|
||||
res.json({
|
||||
triggerPresets: Array.isArray(data.triggerPresets) ? data.triggerPresets : [],
|
||||
fieldPresets: Array.isArray(data.fieldPresets) ? data.fieldPresets : [],
|
||||
})
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 职业模板持久化:POST 全量覆盖保存(结构:{ triggerPresets: [], fieldPresets: [] }) */
|
||||
app.post('/api/templates', (req, res) => {
|
||||
const body = req.body || {}
|
||||
const triggerPresets = body.triggerPresets
|
||||
const fieldPresets = body.fieldPresets
|
||||
if (!Array.isArray(triggerPresets) || !Array.isArray(fieldPresets)) {
|
||||
return res.status(400).json({ error: 'triggerPresets 与 fieldPresets 必须为数组' })
|
||||
}
|
||||
// 触发预设必须绑定合法触发组
|
||||
const groups = ['atking', 'atked', 'fstart', 'dead']
|
||||
const bad = triggerPresets.find((p) => !groups.includes(p.group))
|
||||
if (bad) {
|
||||
return res.status(400).json({ error: `触发预设 ${bad.id || bad.label} 的 group 非法:${bad.group}` })
|
||||
}
|
||||
try {
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true })
|
||||
fs.writeFileSync(TEMPLATES_PATH, JSON.stringify({ triggerPresets, fieldPresets }, null, 2), 'utf8')
|
||||
res.json({ ok: true, path: TEMPLATES_PATH, triggerCount: triggerPresets.length, fieldCount: fieldPresets.length })
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: String(e?.message || e) })
|
||||
}
|
||||
})
|
||||
|
||||
/** 序列化 overrides:TGroup 以字符串存储(如 "Team"),导出时还原为枚举表达式 TGroup.Team;
|
||||
* buff_target 以数值存储(0-3),导出时还原为 BuffTarget.X 枚举表达式提升可读性 */
|
||||
const BUFF_TARGET_NAMES = ['Hit', 'Self', 'Ally', 'Enemy']
|
||||
|
||||
Reference in New Issue
Block a user