feat(config-editor): port buildSkillDesc to JS for panel preview
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
import { test } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { buildSkillDesc } from '../src/shared/desc/buildSkillDesc';
|
||||||
|
import { RecordValue } from '../src/io/recordValue';
|
||||||
|
|
||||||
|
const skillSet: Record<number, RecordValue> = {
|
||||||
|
6301: { kind: 'obj', props: { name: { kind: 'str', value: '护盾' }, kind: { kind: 'enumRef', qualifier: 'SkillKind', member: 'Shield' }, ap: { kind: 'num', value: 4 } } },
|
||||||
|
};
|
||||||
|
const fieldSet: Record<number, RecordValue> = {
|
||||||
|
7015: { kind: 'obj', props: { name: { kind: 'str', value: '死亡强化' }, info: { kind: 'str', value: '死亡触发技能次数+1' } } },
|
||||||
|
};
|
||||||
|
const hero: RecordValue = { kind: 'obj', props: {
|
||||||
|
atked: { kind: 'arr', items: [{ kind: 'obj', props: { s_uuid: { kind: 'num', value: 6301 }, t_num: { kind: 'num', value: 3 }, overrides: { kind: 'obj', props: { ap: { kind: 'num', value: 4 } } } } }] },
|
||||||
|
field: { kind: 'arr', items: [{ kind: 'num', value: 7015 }] },
|
||||||
|
} };
|
||||||
|
|
||||||
|
test('renders atked trigger with shield effect', () => {
|
||||||
|
const out = buildSkillDesc(hero, skillSet, fieldSet);
|
||||||
|
assert.match(out, /受击3次:护盾/);
|
||||||
|
assert.match(out, /护盾4次/);
|
||||||
|
});
|
||||||
|
test('renders field aura', () => {
|
||||||
|
const out = buildSkillDesc(hero, skillSet, fieldSet);
|
||||||
|
assert.match(out, /场上存活:死亡强化 死亡触发技能次数\+1/);
|
||||||
|
});
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { RecordValue } from '../../io/recordValue';
|
||||||
|
|
||||||
|
const TRIGGER_KEYS = ['call', 'dead', 'fstart', 'fend', 'atking', 'atked'] as const;
|
||||||
|
const TRIGGER_DESC: Record<string, string> = {
|
||||||
|
call: '召唤时', dead: '死亡时', fstart: '战斗开始时', fend: '战斗结束时',
|
||||||
|
field: '场上存活', atking: '攻击n次', atked: '受击n次', revive: '复活时',
|
||||||
|
};
|
||||||
|
|
||||||
|
function num(v: RecordValue | undefined): number | undefined { return v && v.kind === 'num' ? v.value : undefined; }
|
||||||
|
function str(v: RecordValue | undefined): string | undefined { return v && v.kind === 'str' ? v.value : undefined; }
|
||||||
|
function member(v: RecordValue | undefined): string | undefined { return v && v.kind === 'enumRef' ? v.member : undefined; }
|
||||||
|
|
||||||
|
function buildEffect(merged: RecordValue): string {
|
||||||
|
if (merged.kind !== 'obj') return '';
|
||||||
|
const kind = member(merged.props['kind']);
|
||||||
|
const ap = num(merged.props['ap']) ?? 0;
|
||||||
|
const parts: string[] = [];
|
||||||
|
if (kind === 'Heal') parts.push(`治疗伙伴${ap}`);
|
||||||
|
else if (kind === 'Shield') parts.push(`护盾${ap}次`);
|
||||||
|
else if (kind === 'Gold') parts.push(`金币+${num(merged.props['gold']) ?? 0}`);
|
||||||
|
else if (kind === 'Support') parts.push(String(str(merged.props['info']) ?? ''));
|
||||||
|
else { // Damage / undefined
|
||||||
|
parts.push(`伤害${ap}%`);
|
||||||
|
if ((num(merged.props['hit_count']) ?? 1) > 1) parts.push(`${num(merged.props['hit_count'])}段`);
|
||||||
|
if (num(merged.props['crt'])) parts.push(`暴击+${num(merged.props['crt'])}%`);
|
||||||
|
if (num(merged.props['stun'])) parts.push(`击晕+${num(merged.props['stun'])}%`);
|
||||||
|
}
|
||||||
|
return parts.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 合并 overrides 到 base(浅合并对象 props) */
|
||||||
|
function merge(base: RecordValue, overrides: RecordValue | undefined): RecordValue {
|
||||||
|
if (!overrides || overrides.kind !== 'obj' || base.kind !== 'obj') return base;
|
||||||
|
return { kind: 'obj', props: { ...base.props, ...overrides.props } };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildSkillDesc(hero: RecordValue, skillSet: Record<number, RecordValue>, fieldSet: Record<number, RecordValue>): string {
|
||||||
|
if (hero.kind !== 'obj') return '';
|
||||||
|
const lines: string[] = [];
|
||||||
|
for (const key of TRIGGER_KEYS) {
|
||||||
|
const arr = hero.props[key];
|
||||||
|
if (!arr || arr.kind !== 'arr') continue;
|
||||||
|
const tpl = TRIGGER_DESC[key] ?? key;
|
||||||
|
for (const it of arr.items) {
|
||||||
|
if (it.kind !== 'obj') continue;
|
||||||
|
const su = num(it.props['s_uuid']); if (su === undefined) continue;
|
||||||
|
const base = skillSet[su]; if (!base) continue;
|
||||||
|
const merged = merge(base, it.props['overrides']);
|
||||||
|
const trigger = tpl.includes('n') ? tpl.replace('n', String(num(it.props['t_num']) ?? '')) : tpl;
|
||||||
|
lines.push(`${trigger}:${str(base.props['name'])} ${buildEffect(merged)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fl = hero.props['field'];
|
||||||
|
if (fl && fl.kind === 'arr') {
|
||||||
|
for (const it of fl.items) { const u = num(it); if (u === undefined) continue; const fs = fieldSet[u]; if (fs) lines.push(`${TRIGGER_DESC.field}:${str(fs.props['name'])} ${str(fs.props['info'])}`); }
|
||||||
|
}
|
||||||
|
const rv = hero.props['revive'];
|
||||||
|
if (rv && rv.kind === 'obj') {
|
||||||
|
const su = num(rv.props['s_uuid']); const base = su !== undefined ? skillSet[su] : undefined;
|
||||||
|
if (base) lines.push(`${TRIGGER_DESC.revive} : ${str(base.props['name'])} ${buildEffect(merge(base, undefined))}`);
|
||||||
|
}
|
||||||
|
return lines.join('\n');
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user