feedback5 CB5: a module's added trait line (official additionalDescription, PRTS 特性追加) shows after the class trait, not instead of it — the 干员调配 module card (特性 + 特性追加 rows), its 局内数值, the detail card and the 自选 module row (community report of 2026-10-06, item 16.2: 114 of the 164 modules the screen offers showed the extra line alone)

Text only: data/chess.json keeps both lines (traitOverride.desc = the class trait or the module's rewrite,
moduleDesc = the added line) and the battle unit keeps the class trait with the module on — the same trait
text, targeting and attack shape as 不装备 for every added-line module (圣约送葬人 REA-Y also rewrites it).
New helpers ui/loadoutModel.js traitLines / fullTraitText; traitText (ui/detailPanel.js) composes the two.
Golden unchanged (no sim change). Tests: test/ui/feedback5-module-trait.test.js (new), loadout-stats updated.
This commit is contained in:
sganggs committed 2026-10-07 01:33:21 +08:00
1 parent 30d9a41c51
commit 02353e13f8
8 files changed
+196 -20

No files matched your search

+5 -5
View File
@@ -196,9 +196,9 @@ test('特性 and 天赋 follow the chosen module: 隐现\'s trait upgrade is MAR
const rows = (id, level, entries) => kitRows(section(id, level, entries));
const { golden } = slot(INSIDE);
const traitOf = (rs) => rs.find((r) => r.k === '特性');
// default module: the module's upgraded trait text; 不装备: the plain class trait
assert.equal(traitOf(rows(INSIDE, 'elite', {})).text, golden.trait.moduleDescRaw);
assert.match(traitOf(rows(INSIDE, 'elite', {})).text, /110%/);
// default module: the class trait, then the module's added line (item 16.2 of 2026-10-06); 不装备: the plain class trait
assert.equal(traitOf(rows(INSIDE, 'elite', {})).text, `${golden.trait.descRaw}\n${golden.trait.moduleDescRaw}`);
assert.match(traitOf(rows(INSIDE, 'elite', {})).text, /^优先攻击空中单位\n[^\n]*110%/);
assert.equal(traitOf(rows(INSIDE, 'elite', { [INSIDE]: { module: 'none' } })).text, golden.traitBase.descRaw);
assert.equal(traitOf(rows(INSIDE, 'normal', {})).text, slot(INSIDE).base.trait.descRaw, '普通: its own trait');
// 天赋: named and not hidden, the record's list
@@ -292,8 +292,8 @@ test('特性 follows the chosen module also when the skill or the module differs
const chess = JSON.parse(fs.readFileSync(new URL('../../data/chess.json', import.meta.url), 'utf8'));
const get = (id) => chess[id];
const shown = (id, lo) => traitText(get(id), true, chessLoadout(get(id), lo, get));
// 隐现 (MAR-X): its other skill keeps the module's line, not the class trait 优先攻击空中单位
assert.match(shown('chess_char_1_01_b', { chess_char_1_01_a: { skill: 0, module: null } }), /攻击空中单位时攻击力提升至/);
// 隐现 (MAR-X): its other skill keeps the module's line after the class trait 优先攻击空中单位 (item 16.2)
assert.match(shown('chess_char_1_01_b', { chess_char_1_01_a: { skill: 0, module: null } }), /^优先攻击空中单位\n攻击空中单位时攻击力提升至/);
// 信仰搅拌机: SPT-Y shows its own line; 不装备 shows the class trait
assert.match(shown('chess_char_4_01_b', { chess_char_4_01_a: { skill: get('chess_char_4_01_b').skill.index, module: 'uniequip_003_rmixer' } }), /攻击距离\+1/);
assert.match(shown('chess_char_4_01_b', { chess_char_4_01_a: { skill: get('chess_char_4_01_b').skill.index, module: 'none' } }), /能够阻挡三个敌人/);