Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,61 @@
# Changelog

## v1.12.0

- **The whole economy is retuned to a weeks-long curve.** A daily player now
reaches tiers 0-9 in the first four days, tier 10 around day 18, and the top
of the ladder over the following weeks. Previously the entire 14-tier ladder
fell inside two weeks and a Singularity was available *every single day*.

The rack ladder itself was never the problem - in isolation it was a clean
doubling curve. What broke it was every reward system layered on top, which
together multiplied progression by about 21x.

- **Signal Boost no longer makes the anomaly boost permanent.** It scaled the
boost's *duration* as well as its payout, so at max level a 2-4x global
multiplier lasted longer than the interval between anomalies. Measured boost
uptime was 55% of session time. Signal Boost now scales the payout only, and
anomalies are rarer, more valuable, and give you twice as long to catch one.

- **Legacy Cores plateau, and Singularity is finally worth taking.** Cores
stop buying output past a cap; beyond it they are fuel for the next
Singularity. That plateau is the point - Singularity used to be a strict
downgrade at every scale (it zeroes cores and returned far less than it
destroyed), and was only survivable because cores regrew within a day.
Singularity yield is now linear in cores rather than a square root, and the
Engine upgrade has a longer tail so the shard tree stays a long-term goal.

- **Quantum Bootstrap is x3 per level, not x10.** Maxed alongside Deep Cache it
handed you 11,000,000 credits at every Migrate - enough to buy straight back
into the mid-game, so Migrate had stopped being a reset. Echo Cores now
grants a share of the Migrate gain instead of a flat amount.

- **Incidents are twice as frequent but individually softer, and preparing is
now clearly worth it.** Supplies used to be break-even at best and an
outright loss for two of the three, so the rational play was to ignore the
entire prepaid economy. Drive failures and overheats now hit your *top* rack
tier - a random victim was both unpredictable and usually trivial.

- **Overheating is a real trade-off instead of a cliff.** Venting used to
supply far more cooling than any fleet could generate, so an attentive player
could never overheat and an inattentive one was punished constantly. Venting
is slower now, passive Auto-Vent is much stronger, and the meltdown notice
tells you which rack went dark and why.

- **Live Event ladders scale with your output.** Their FLOPS rungs were fixed
numbers, so every seasonal event's FLOPS ladder cleared in a fraction of a
second. Targets are now expressed in seconds of your own production and
snapshotted when you join.

- **Minigames pay far fewer wafers.** The whole permanent upgrade tree used to
be reachable in about two and a half hours of minigames.

- **Reward magnitudes are now admin-tunable.** The root cause of most of the
above was that rate curves were tunable while payout sizes were hardcoded
constants calibrated for the early game. 21 new tunables cover them.

Existing saves are unaffected in balance terms - no progress is rewritten.

## v1.11.0

