Add server-managed balance configuration

This commit is contained in:
Emporex committed 2026-10-11 10:47:13 +02:00
1 parent 67abdf13b0
commit 39ed4c3bf7
12 files changed
+289 -27

No files matched your search

+36 -2
View File
@@ -22,6 +22,28 @@ assert.ok(context.TOWERS[3].bothScale < 1, "Universal towers should trade damage
assert.strictEqual(context.TOWERS[4].damage, 20, "EMP damage should be tuned down to about 20.");
assert.strictEqual(context.TOWERS[4].targetClass, "both", "EMP should cover both air and ground units.");
assert.strictEqual(context.TOWERS[6].targetClass, "air", "The Flak tower must only target air units.");
const balanceStorage = new Map();
let balanceVersion = 0;
const balanceNk = {
storageRead(ops) { return ops.map(op => balanceStorage.get(`${op.collection}:${op.userId}:${op.key}`)).filter(Boolean); },
storageWrite(ops) {
for (const op of ops) {
balanceVersion += 1;
balanceStorage.set(`${op.collection}:${op.userId}:${op.key}`, { ...op, version: String(balanceVersion) });
}
}
};
assert.throws(() => context.rpcGetGameBalance({}, {}, balanceNk, "{}"), /authentication required/);
const adminBalance = JSON.parse(context.rpcGetGameBalance({ userId: "pilot-b" }, {}, balanceNk, "{}"));
assert.strictEqual(adminBalance.config.towers[0].damage, 22);
const editedBalance = JSON.parse(JSON.stringify(adminBalance.config));
editedBalance.towers[0].damage = 31;
editedBalance.enemies[0].hp = 90;
assert.throws(() => context.rpcSetGameBalance({ userId: "pilot-b" }, {}, balanceNk, JSON.stringify({ config: editedBalance })), /server-to-server/);
assert.strictEqual(JSON.parse(context.rpcSetGameBalance({}, {}, balanceNk, JSON.stringify({ config: editedBalance }))).accepted, true);
assert.strictEqual(JSON.parse(context.rpcGetGameBalance({ userId: "pilot-b" }, {}, balanceNk, "{}")).config.towers[0].damage, 31);
assert.strictEqual(context.matchInit({}, {}, balanceNk, { difficulty: 1 }).state.balance.enemies[0].hp, 90);
assert.throws(() => context.rpcSetGameBalance({}, {}, balanceNk, JSON.stringify({ config: { towers: [], enemies: [] } })), /invalid balance schema/);
const hostId = "11111111-1111-1111-1111-111111111111";
const friendId = "22222222-2222-2222-2222-222222222222";
const sentInvites = [];
@@ -366,8 +388,11 @@ context.Math.random = () => 0;
context.spawnEnemy(bossState);
context.Math.random = originalRandom;
assert.ok(bossState.enemies[0].shield, "The first boss shield test needs a shielded ship.");
assert.strictEqual(bossState.enemies[0].max_shield_hp, bossState.enemies[0].max_hp * 0.275,
"Wave-five mothership shields must be half their former strength.");
assert.ok(Math.abs(bossState.enemies[0].max_hp -
context.ENEMIES[5].hp * (1 + 4 * 0.20 + 2 * 0.09) * 3.25 * context.DIFFICULTIES[1].hp * 0.5,
) < 0.0001, "Wave-five mothership hull should be reduced by 50%.");
assert.ok(Math.abs(bossState.enemies[0].max_shield_hp - bossState.enemies[0].max_hp * 0.55) < 0.0001,
"The wave-five shield remains at its already-halved absolute strength while hull is reduced.");
const laterBossState = context.initialState({ difficulty: 1 });
laterBossState.wave = 10;
laterBossState.waveSchedule = [{ type: 8, boss: true }];
@@ -377,6 +402,15 @@ context.Math.random = originalRandom;
assert.strictEqual(laterBossState.enemies[0].max_shield_hp, laterBossState.enemies[0].max_hp * 0.55,
"Later bosses retain their original shield balance.");
const flakAimState = {
towers: [{ id: 1, type: 6, x: 0, y: 0, owner: 0, level: 1, cooldown: 1, angle: 0 }],
enemies: [{ id: 1, type: 0, x: 100, y: 0, hp: 100, shield: false }],
shots: []
};
context.updateTowers(flakAimState, 0.1);
assert.ok(Math.abs(flakAimState.towers[0].angle - Math.PI) < 0.0001,
"Flak visualization must include the 180-degree sprite orientation correction.");
const diagnosticStore = new Map();
const diagnosticNk = {
sha256Hash(value) { return crypto.createHash("sha256").update(value).digest("hex"); },