Deriving help text point values from the game engine

Hardcoded point strings in UI translation dictionaries drifted when fruit values changed. Deriving help copy directly from EDIBLE_POINTS enforced a single source of truth.

When fruit tier scoring rules were originally introduced during five-new-combos-and-fruit-tiers, point values were stored in the engine’s EDIBLE_POINTS map. However, the game’s help screen and edible tooltips described these values using hardcoded string literals inside localized dictionary files. When scoring values were balanced, the UI help text remained fixed to stale numbers, creating quiet discrepancies between what the help page promised and what the engine actually awarded during gameplay.

Extracting dynamic fruit facts#

To eliminate drift between engine constants and UI presentation, static point descriptors were removed from dictionary files. A new fruitFacts.ts module was introduced in the help route to compute fruit values dynamically directly from EDIBLE_POINTS.

export function getFruitFact(type: EdibleType, locale: Locale): string {
  const points = EDIBLE_POINTS[type];
  const template = strings.fruitPointTemplate[locale];
  return template.replace('{points}', points.toString());
}

Instead of storing full sentences per fruit, dictionary files now supply a single parameterized format string. Replacing hardcoded values with dynamic interpolation ensures that any future adjustment to EDIBLE_POINTS updates all help copy across both languages automatically.

Simplifying the dictionary schema#

Removing duplicate point numbers reduced translation dictionary overhead across all supported languages. The dictionary schema dropped multiple per-fruit point descriptors in favor of a shared template string.

Deriving presentation text from engine constants prevents documentation drift without duplicating scoring formulas across translation dictionaries.

Domain single source of truth

This reduction simplified string maintenance while ensuring that adding a new edible tier requires updating only the engine config and icon asset.

Locking derived copy with tests#

To prevent regressions where dynamic formatting might fail or return unpopulated placeholders, a new test suite in fruitFacts.test.ts validates output for every registered edible tier.

it('formats point values correctly for every edible type', () => {
  for (const type of EDIBLE_TYPES) {
    const fact = getFruitFact(type, 'en');
    expect(fact).toContain(EDIBLE_POINTS[type].toString());
    expect(fact).not.toContain('{points}');
  }
});

With fruitFacts.ts in place, all help components and edible tooltips render derived point values, ensuring complete consistency across the game’s documentation and scoring engine.