Files
vending-machine-game/tests/scoring.test.js
T
HamedandClaude Opus 5.5 bced4dc6f6 feat: step-based missions around park machines with 3D objective arrow
Phase 5 of turning the game into the company landing page.

- Replace purchase-only missions with a data-driven list of short step
  chains (goto, locate on map, inspect, order, buy, buy at N places)
  in src/game/missions, with pure progress logic on the game state.
- Six missions, most about machines installed in Park Mellat; add two
  sites there (lake and sports fields) and record the product model
  installed at every site.
- Inspecting a machine opens a machine card with the installed model,
  specs, price, an order request and sales contact.
- The objective chip shows the current step; the missions sheet lists
  missions with the current one's steps ticked; a brand-coloured arrow
  hovers over the target machine.
- Rewards and banners per finished mission, the next step is spoken.
- Tests for mission data, step logic, text and the machine card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:19:25 +03:00

34 lines
1.5 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { awardsFor, rankFor, POINTS, RANKS } from '../src/game/economy/scoring.js';
import { createState, purchase } from '../src/game/economy/gameState.js';
import { machineById } from '../src/constants/locations.js';
const total = (awards) => awards.reduce((s, a) => s + a.points, 0);
test('Discovery, combo and all-category bonuses are paid once', () => {
const state = createState(),
park = machineById('mellat-park');
const buy = (machine, product) => {
const before = state.purchases.slice();
return awardsFor(before, purchase(state, machine, product));
};
assert.equal(total(buy(park, 'water')), POINTS.purchase + POINTS.discovery);
assert.equal(total(buy(park, 'juice')), POINTS.purchase, 'same type: no combo');
assert.equal(total(buy(park, 'cake')), POINTS.purchase + POINTS.combo);
assert.equal(total(buy(park, 'water')), POINTS.purchase, 'combo only once');
buy(machineById('factory'), 'water');
buy(machineById('school-rahil'), 'water');
buy(machineById('ferdowsi-university'), 'water');
buy(machineById('azadi-metro'), 'water');
state.minutes = 11 * 60;
const last = buy(machineById('mashhad-mall'), 'water');
assert.ok(last.some((a) => a.points === POINTS.allCategories));
});
test('Ranks advance with experience', () => {
assert.equal(rankFor(0).name, RANKS[0].name);
assert.equal(rankFor(RANKS[1].xp).index, 1);
assert.equal(rankFor(1e6).progress, 1);
});