104 lines
5.1 KiB
JavaScript
104 lines
5.1 KiB
JavaScript
// Run: node --test tools/test-level-reward.cjs
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const { loadMembers, resolveFile } = require('./new-player-ab-test-support.cjs');
|
|
const read = file => JSON.parse(fs.readFileSync(resolveFile(file), 'utf8'));
|
|
const configFile = 'assets/Script/module/Config/GameConfig.ts';
|
|
|
|
test('win display uses the awarded amount with shared digits and stays centered', () => {
|
|
const rendered = [], symbol = { active: true }, background = { x: 55 };
|
|
const root = { getChildByName: name => name === 'New Sprite' ? symbol : background };
|
|
const cc = { isValid: node => !!node };
|
|
const Manager = loadMembers('assets/Script/SceneManager.ts', ['updateWinCoin'], {
|
|
cc, console: { log() {} },
|
|
NumberToImage: { rewardTextToImages: (text, node, height) => rendered.push({ text, node, height }) },
|
|
});
|
|
const manager = new Manager();
|
|
manager.winCoin = { parent: root, x: 0, active: false };
|
|
manager.updateWinCoinIconState = () => {};
|
|
for (const amount of [40, 120, 480]) {
|
|
manager.updateWinCoin(amount);
|
|
assert.deepEqual(rendered.at(-1), { text: String(amount), node: manager.winCoin, height: 56 });
|
|
assert.equal(manager.winCoin.active, true);
|
|
assert.equal(manager.winCoin.x, background.x);
|
|
assert.equal(symbol.active, false);
|
|
}
|
|
manager.updateWinCoin(0);
|
|
assert.equal(manager.winCoin.active, false);
|
|
assert.equal(rendered.length, 3);
|
|
});
|
|
|
|
function fixture() {
|
|
const credits = [], events = [], callbacks = [];
|
|
const cc = { resources: { load: (path, done) => { assert.equal(path, 'Json/PASS_RATE'); callbacks.push(done); } }, fx: {} };
|
|
const Config = loadMembers(configFile, ['defaultPassRate', 'PASS_RATE', 'passRateReady', 'passRateLoading',
|
|
'ensurePassRateLoaded', 'getLevelPassRate', 'getLevelRewardMultiplier', 'getLoadedLevelNumber', 'applyLevelData'],
|
|
{ cc, console: { log() {} }, LEVEL_TIME_BONUS: {} });
|
|
Config.defaultPassRate = read('assets/resources/Json/PASS_RATE.json');
|
|
Config.GM_INFO = { level: 0, doubleCoin: 1, rewardAdCoin: 1 };
|
|
cc.fx = { GameConfig: Config, GameTool: {
|
|
changeCoin: amount => credits.push(amount), shushu_Track: (name, data) => events.push({ name, ...data }),
|
|
} };
|
|
const Map = loadMembers('assets/Script/Map.ts', ['initLevelReward', 'grantWinCoinReward'], { cc });
|
|
return { Config, map: new Map(), credits, events, callbacks };
|
|
}
|
|
|
|
test('every configured hard level pays 120; ordinary levels pay 40; both extra multipliers stack', () => {
|
|
const { Config, map, credits, events } = fixture();
|
|
for (const level of [1, 20, 22, ...Config.PASS_RATE.map(row => row.level)]) {
|
|
for (const doubleCoin of [1, 2]) for (const rewardAdCoin of [1, 2]) {
|
|
Config.loadedLevelNumber = level;
|
|
Object.assign(Config.GM_INFO, { doubleCoin, rewardAdCoin });
|
|
map.initLevelReward(); map.gameWin = true; map.grantWinCoinReward();
|
|
const expected = ([1, 20, 22].includes(level) ? 40 : 120) * doubleCoin * rewardAdCoin;
|
|
assert.equal(map.winRewardCoin, expected, `level ${level}`);
|
|
assert.equal(credits.at(-1), expected);
|
|
assert.equal(events.at(-1).num, expected);
|
|
}
|
|
}
|
|
});
|
|
|
|
test('loaded file number wins over stale JSON id, progress and later endless/help level changes', () => {
|
|
const { Config, map, credits } = fixture();
|
|
for (const level of [21, 22, 21]) {
|
|
const data = { LEVEL_INFO: [{ id: '1' }], BLOCK_INFO: [[]], WALL_INFO: [[]] };
|
|
Config.applyLevelData(data, false, 0, level);
|
|
map.initLevelReward();
|
|
assert.equal(map.enteredLevelNumber, level);
|
|
Config.GM_INFO.level = 999;
|
|
Config.GM_INFO.randomLevel = 22;
|
|
Config.GM_INFO.otherLevel = 22;
|
|
Config.loadedLevelNumber = 22;
|
|
map.gameWin = true; map.grantWinCoinReward();
|
|
assert.equal(credits.at(-1), level === 21 ? 120 : 40);
|
|
}
|
|
});
|
|
|
|
test('failed attempts pay nothing; repeated wins and changed bonuses cannot pay a second time', () => {
|
|
const { Config, map, credits, events } = fixture();
|
|
Config.loadedLevelNumber = 21; map.initLevelReward();
|
|
map.gameWin = false; map.grantWinCoinReward();
|
|
assert.equal(credits.length, 0);
|
|
map.gameWin = true; map.grantWinCoinReward();
|
|
Config.GM_INFO.doubleCoin = 2; map.grantWinCoinReward();
|
|
assert.deepEqual(credits, [120]);
|
|
assert.equal(events.length, 1);
|
|
});
|
|
|
|
test('difficulty load is shared, retries failures and retains a successful empty table', async () => {
|
|
const { Config, callbacks } = fixture();
|
|
const first = Config.ensurePassRateLoaded();
|
|
assert.equal(Config.ensurePassRateLoaded(), first);
|
|
assert.equal(callbacks.length, 1);
|
|
callbacks[0](new Error('load failed'));
|
|
await assert.rejects(first, /load failed/);
|
|
const retry = Config.ensurePassRateLoaded();
|
|
assert.equal(callbacks.length, 2);
|
|
callbacks[1](null, { json: [] });
|
|
await retry;
|
|
await Config.ensurePassRateLoaded();
|
|
assert.equal(callbacks.length, 2);
|
|
assert.equal(Config.getLevelRewardMultiplier(21), 1);
|
|
});
|