Files
2026-10-30 23:54:07 +07:00

64 lines
3.9 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import * as p from './portal_bonus.mjs';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
const DIR = path.join(ROOT, 'resources/grid_fight');
const load = n => JSON.parse(fs.readFileSync(path.join(DIR, n), 'utf8'));
test('installed portal-bonus.json equals the derivation from the raw tables', () => {
const built = p.build(load('catalog.raw.json'), load('bonus.raw.json'), load('portals.json'));
assert.deepEqual(load('portal-bonus.json'), built);
assert.equal(Object.keys(built.portals).length, 74);
});
test('every Index Fund bundle resolves to season-2 cards of its own Bond and a basic component', () => {
const bonus = load('bonus.raw.json'), roles = load('roles.json'), wiki = load('wiki-4654.json'), table = load('portal-bonus.json');
const season = load('season.json').season_id;
const basic = id => bonus.GridFightBasicBonusConfigRow.find(r => r.BonusID === id);
const sold = row => row.raw.IsInPool && row.raw.SeasonID === season &&
!roles.some(o => o.avatar_id === row.avatar_id && o.id !== row.id && o.raw.IsInPool && o.raw.SeasonID === season && o.cost < row.cost);
const cheapest = avatar => roles.filter(r => r.avatar_id === avatar && sold(r)).sort((a, b) => a.cost - b.cost)[0];
for (const portal of wiki.portals.filter(x => x.id >= 2201 && x.id <= 2214)) {
const [bundle, trait, boost] = portal.params;
assert.equal(boost, 40);
assert.deepEqual(table.portals[portal.id].show, [bundle]);
assert.deepEqual(table.portals[portal.id].traits, [trait]);
const combo = bonus.GridFightCombinationBonusConfigRow.find(r => r.BonusID === bundle);
assert.equal(combo.CombinationBonusList[0], 1); // Gold Coins
assert.equal(combo.CombinationBonusList.at(-1), 101); // two random 1-cost cards (OrbConfig 200001)
assert.equal(combo.BonusNumberList.at(-1), 20000);
const rows = combo.CombinationBonusList.map(basic);
const cards = rows.filter(r => r.BonusType === 5).map(r => cheapest(r.BonusTypeParamList[0]));
assert.equal(cards.length, 2, 'portal ' + portal.id);
for (const card of cards) assert.ok(card && card.traits.includes(trait), `portal ${portal.id}: ${card && card.id} lacks trait ${trait}`);
const items = rows.filter(r => r.BonusType === 7).map(r => r.BonusTypeParamList[0]);
assert.equal(items.length, 1);
assert.ok(items[0] >= 350201 && items[0] <= 350208); // a basic component
}
});
test('Invitation, weapon-box and delayed bundles match the portal params', () => {
const bonus = load('bonus.raw.json'), wiki = load('wiki-4654.json'), table = load('portal-bonus.json').portals;
const item = id => bonus.GridFightBasicBonusConfigRow.find(r => r.BonusID === id).BonusTypeParamList[0];
for (const portal of wiki.portals.filter(x => x.id >= 2101 && x.id <= 2119)) assert.equal(item(table[portal.id].show[0]), portal.params[0]);
// 101: two Basic Weapon Boxes (99999) = params[0]; 102: Privilege box (99997) later; 104: Wealth Gem; 106: Staff Projector.
const combo = bonus.GridFightCombinationBonusConfigRow.find(r => r.BonusID === table[101].show[0]);
assert.equal(combo.BonusNumberList[0] / 10000, wiki.portals.find(x => x.id === 101).params[0]);
assert.equal(item(209), 99997);
assert.deepEqual(table[102].delayed, [209]);
assert.equal(item(table[104].delayed[0]), 350701);
assert.equal(item(205), 350105);
assert.deepEqual(table[106].delayed, [205]);
// 103: orbs 140021..140023 hold 6/8/12 coins (BonusID 1 x N).
for (const [i, coins] of [6, 8, 12].entries()) {
const c = bonus.GridFightCombinationBonusConfigRow.find(r => r.BonusID === 40021 + i);
assert.deepEqual(c.CombinationBonusList, [1]);
assert.equal(c.BonusNumberList[0] / 10000, coins);
assert.equal(wiki.portals.find(x => x.id === 103).params[i], coins);
}
});