Improve IK-style artifact scanner pipeline

This commit is contained in:
AzuTear
2026-07-07 22:02:24 +02:00
parent 8ebbe91c39
commit f791d1464c
70 changed files with 7408 additions and 445 deletions
+106
View File
@@ -44,6 +44,9 @@ const artifactPieces = artifacts
const slotByPiece = Object.fromEntries(artifactPieces.map((piece) => [piece.name, piece.slot]));
const setByPiece = Object.fromEntries(artifactPieces.map((piece) => [piece.name, piece.setName]));
const setToPieces = Object.fromEntries(
artifacts.map((set) => [set.name, artifactPieces.filter((piece) => piece.setName === set.name).map((piece) => piece.name)]),
);
const mainStats = [
'Elemental Mastery',
@@ -198,6 +201,23 @@ const data = {
'Qiqi ': 'Qiqi',
},
},
lookup: {
normalizedKeys: {
sets: normalizedMap(artifacts.map((set) => set.name)),
pieces: normalizedMap(artifactPieces.map((piece) => piece.name)),
slots: normalizedMap(['Flower of Life', 'Plume of Death', 'Sands of Eon', 'Goblet of Eonothem', 'Circlet of Logos']),
stats: normalizedMap([...mainStats, ...substats]),
characters: normalizedMap(characters.map((character) => character.name)),
},
goodKeys: {
sets: Object.fromEntries(artifacts.map((set) => [set.name, goodKey(set.name)])),
pieces: Object.fromEntries(artifactPieces.map((piece) => [piece.name, goodKey(piece.name)])),
stats: Object.fromEntries([...mainStats, ...substats].map((stat) => [stat, goodStatKey(stat)])),
characters: Object.fromEntries(characters.map((character) => [character.name, goodKey(character.name)])),
},
setToPieces,
validation: validateLookupPackage({ artifacts, artifactPieces, characters, mainStats, substats, setToPieces }),
},
uiProfiles: {
artifactDetailEn: {
language: 'English',
@@ -231,3 +251,89 @@ function slotFromRelicType(relicType) {
return '';
}
}
function normalizeLookupKey(value) {
return String(value)
.toLowerCase()
.normalize('NFKD')
.replace(/[']/g, '')
.replace(/[^a-z0-9]+/g, '');
}
function normalizedMap(values) {
return Object.fromEntries(values.filter(Boolean).map((value) => [normalizeLookupKey(value), value]));
}
function goodKey(value) {
return String(value)
.replace(/[']/g, '')
.replace(/[^A-Za-z0-9]+(.)/g, (_match, next) => String(next).toUpperCase())
.replace(/^[a-z]/, (first) => first.toUpperCase())
.replace(/[^A-Za-z0-9]/g, '');
}
function goodStatKey(stat) {
switch (stat) {
case 'HP':
return 'hp';
case 'HP%':
return 'hp_';
case 'ATK':
return 'atk';
case 'ATK%':
return 'atk_';
case 'DEF':
return 'def';
case 'DEF%':
return 'def_';
case 'Elemental Mastery':
return 'eleMas';
case 'Energy Recharge':
return 'enerRech_';
case 'CRIT Rate':
return 'critRate_';
case 'CRIT DMG':
return 'critDMG_';
case 'Healing Bonus':
return 'heal_';
case 'Physical DMG Bonus':
return 'physical_dmg_';
default:
return stat.toLowerCase().replace(' dmg bonus', '_dmg_').replace(/\s+/g, '');
}
}
function validateLookupPackage({ artifacts, artifactPieces, characters, mainStats, substats, setToPieces }) {
const errors = [];
const warnings = [];
const setNames = new Set(artifacts.map((set) => set.name));
const slotNames = new Set(['Flower of Life', 'Plume of Death', 'Sands of Eon', 'Goblet of Eonothem', 'Circlet of Logos']);
const goodSetKeys = new Set();
for (const set of artifacts) {
const key = goodKey(set.name);
if (goodSetKeys.has(key)) errors.push(`Duplicate GOOD set key: ${key}`);
goodSetKeys.add(key);
if ((setToPieces[set.name] ?? []).length === 0) warnings.push(`Set has no pieces: ${set.name}`);
}
for (const piece of artifactPieces) {
if (!setNames.has(piece.setName)) errors.push(`Piece ${piece.name} references missing set ${piece.setName}`);
if (!slotNames.has(piece.slot)) errors.push(`Piece ${piece.name} references missing slot ${piece.slot}`);
}
if (!characters.length) warnings.push('No characters generated.');
if (!mainStats.length || !substats.length) errors.push('Stats were not generated.');
return {
valid: errors.length === 0,
errors,
warnings,
summary: {
artifactSets: artifacts.length,
artifactPieces: artifactPieces.length,
characters: characters.length,
stats: mainStats.length + substats.length,
},
};
}