import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; const read = name => JSON.parse(fs.readFileSync(new URL('../../resources/grid_fight/' + name, import.meta.url))); const special = read('special-units.raw.json'); const mechanics = read('mechanics-4654.raw.json'); test('CW MECH 4.6.54 decoded Aha family excludes the obsolete three-cost form', () => { const rows = special.GridFightRoleConfigRow.filter(r => r.AvatarID === 1511 && r.SeasonID === 2); assert.deepEqual(rows.map(r => [r.ID, r.Rarity]), [[151112, 4], [151122, 5], [151132, 5]]); const noStars = mechanics.ConstValueCommonRow.find(r => r.ConstValueName === 'GridFight_Aha_No_Star_Role_IDList'); assert.deepEqual(noStars.Value.value.map(r => r.value), [151112, 151122]); assert.equal(mechanics.ConstValueCommonRow.find(r => r.ConstValueName === 'GridFight_Aha_Level_SavedValueKey').Value.value, 'GP_Avatar_S2_Aha_00'); }); test('CW MECH restaurant menus retain native weights and signature component pairs', () => { const menus = mechanics.GridFightTraitEquipTemplateConfigRow.filter(r => r.TraitID === 101202); assert.equal(menus.length, 20); assert.equal(new Set(menus.map(r => r.TemplateID)).size, 20); for (const menu of menus) { assert.ok([25, 50, 100].includes(menu.Weight)); assert.equal(menu.EquipList.length, 2); for (const id of menu.EquipList) assert.ok(special.GridFightEquipConfigRow.some(e => e.ID === id)); } assert.ok(special.GridFightRoleConfigRow.find(r => r.ID === 141502).TraitList.includes(101202)); }); test('CW MECH Twin Dragons IDs come from effect 3001022 rather than avatar-ID arithmetic', () => { const pair = special.GridFightTraitEffectLayerParamConfigRow.find(r => r.ID === 3001022 && r.Layer === 1); assert.deepEqual(pair.EffectParamList.map(p => p.wire / 2 ** 34), [121302, 141402]); for (const id of [121302, 141402]) assert.ok(special.GridFightRoleConfigRow.find(r => r.ID === id).TraitList.includes(300102)); }); test('CW MECH additional tables retain complete client-asset round-trip proofs', () => { const proof = read('mechanics-4654-provenance.json'); assert.equal(proof.game_assembly_sha256, '4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6'); assert.ok(proof.tables.length >= 7); for (const p of proof.tables) { assert.equal(p.round_trip, true); assert.match(p.asset_sha256, /^[a-f0-9]{64}$/); } }); test('CW MECH takeover chip contains stat properties, not a decoded budget or payout specification', () => { const chip = special.GridFightEquipConfigRow.find(r => r.ID === 353601); assert.equal(chip.ParamList.length, 6); assert.equal(chip.GeneralPropertyList.length, 6); assert.ok(chip.ParamList.every(p => Math.abs(p.wire / 2 ** 34 - 0.99) < 1e-8)); assert.equal(chip.JsonPath, 'Config/Level/GridFight/Equip/GridFightEquip353601.json'); }); test('CW MECH future-node weakening preserves native reduction tiers independently of Trotter data', () => { for (const [id, reduction] of [[353303, 0.08], [353403, 0.12], [353503, 0.16]]) { const chip = special.GridFightEquipConfigRow.find(r => r.ID === id); for (const p of chip.ParamList.slice(1)) assert.ok(Math.abs(p.wire / 2 ** 34 - reduction) < 1e-8); } assert.equal(special.GridFightEquipConfigRow.find(r => r.ID === 353405).ParamList.length, 1); assert.equal(special.GridFightEquipConfigRow.find(r => r.ID === 353505).ParamList.length, 2); });