Online co-op browser remake of Arknights' Stronghold Protocol: Alliance (client-simulated combat, official waves/bonds/items/strategies, 3D board, facing wheel, operator loadout, official emotes, deployment scripts).
78 lines
4.0 KiB
JavaScript
78 lines
4.0 KiB
JavaScript
// Asset URL helpers (public/js/ui/assetUrls.js) against the real manifest: every visible chess resolves its
|
|
// avatar and portrait (normal + golden), bonds / bands / items / enemies / factions / titles resolve, and
|
|
// nothing outside the manifest is ever returned.
|
|
|
|
import { test, describe } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import {
|
|
uiUrl, chessAvatarUrl, chessPortraitUrl, skillIconUrl, profIconUrl, subProfIconUrl, bondIconUrl, bandIconUrl, itemIconUrl,
|
|
enemyIconUrl, tokenAvatarUrl, factionIconUrl, titleIconUrl, effectIconUrl,
|
|
} from '../../public/js/ui/assetUrls.js';
|
|
|
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
const load = (f) => JSON.parse(readFileSync(path.join(ROOT, 'data', f), 'utf8'));
|
|
const m = load('assets.json');
|
|
const chess = load('chess.json');
|
|
|
|
function manifestUrls(obj, out = new Set()) {
|
|
if (typeof obj === 'string' && obj.startsWith('/assets/')) out.add(obj);
|
|
else if (obj && typeof obj === 'object') for (const v of Object.values(obj)) manifestUrls(v, out);
|
|
return out;
|
|
}
|
|
const ALL = manifestUrls(m);
|
|
const inManifest = (u) => u == null || ALL.has(u);
|
|
|
|
describe('assetUrls', () => {
|
|
test('every visible chess (normal + golden) has avatar, portrait and skill icon', () => {
|
|
let n = 0;
|
|
for (const c of Object.values(chess)) {
|
|
if (!c.charId || c.isDiy) continue;
|
|
const a = chessAvatarUrl(m, c);
|
|
const p = chessPortraitUrl(m, c);
|
|
assert.ok(a && inManifest(a), `avatar ${c.chessId}`);
|
|
assert.ok(p && inManifest(p), `portrait ${c.chessId}`);
|
|
assert.ok(inManifest(skillIconUrl(m, c)), `skill ${c.chessId}`);
|
|
assert.ok(inManifest(profIconUrl(m, c.profession)));
|
|
assert.ok(inManifest(subProfIconUrl(m, c)));
|
|
n++;
|
|
}
|
|
assert.ok(n >= 200);
|
|
const golden = Object.values(chess).find((c) => c.isGolden && m.chars[c.charId]?.avatarE2);
|
|
assert.equal(chessAvatarUrl(m, golden), m.chars[golden.charId].avatarE2, 'golden uses E2 art');
|
|
});
|
|
test('bonds, bands, items, enemies, tokens, factions, titles, effects', () => {
|
|
for (const id of Object.keys(load('bonds.json'))) assert.ok(bondIconUrl(m, id), id);
|
|
for (const id of Object.keys(load('bands.json'))) assert.ok(bandIconUrl(m, id), id);
|
|
for (const it of Object.values(load('items.json'))) assert.ok(inManifest(itemIconUrl(m, it)), it.id);
|
|
assert.ok(itemIconUrl(m, Object.values(load('items.json'))[0]));
|
|
const enemies = load('enemies.json');
|
|
let found = 0;
|
|
for (const k of Object.keys(enemies)) { const u = enemyIconUrl(m, k); assert.ok(inManifest(u), k); if (u) found++; }
|
|
assert.ok(found > Object.keys(enemies).length * 0.9);
|
|
for (const t of Object.values(load('factions.json').types)) assert.ok(factionIconUrl(m, t.icon), t.type);
|
|
for (const t of load('config.json').titles) assert.ok(titleIconUrl(m, t.picId), t.id);
|
|
assert.ok(tokenAvatarUrl(m, 'token_10028_vigil_wolf'));
|
|
assert.ok(effectIconUrl(m, { iconKind: 'team' }));
|
|
assert.ok(effectIconUrl(m, { iconKind: 'choice' }));
|
|
assert.ok(effectIconUrl(m, { iconKind: 'band', iconId: 'band_bldsk' }));
|
|
assert.ok(effectIconUrl(m, { iconKind: 'garrison' }));
|
|
assert.equal(effectIconUrl(m, { iconKind: 'x' }), null);
|
|
assert.ok(uiUrl(m, 'hudPanel/icon_hp'));
|
|
});
|
|
test('missing manifest / ids ⇒ null, never throws', () => {
|
|
for (const fn of [chessAvatarUrl, chessPortraitUrl, skillIconUrl, subProfIconUrl, itemIconUrl]) {
|
|
assert.equal(fn(null, null), null);
|
|
assert.equal(fn(m, { assets: {} }) ?? null, fn === skillIconUrl ? uiUrl(m, 'skillIcon/empty') : null);
|
|
}
|
|
assert.equal(bondIconUrl(m, 'nope'), null);
|
|
assert.equal(bandIconUrl(null, 'band_bldsk'), null);
|
|
assert.equal(enemyIconUrl(m, 'enemy_nope'), null);
|
|
assert.equal(profIconUrl(m, 'NOPE'), null);
|
|
assert.equal(uiUrl(undefined, 'x'), null);
|
|
assert.equal(tokenAvatarUrl(m, null), null);
|
|
});
|
|
});
|