feat: New features (research, invest, gambling, new game+, trophies)
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
// The gamble (a "quantum computer" in the first theme): chips are a second
|
||||
// currency, hard to buy (the price rises with every chip owned) and hard to
|
||||
// grow. Stake chips on a cycle: win and the stake doubles, hit a jackpot and it
|
||||
// is multiplied, lose it, or crash and lose more than you bet. Reliability
|
||||
// upgrades (paid in funds) tilt the odds. Chips give a diminishing demand bonus.
|
||||
|
||||
import { clamp } from './formulas.js';
|
||||
|
||||
const MAX_EXPONENT = 200;
|
||||
|
||||
export function chipCost(state, ctx) {
|
||||
const g = ctx.rules.gamble;
|
||||
return Math.ceil(g.baseChipCost * g.chipCostGrowth ** Math.min(state.chips, MAX_EXPONENT));
|
||||
}
|
||||
|
||||
export function reliabilityCost(state, ctx) {
|
||||
const r = ctx.rules.gamble.reliability;
|
||||
return Math.ceil(r.baseCost * r.costGrowth ** state.reliabilityLevel);
|
||||
}
|
||||
|
||||
/** Probabilities of each outcome of one cycle. They always sum to 1. */
|
||||
export function odds(state, ctx, mods) {
|
||||
const g = ctx.rules.gamble;
|
||||
const crash = g.crashChance;
|
||||
const jackpot = g.jackpotChance;
|
||||
const reliability = g.baseWin + state.reliabilityLevel * g.reliability.perLevel + mods.reliability;
|
||||
const win = clamp(reliability, 0.05, g.maxWin - crash - jackpot);
|
||||
return { crash, jackpot, win, lose: 1 - crash - jackpot - win };
|
||||
}
|
||||
|
||||
export function buyChip(state, ctx) {
|
||||
const cost = chipCost(state, ctx);
|
||||
if (state.funds < cost || state.chips >= ctx.rules.gamble.maxChips) return false;
|
||||
state.funds -= cost;
|
||||
state.chips += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function buyReliability(state, ctx) {
|
||||
if (state.reliabilityLevel >= ctx.rules.gamble.reliability.maxLevel) return false;
|
||||
const cost = reliabilityCost(state, ctx);
|
||||
if (state.funds < cost) return false;
|
||||
state.funds -= cost;
|
||||
state.reliabilityLevel += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stake `stake` chips on one cycle. Returns { outcome, stake, delta } or null
|
||||
* when it cannot be played (no chips, nothing staked, still cooling down).
|
||||
*/
|
||||
export function gamble(state, ctx, stake, mods, rng = Math.random) {
|
||||
const g = ctx.rules.gamble;
|
||||
const bet = Math.min(Math.floor(stake), state.chips);
|
||||
if (!(bet >= 1) || state.gambleCooldown > 0) return null;
|
||||
|
||||
const p = odds(state, ctx, mods);
|
||||
const roll = rng();
|
||||
let outcome = 'lose';
|
||||
let delta = -bet;
|
||||
if (roll < p.crash) {
|
||||
outcome = 'crash';
|
||||
delta = -Math.min(state.chips, Math.ceil(bet * g.crashMultiplier));
|
||||
} else if (roll < p.crash + p.jackpot) {
|
||||
outcome = 'jackpot';
|
||||
delta = bet * g.jackpotMultiplier;
|
||||
} else if (roll < p.crash + p.jackpot + p.win) {
|
||||
outcome = 'win';
|
||||
delta = bet;
|
||||
}
|
||||
|
||||
state.chips = clamp(state.chips + delta, 0, g.maxChips);
|
||||
state.gambleCooldown = g.cooldownSeconds;
|
||||
if (delta > 0) state.stats.gambleWins += 1;
|
||||
else state.stats.gambleLosses += 1;
|
||||
return { outcome, stake: bet, delta };
|
||||
}
|
||||
Reference in New Issue
Block a user