- **Things can now go wrong.** Every few hours something breaks: ransomware
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ global leaderboards, and a badge case of achievements that unlock on their own
as you play. A daily login streak sits in the header. See
[Social & Retention](#social--retention) below.

As of v1.12, the economy is retuned to a weeks-long curve: tiers 0-9 in the
first few days, tier 10 as a wall around day 18, and the top of the ladder over
the weeks after. Legacy Cores plateau at a cap, which is what makes Singularity
worth taking; anomaly boosts no longer run permanently; incidents are more
frequent but softer and preparing for them now pays; overheating is a genuine
trade-off; and Live Event ladders scale with your output instead of using fixed
targets. Reward magnitudes that used to be hardcoded are admin-tunable. Existing
saves keep their progress - nothing is rewritten.

## Architecture

- `shared/` - a package used by both server and client (via a `@shared` Vite
Expand Down
10 changes: 5 additions & 5 deletions client/src/RackStack.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ export default function RackStack({ user }) {
lastTickAtRef.current = now;
setState(next);

if (serverState.server.overheated) setModal({ type: 'meltdown' });
if (serverState.server.overheated) setModal({ type: 'meltdown', tierIndex: serverState.server.overheated?.tierIndex });

// v1.11: one-shot outage notices, same lifecycle as `overheated` above.
// Toast, not modal - these are information, not a reward (the v1.10 rule:
Expand Down Expand Up @@ -526,7 +526,7 @@ export default function RackStack({ user }) {
if (stateRes.offlineGain > 1) {
setModal({ type: 'welcome', amount: stateRes.offlineGain });
} else if (initial.server.overheated) {
setModal({ type: 'meltdown' });
setModal({ type: 'meltdown', tierIndex: initial.server.overheated?.tierIndex });
}
// Live Events (v1.4): GET /api/state already carries this player's
// claimable event identity - seed activeEvent from it directly so the
Expand Down Expand Up @@ -566,7 +566,7 @@ export default function RackStack({ user }) {
lastTickAtRef.current = now;
stateRef.current = next;
setState(next);
if (next.server.overheated) setModal({ type: 'meltdown' });
if (next.server.overheated) setModal({ type: 'meltdown', tierIndex: next.server.overheated?.tierIndex });
}, TICK_MS);
return () => clearInterval(iv);
}, [loaded]);
Expand Down Expand Up @@ -1093,8 +1093,8 @@ export default function RackStack({ user }) {
const runForOverclock = { ...state.run, heat: heatPct };

const ctx = goalCtx(state, config.data, now);
const gain = migrateGain(state.run.lifetimeRun, eff.legacyGainMult);
const singularityGain = Math.floor(Math.sqrt(state.meta.legacyCores || 0));
const gain = migrateGain(state.run.lifetimeRun, eff.legacyGainMult, config.data);
const singularityGain = Math.floor((state.meta.legacyCores || 0) * config.data.prestige.shardsPerCore);

// Single source of truth with the tour's auto-start effect above.
const { gridUnlocked, overclockUnlocked, singularityUnlocked, coldStorageUnlocked } = buildTourCtx(state, now);
Expand Down
15 changes: 13 additions & 2 deletions client/src/game/components/modals/MessageModal.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AlertTriangle } from 'lucide-react';
import { TIER_DEFS } from '@shared/gameData.js';
import { amber, violet, danger, textDim, textMain } from '../../theme.js';
import { fmt } from '../../helpers.js';

Expand Down Expand Up @@ -38,14 +39,24 @@ export default function MessageModal({ modal, onClose }) {
<button onClick={onClose} className="w-full rounded-lg py-2 text-sm font-semibold" style={{ background: violet, color: '#0E141B' }}>Nice</button>
</>
);
case 'meltdown':
// The pre-v1.12 copy here described PRE-v1.11 behaviour ("the lane is
// frozen ... no nodes were lost"), which stopped being true when the
// overheat penalty moved to the Racks lane. Name the actual victim.
case 'meltdown': {
const downed = typeof modal.tierIndex === 'number' ? TIER_DEFS[modal.tierIndex] : null;
return (
<>
<h2 className="text-lg font-bold mb-2 flex items-center gap-2" style={{ color: danger }}><AlertTriangle size={18} /> Overheated!</h2>
<p className="text-sm mb-4" style={{ color: textDim }}>Your Overclock Bay hit 100% heat and the lane is frozen for a short cooldown - no nodes were lost. Keep an eye on the heat gauge and vent regularly, or invest in Thermal Regulators / Auto-Vent upgrades to avoid the lockout.</p>
<p className="text-sm mb-4" style={{ color: textDim }}>
{downed
? `Your Overclock Bay hit 100% heat and took your ${downed.name} offline while it cools. Overclocking is what multiplies your racks, so running it hot risks the very thing it amplifies.`
: 'Your Overclock Bay hit 100% heat and the lane is frozen while it cools.'}
{' '}Vent before the gauge fills, or invest in Thermal Regulators / Auto-Vent to raise the fleet you can run unattended.
</p>
<button onClick={onClose} className="w-full rounded-lg py-2 text-sm font-semibold" style={{ background: danger, color: textMain }}>Understood</button>
</>
);
}
case 'singularityDone':
return (
<>
Expand Down
Loading
Loading