64 lines
4.0 KiB
JavaScript
64 lines
4.0 KiB
JavaScript
// Master of Vega — human-readable descriptions for `tech.effects` values.
|
||
// Headless, no Phaser: kept separate from VegaTurnReport.js so any other
|
||
// screen (a future tech-tree view, say) can reuse the same wording without
|
||
// pulling in turn-report-specific code.
|
||
//
|
||
// Every formatter is hand-matched to how the effect is actually consumed
|
||
// elsewhere in the engine (VegaCombat.js/VegaLogic.js/VegaShips.js) — not a
|
||
// generic key/value dump. A few effects (cloaked, scanRange, singularity)
|
||
// are currently inert stats with no downstream mechanic wired up yet; their
|
||
// wording stays modest/flavor rather than promising a numeric benefit that
|
||
// doesn't exist in the sim.
|
||
|
||
const pct = (mult) => `${Math.round(Math.abs(mult - 1) * 100)}%`;
|
||
|
||
function describeWeapon(w) {
|
||
const perRound = w.shots > 1 ? `, ${w.shots} shots per round` : '';
|
||
const pierce = w.shieldPierce
|
||
? `, pierces ${w.shieldPierce} point${w.shieldPierce === 1 ? '' : 's'} of enemy shields` : '';
|
||
const cracker = w.planetCracker ? ' — powerful enough to crack a planet apart' : '';
|
||
return `New ${w.kind} weapon available: ${w.name}, ${w.min}-${w.max} damage per shot${perRound}${pierce}${cracker}.`;
|
||
}
|
||
|
||
function hostilityWorlds(rules, tier) {
|
||
const names = rules.planetTypes
|
||
.filter((t) => t.colonizable && t.hostility === tier)
|
||
.map((t) => t.name);
|
||
return names.length ? `${names.join('/')}-class` : `hostility ${tier}`;
|
||
}
|
||
|
||
const FORMATTERS = {
|
||
armor: (rules, v) => `Hull armor upgraded to ${v.name} plating — hull hit points ×${v.hpMult} (+${pct(v.hpMult)}).`,
|
||
cloaked: () => 'Ships are fitted with a stealth field, cloaking them from enemy sensors.',
|
||
colonizeHostility: (rules, v) => `Colonists can now settle ${hostilityWorlds(rules, v)} worlds.`,
|
||
counterEspionage: (rules, v) => `+${v} counter-espionage — makes it harder for enemy agents to steal your technology.`,
|
||
engine: (rules, v) => `Engines upgraded to ${v.name} Drive (speed ${v.speed}).`,
|
||
espionage: (rules, v) => `+${v} espionage — improves your odds of stealing enemy technology.`,
|
||
factoryCostMult: (rules, v) => `Factories cost ${pct(v)} less to build.`,
|
||
fuelRange: (rules, v) => `Fuel range extended to ${v} parsecs — fleets can be ordered further from friendly colonies and starbases.`,
|
||
groundAttack: (rules, v) => `+${v} ground attack — improves the odds of a successful invasion.`,
|
||
groundDefense: (rules, v) => `+${v} ground defense — colonies field more defenders when invaded.`,
|
||
initiative: (rules, v) => `+${v} initiative — fleets choose their engagement range before slower opponents each combat round.`,
|
||
maxPopBonus: (rules, v) => `+${v} maximum population per colony.`,
|
||
planetaryShield: (rules, v) => (
|
||
`+${v} planetary shield — cuts population lost to bombardment by about ${Math.round((1 - 1 / (1 + v * 0.15)) * 100)}%.`
|
||
),
|
||
redirectInFlight: () => 'Fleets already in transit can be redirected to a new destination.',
|
||
refitCostMult: (rules, v) => `Auto-refit costs reduced by ${pct(v)}.`,
|
||
repairPerRound: (rules, v) => `Ships self-repair ${Math.round(v * 100)}% of max hull every combat round.`,
|
||
researchMult: (rules, v) => `Research output increased by ${pct(v)} empire-wide.`,
|
||
scanRange: (rules, v) => `+${v} scanner range for detecting distant fleets and systems.`,
|
||
shield: (rules, v) => `Deflector shields absorb ${v} point${v === 1 ? '' : 's'} of damage from every incoming hit, on ships and planetary defenses alike.`,
|
||
singularity: () => "A breakthrough in exotic physics — the foundation for the galaxy's ultimate weapon.",
|
||
targeting: (rules, v) => `Combat accuracy increased by ${Math.round(v * 6)}% (better targeting computers).`,
|
||
wasteMult: (rules, v) => `Industrial waste reduced by ${pct(v)}.`,
|
||
weapon: (rules, v) => describeWeapon(v),
|
||
};
|
||
|
||
/** Turns a tech's `effects` object into an array of full sentences, one per effect. */
|
||
export function describeTechEffects(rules, effects) {
|
||
return Object.entries(effects ?? {})
|
||
.map(([key, value]) => FORMATTERS[key]?.(rules, value))
|
||
.filter(Boolean);
|
||
}
|