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