95 lines
2.7 KiB
JavaScript
95 lines
2.7 KiB
JavaScript
// Effects: the single vocabulary used by upgrades, research, legacy perks,
|
|
// achievements, chips and temporary buffs. To add a new effect type: register
|
|
// it here, add its `effect.<type>` text to the core locale files, then use it
|
|
// in any data file.
|
|
|
|
export function newModifiers() {
|
|
return {
|
|
click: 1,
|
|
generators: {},
|
|
global: 1,
|
|
demand: 1,
|
|
value: 1,
|
|
materialEfficiency: 1,
|
|
batchDiscount: 1,
|
|
batchSize: 1,
|
|
autoBuyMaterial: false,
|
|
dividend: 1,
|
|
reliability: 0,
|
|
offline: 0,
|
|
contract: 1,
|
|
rp: 1,
|
|
generatorCost: 1,
|
|
startFunds: 0,
|
|
priceAdvisor: false,
|
|
materialPrice: 1,
|
|
legacyGain: 1,
|
|
};
|
|
}
|
|
|
|
// `times` lets a repeatable effect (a perk level, N achievements) stack.
|
|
function mult(key) {
|
|
return (m, e, times) => {
|
|
m[key] *= e.value ** times;
|
|
};
|
|
}
|
|
|
|
function add(key) {
|
|
return (m, e, times) => {
|
|
m[key] += e.value * times;
|
|
};
|
|
}
|
|
|
|
function flag(key) {
|
|
return (m) => {
|
|
m[key] = true;
|
|
};
|
|
}
|
|
|
|
const APPLY = {
|
|
click_mult: mult('click'),
|
|
generator_mult: (m, e, times) => {
|
|
m.generators[e.target] = (m.generators[e.target] ?? 1) * e.value ** times;
|
|
},
|
|
global_mult: mult('global'),
|
|
demand_mult: mult('demand'),
|
|
value_mult: mult('value'),
|
|
material_efficiency: mult('materialEfficiency'),
|
|
batch_discount: mult('batchDiscount'),
|
|
batch_size_mult: mult('batchSize'),
|
|
auto_buy_material: flag('autoBuyMaterial'),
|
|
dividend_mult: mult('dividend'),
|
|
reliability_add: add('reliability'),
|
|
offline_add: add('offline'),
|
|
contract_mult: mult('contract'),
|
|
rp_mult: mult('rp'),
|
|
generator_cost_mult: mult('generatorCost'),
|
|
start_funds: add('startFunds'),
|
|
price_advisor: flag('priceAdvisor'),
|
|
material_price_mult: mult('materialPrice'),
|
|
legacy_gain_mult: mult('legacyGain'),
|
|
};
|
|
|
|
export const EFFECT_TYPES = Object.keys(APPLY);
|
|
|
|
// Endless upgrades stack without limit, so keep every result finite and sensible.
|
|
const CAP = 1e100; // low enough that products of several multipliers stay finite; real play never gets close
|
|
const FLOORS = { generatorCost: 0.05, batchDiscount: 0.001 };
|
|
|
|
function finalize(m) {
|
|
const keep = (value) => (Number.isFinite(value) ? Math.min(CAP, value) : CAP);
|
|
for (const key of Object.keys(m)) if (typeof m[key] === 'number') m[key] = keep(m[key]);
|
|
for (const id of Object.keys(m.generators)) m.generators[id] = keep(m.generators[id]);
|
|
for (const [key, floor] of Object.entries(FLOORS)) m[key] = Math.max(floor, m[key]);
|
|
return m;
|
|
}
|
|
|
|
/** Fold a list of `{ effect, times }` entries into one set of multipliers. */
|
|
export function foldEffects(entries) {
|
|
const m = newModifiers();
|
|
for (const { effect, times = 1 } of entries) {
|
|
if (effect && times > 0) APPLY[effect.type]?.(m, effect, times);
|
|
}
|
|
return finalize(m);
|
|
}
|