feat(trigger-editor): 添加触发组概率与保底配置功能
1. 新增触发组条目字段t_chance(触发概率)和pity_add(保底叠加),仅攻击/受击组生效 2. 为TriggerGroupEditor传入分组标识,动态显示概率配置表单项 3. 新增条目创建时继承同组末档概率参数的逻辑 4. 更新常量定义与文档说明,补充概率参数使用规则 5. 在前端展示和服务端导出中添加概率相关信息展示
This commit is contained in:
@@ -68,18 +68,18 @@
|
||||
],
|
||||
"atking": {},
|
||||
"atked": {
|
||||
"6301": [
|
||||
"6302": [
|
||||
{
|
||||
"lv": 4,
|
||||
"s_lv": 1,
|
||||
"name": "全体圣盾",
|
||||
"name": "",
|
||||
"t_num": 3,
|
||||
"overrides": {
|
||||
"TGroup": null,
|
||||
"ap": 10,
|
||||
"icon": "Stat_UnitSummonIncrease_01"
|
||||
"ap": 10
|
||||
},
|
||||
"desc": "全队获得本英雄生命最大值{ap}%的护盾"
|
||||
"desc": "有 {t_chance}% 的概率,治疗自己 {ap}%生命最大值",
|
||||
"t_chance": 50,
|
||||
"pity_add": 20
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -70,9 +70,11 @@
|
||||
## 4. 触发组规范(atking / atked / fstart / fend / dead)
|
||||
|
||||
- 结构:`{ "<技能uuid字符串>": [条目, ...] }`,一个组可挂多个技能 uuid;
|
||||
- 条目:`{lv, s_lv, name, t_num, overrides, desc}`;
|
||||
- 条目:`{lv, s_lv, name, t_num, t_chance?, pity_add?, overrides, desc}`;
|
||||
- 解锁等级惯例 **lv4**(`lv:4, s_lv:1`;heroSet.ts 头部注释写的 lv6 已过时,现有英雄与编辑器默认值均为 lv4);
|
||||
- `t_num`:每 n 次普攻(atking)/受击(atked)触发一次;fstart/fend 为每回合开始/结束固定触发 1 次,`t_num` 恒填 1;
|
||||
- `t_chance`:触发概率(百分点 0~100,**仅 atking/atked 生效**,其余组忽略);缺省/100 = 必触发。示例 30 表示次数条件达成后掷骰 30%;
|
||||
- `pity_add`:保底叠加(百分点,仅 atking/atked 生效);未触发时为该技能累积下次概率增量,触发成功后清零、封顶 100。示例 `t_chance:30, pity_add:20` → 30/50/70/90/100 递进;
|
||||
- `name` 为组对外展示名(写在该组首档),留空回退底座名;
|
||||
- 复活:在 `dead` 某条目 `overrides` 配 `revive_hp`(回血%)+ `revive_count`(次数上限);
|
||||
- 无触发组时写空对象 `{}`,**不要省略字段**。
|
||||
|
||||
@@ -215,6 +215,9 @@ function renderSingleHero(h) {
|
||||
if (e.s_lv) eparts.push(`s_lv: SkillLv.Lv${e.s_lv}`)
|
||||
if (e.name) eparts.push(`name: ${JSON.stringify(e.name)}`)
|
||||
eparts.push(`t_num: ${e.t_num}`)
|
||||
// 概率参数:仅攻/受击触发消费;缺省(100/0)不输出,保持生成 TS 干净
|
||||
if (e.t_chance != null && e.t_chance < 100) eparts.push(`t_chance: ${e.t_chance}`)
|
||||
if (e.pity_add != null && e.pity_add > 0) eparts.push(`pity_add: ${e.pity_add}`)
|
||||
if (e.overrides && Object.keys(e.overrides).length) eparts.push(`overrides: ${serializeOverrides(e.overrides)}`)
|
||||
if (e.desc) eparts.push(`desc: ${JSON.stringify(e.desc)}`)
|
||||
push(` { ${eparts.join(', ')} },`)
|
||||
@@ -351,6 +354,8 @@ function csvTrigger(grp) {
|
||||
const name = e.name || base?.name || ''
|
||||
const ov = e.overrides || {}
|
||||
const parts = [`t_num${e.t_num}`]
|
||||
// 攻/受击组附带概率信息(缺省 100 不展示)
|
||||
if (e.t_chance != null && e.t_chance < 100) parts.push(`概率${e.t_chance}%`)
|
||||
if (ov.ap != null) parts.push(`ap${ov.ap}`)
|
||||
const desc = e.desc || ''
|
||||
return `${sid} ${name}(${parts.join(';')}):${desc}`
|
||||
|
||||
@@ -165,11 +165,11 @@
|
||||
<div class="panel">
|
||||
<h3>触发技能(lv4 激活)</h3>
|
||||
<el-tabs>
|
||||
<el-tab-pane label="atking 攻击后"><TriggerGroupEditor :model="current.atking" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="atked 受击后"><TriggerGroupEditor :model="current.atked" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="fstart 战斗开始"><TriggerGroupEditor :model="current.fstart" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="fend 回合结束"><TriggerGroupEditor :model="current.fend" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="dead 死亡后"><TriggerGroupEditor :model="current.dead" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="atking 攻击后"><TriggerGroupEditor group="atking" :model="current.atking" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="atked 受击后"><TriggerGroupEditor group="atked" :model="current.atked" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="fstart 战斗开始"><TriggerGroupEditor group="fstart" :model="current.fstart" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="fend 回合结束"><TriggerGroupEditor group="fend" :model="current.fend" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
<el-tab-pane label="dead 死亡后"><TriggerGroupEditor group="dead" :model="current.dead" :skill-options="allSkills" :skill-map="skillMap" :buff-options="buffOptions" /></el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
@@ -380,7 +380,15 @@ function triggerSummary(h) {
|
||||
const name = entries[0]?.name || skillMap.value[sid]?.name || ''
|
||||
const e = entries[0]
|
||||
const ov = e?.overrides || {}
|
||||
const parts = [`t_num${e?.t_num}`, ...overrideParts(ov)]
|
||||
const parts = [`t_num${e?.t_num}`]
|
||||
// 攻/受击组附带概率与保底信息(缺省 100%/0 不展示)
|
||||
if (tk === 'atking' || tk === 'atked') {
|
||||
if (e?.t_chance != null && e.t_chance < 100) {
|
||||
parts.push(`概率${e.t_chance}%`)
|
||||
if (e.pity_add > 0) parts.push(`保底+${e.pity_add}%`)
|
||||
}
|
||||
}
|
||||
parts.push(...overrideParts(ov))
|
||||
lines.push(`${tk}: ${sid} ${name} lv${minLv} ${parts.join(' ')}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
<span class="tpl-meta-item">{{ p.uuid }} {{ skillName(p.uuid) }}</span>
|
||||
<span class="tpl-meta-sep">·</span>
|
||||
<span class="tpl-meta-item">t_num {{ p.entry.t_num }}</span>
|
||||
<span class="tpl-meta-sep" v-if="p.entry.t_chance != null && p.entry.t_chance < 100">·</span>
|
||||
<span class="tpl-meta-item" v-if="p.entry.t_chance != null && p.entry.t_chance < 100">概率 {{ p.entry.t_chance }}%</span>
|
||||
<span class="tpl-meta-sep">·</span>
|
||||
<span class="tpl-meta-item">lv{{ p.entry.lv }}</span>
|
||||
</div>
|
||||
@@ -129,6 +131,14 @@
|
||||
<el-form-item label="t_num">
|
||||
<el-input-number v-model="currentTrigger.entry.t_num" :min="1" :controls="false" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<template v-if="currentTrigger.group === 'atking' || currentTrigger.group === 'atked'">
|
||||
<el-form-item label="t_chance 触发概率%(空=100)">
|
||||
<el-input-number v-model="currentTrigger.entry.t_chance" :min="0" :max="100" :controls="false" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="pity_add 保底叠加%(空=0)">
|
||||
<el-input-number v-model="currentTrigger.entry.pity_add" :min="0" :max="100" :controls="false" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item label="组名 name">
|
||||
<el-input v-model="currentTrigger.entry.name" placeholder="留空回退底座名" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -81,6 +81,13 @@ function removeGroup(sid) {
|
||||
}
|
||||
function addEntry(group) {
|
||||
const lastLv = group.length ? group[group.length - 1].lv : 4
|
||||
group.push({ lv: lastLv + 3, s_lv: 2, name: '', t_num: 3, overrides: {}, desc: '' })
|
||||
const entry = { lv: lastLv + 3, s_lv: 2, name: '', t_num: 3, overrides: {}, desc: '' }
|
||||
// 概率参数沿袭组内末档(攻/受击触发才生效)
|
||||
if (chanceVisible.value && group.length) {
|
||||
const last = group[group.length - 1]
|
||||
entry.t_chance = last.t_chance ?? null
|
||||
entry.pity_add = last.pity_add ?? null
|
||||
}
|
||||
group.push(entry)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -117,7 +117,7 @@ export function defaultHero() {
|
||||
dodge: null, // 闪避率(null = 全局默认 15,填值覆盖)
|
||||
accuracy: null, // 命中率(null = 全局默认 10,填值覆盖)
|
||||
skills: [], // [{uuid,name,cd,cdExpr,overrides,desc,lv_entries:[{lv,s_lv,overrides,desc}]}]
|
||||
atking: {}, // {uuid:[{lv,s_lv,name,t_num,overrides,desc}]}
|
||||
atking: {}, // {uuid:[{lv,s_lv,name,t_num,t_chance?,pity_add?,overrides,desc}]} t_chance/pity_add 仅攻/受击组生效
|
||||
atked: {},
|
||||
fstart: {},
|
||||
fend: {},
|
||||
|
||||
Reference in New Issue
Block a user