feedback7 R22-LOADOUT: the data carries every potential (潜能 1–6), not only full potential; golden: unchanged
Potential becomes a per-player setting (the owner's decision of 2026-10-08: 「调配干员里自己设置吧,默认满潜满加成」;
official: 调度手册 「卫戍协议中干员潜能由自身已持有干员潜能决定」). 0.2.1 baked full potential into the data (§26.14).
- tools/build-data.mjs runs the chess / backups / tokens builders once per potential rank (ctx.potRank, 0–5) and keeps
the full-potential build annotated with what each lower rank changes: `potDown` { rank: { dotted.path: value } } on
chess records, backups.json forms and token variants (stats, statsBase; 望's 棋子 deployLimit / deckStack, 多萝西's
共振装置 count), and chained talent entries (`potMin` / `potBelow`: the candidates by requiredPotentialRank, the
fields a lower rank changes) in talents / talentsBase / modules[].talentChanges / variant talents. A self-check proves
shared/potential.js atRank rebuilds every rank exactly; the unit-form parity runs at every rank.
- shared/potential.js (new): atPotential / atRank, talentAtRank, stripPotential, and the 练度 helpers used next
(cultivateMul from the effects.json CHAR_MAP records aceffect_char_1…4, cultivationOf, cultivatedStats).
- composeTalents / composeUnitRecord return potential-resolved lists (no chains): a composed record is built at one
potential (its form resolved first).
- JSON compare: the new chess / backups / tokens minus the annotations equal the old files byte for byte; every other
data file identical; data/i18n/* rebuilt (the chained talent texts translated at the old rates: en 95.4 %, ja 95.2 %,
ko 95.2 %, zh-TW 90 %). Data 5.21 → 5.51 MB.
- Docs: DATA.md §2.3 (new), §2, §7, §14, §16, §18; research/03-operators.md; kits/README.md.
- Tests: test/potential.test.js (new, 7): every chess and 自选 form at every potential = the raw keyframes plus the
potential steps up to it, every talent = the last candidate with requiredPotentialRank ≤ the rank, 刺玫 at each
potential, summons at the owner's potential (Mon3tr 3 s / 1200, 望's 棋子 6 / 7, “小自在” 15), the 练度 table =
cultivateEffectList; data.test.js compares the composed talents without annotations.
This commit is contained in:
1 parent
ae22335cfe
commit
7e09c63da8
17 files changed
+614
-69
No files matched your search
+7
-4
@@ -15,6 +15,7 @@
|
||||
// chess's ids, so its kit must be looked up by its `charId`, never by `baseId` (that is the replaced operator's kit).
|
||||
|
||||
import { composeStats, composeTalents } from './loadoutRecord.js';
|
||||
import { stripPotential } from './potential.js';
|
||||
|
||||
/** The key of a unit form: a chess record's `status` as `${phase}/${level}/${skillLevel}/${equipLevel}`. */
|
||||
export function statusKey(status) {
|
||||
@@ -44,7 +45,9 @@ const byNatural = (a, b) => String(a).localeCompare(String(b), 'en', { numeric:
|
||||
* The same rules as tools/build-data.mjs buildChess: stats = form stats + the module's `attr`, trait = the module's
|
||||
* `traitOverride` or the form's, talents = form talents + the module's `talentChanges`; `module` is active only when
|
||||
* `status.equipLevel > 0` and the module has that level; an elite with `equipLevel > 0` carries
|
||||
* `statsBase` / `traitBase` / `talentsBase` / `modules[]`; `tokens` are the summons the selection produces.
|
||||
* `statsBase` / `traitBase` / `talentsBase` / `modules[]`; `tokens` are the summons the selection produces. The record is
|
||||
* composed at ONE potential: pass the form at the wanted potential (shared/potential.js atPotential — a stand-in has none)
|
||||
* and the result carries no potential annotation (`potDown`, chained talents).
|
||||
* @param {object} identity the data/chess.json record whose identity the unit takes (IDENTITY_FIELDS)
|
||||
* @param {object} unit backups.units[charId]
|
||||
* @param {object} form backups.units[charId].forms[statusKey(identity.status)]
|
||||
@@ -63,7 +66,7 @@ export function composeUnitRecord(identity, unit, form, { skillIndex, moduleId =
|
||||
const skill = skills.find((s) => s && s.index === skillIndex) ?? null;
|
||||
const mods = Array.isArray(form.modules) ? form.modules : null;
|
||||
const mod = moduleId && mods ? mods.find((m) => m && m.uniEquipId === moduleId) ?? null : null;
|
||||
const talents = mod ? composeTalents(form.talents, mod.talentChanges) : form.talents;
|
||||
const talents = composeTalents(form.talents, mod ? mod.talentChanges : null);
|
||||
// summons: listed by the character, produced by the selected skill or a talent (buildChess `tokens`)
|
||||
const known = new Set(form.tokens || []);
|
||||
const tokenIds = new Set([...(form.displayTokens || []), skill?.overrideTokenKey, ...(talents || []).map((t) => t?.tokenKey)]
|
||||
@@ -95,8 +98,8 @@ export function composeUnitRecord(identity, unit, form, { skillIndex, moduleId =
|
||||
if (golden && equipLevel > 0) {
|
||||
out.statsBase = form.stats;
|
||||
out.traitBase = form.trait;
|
||||
out.talentsBase = form.talents;
|
||||
out.modules = (mods || []).map((m) => ({ ...m, isDefault: m.uniEquipId === moduleId }));
|
||||
out.talentsBase = stripPotential(form.talents);
|
||||
out.modules = (mods || []).map((m) => ({ ...stripPotential(m), isDefault: m.uniEquipId === moduleId }));
|
||||
}
|
||||
if (standInFor) out.standInFor = standInFor;
|
||||
return out;
|
||||
|
||||
Reference in new issue
Block a user