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 r from './rewards.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); const fix = n => ({wire: BigInt(Math.round(n * 4294967296))}); test('fixed decodes Q32.32 and rounds the float noise of the client', () => { assert.equal(r.fixed({wire: 4294967300}), 1); assert.equal(r.fixed({wire: 343597384}), 0.08); assert.equal(r.fixed({wire: 103079215104}), 24); assert.equal(r.fixed(undefined), 0); }); test('elite resource: ids follow family*100+quality and tables are sorted', () => { const out = r.eliteResource({ GridFightBinaryNodeRuleConfigRow: [{ID: 10302, Quality: 2, PerformLevel: 2}, {ID: 1, Quality: 1, PerformLevel: 1}, {ID: 10301, Quality: 1, PerformLevel: 1}], GridFightBinaryDiffAddRuleConfigRow: [{ID: 2, Quality: 1}, {ID: 1, Quality: 2, EnemyDifficultyAddValue: 5}], GridFightEnemyDifficultyLvConfigRow: [{ChapterID: 2, EnemyDifficultyLevel: 1, HPRatio: fix(4.16)}, {ChapterID: 1, HPRatio: fix(4)}] }); assert.deepEqual(out.node_rules.map(x => [x.id, x.family, x.quality]), [[1, 0, 1], [10301, 103, 1], [10302, 103, 2]]); assert.deepEqual(out.diff_add, [{rule: 1, quality: 2, add: 5}, {rule: 2, quality: 1, add: 0}]); assert.deepEqual(out.difficulty.map(x => [x.chapter, x.level, x.hp]), [[1, 0, 4], [2, 1, 4.16]]); assert.throws(() => r.eliteResource({ GridFightBinaryNodeRuleConfigRow: [{ID: 10399, Quality: 2}], GridFightBinaryDiffAddRuleConfigRow: [], GridFightEnemyDifficultyLvConfigRow: [] }), /family\*100\+quality/); }); test('goods resource keeps only SpecialGoods projections and classifies series', () => { const out = r.goodsResource({ GridFightProjectionConfigRow: [ {ID: 1509, RoleID: 1509, Rarity: 2, MazebuffID: 35610001, UnlockType: 1, ParamList: [{wire: 343597384}]}, {ID: 7, RoleID: 7, UnlockType: 0} ], GridFightSpecialGoodsConfigRow: [ {ID: 401, GroupID: 3, Quality: 1, LowerGoodID: 301, JsonPath: 'Config/Level/GridFight/SpecialGoods/Aha/GridFightAhaGoods401.json', EffectParamList: [{wire: 51539607552}]}, {ID: 101, GroupID: 1, Cost: 24, Quality: 1, JsonPath: 'Config/Level/GridFight/SpecialGoods/Cyrene/GridFightCyreneGoods101.json'} ] }); assert.deepEqual(out.projections, [{id: 1509, role_id: 1509, rarity: 2, mazebuff_id: 35610001, params: [0.08]}]); assert.deepEqual(out.special_goods.map(g => [g.id, g.series, g.cost, g.lower_good_id, g.params]), [[101, 'Cyrene', 24, 0, []], [401, 'Aha', 0, 301, [12]]]); assert.equal(out.unlock_case, 1684); assert.deepEqual(out.grants, []); assert.throws(() => r.goodsResource({ GridFightProjectionConfigRow: [], GridFightSpecialGoodsConfigRow: [{ID: 1, GroupID: 9, JsonPath: 'Config/Other/x.json'}] }), /Unknown SpecialGoods series/); }); test('installed resources agree with the extractor contract', () => { const dir = path.join(ROOT, 'resources/grid_fight'); const elite = JSON.parse(fs.readFileSync(path.join(dir, 'elite_rewards.json'), 'utf8')); const goods = JSON.parse(fs.readFileSync(path.join(dir, 'projection_goods.json'), 'utf8')); assert.equal(elite.node_rules.length, 44); assert.equal(elite.diff_add.length, 8); assert.equal(elite.difficulty.length, 903); for (const rule of elite.node_rules) assert.equal(rule.id, rule.family ? rule.family * 100 + rule.quality : rule.quality); assert.deepEqual(goods.projections.map(p => p.id), [1508, 1509]); assert.equal(goods.special_goods.length, 164); assert.equal(elite.source.dump_sha256, goods.source.dump_sha256); });