Skip to content

feat: gameplay changes — cost scaling, hacks prestige gate, endgame surge#20

Merged
Fralleee merged 9 commits into
mainfrom
feat/gameplay-changes
Apr 17, 2026
Merged

feat: gameplay changes — cost scaling, hacks prestige gate, endgame surge#20
Fralleee merged 9 commits into
mainfrom
feat/gameplay-changes

Conversation

@Fralleee
Copy link
Copy Markdown
Owner

Summary

Three gameplay changes to extend progression and make the endgame interesting:

  1. Building cost multiplier 1.15 → 1.30 — ~2x longer progression (intern: 15→20→25→33)
  2. Hacks behind prestige — "Hacker Mindset" upgrade at 5,000 rep gates all hacks
  3. Escalating Surge — when 9+ buildings mastered, production multiplier grows every 30s (2x→3x→4x...), buffs spawn faster with doubled duration

Changes

Area What
buildings.ts costMultiplier 1.15 → 1.30 for all 12
prestige.ts New "Hacker Mindset" upgrade at 5K rep
StatsPanel/MobileBottomNav Gate hacks behind prestige upgrade
gameConfig.ts Surge config (threshold, start multiplier, interval)
types/game.ts Add surgeStartedAt to GameState
gameStore.ts Manage surge state in tick
production.ts Apply surge multiplier
selectors.ts Add surge selectors
BuffSpawn.tsx Double spawn rate + buff duration during surge
TopBar.tsx Surge indicator (⚡ SURGE Xx)
HelpDrawer.tsx Updated: cost multiplier, hacks requirement, new Endgame Surge section

Test plan

  • All 84 tests pass
  • Building costs scale at 1.3x
  • Hacks hidden until Hacker Mindset purchased
  • Surge activates at 9 mastered buildings, multiplier grows
  • Help drawer accurate

🤖 Generated with Claude Code

…urge

Three gameplay changes:

1. Building cost multiplier 1.15 → 1.30 for all 12 buildings
   Makes progression ~2x longer (intern: 15→20→25→33)

2. Hacks require "Hacker Mindset" prestige upgrade (5,000 rep)
   Removes early-game power spike, makes hacks a mid-game reward

3. Escalating Surge when 9+ buildings mastered
   - Production multiplier starts at 2x, +1x every 30 seconds
   - Buffs spawn 2x faster with doubled duration
   - Surge indicator in TopBar shows current multiplier
   - Makes the final push for last 3 buildings feel like a crescendo

Also updates Help drawer with all mechanic changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
code-clicker Ready Ready Preview, Comment Apr 17, 2026 1:01pm

The refactor button was only in the desktop TD section (hidden on
mobile). Now the mobile compact TD indicator includes a small
Refactor button that shows a countdown timer during refactoring.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

This comment was marked as resolved.

- Gate activateHack behind hack_access prestige upgrade
- Clamp surge elapsed to >= 0 (handles clock backwards)
- Reset surgeStartedAt to now on load (prevents offline surge growth)
- Add rescheduleTrigger to BuffSpawn for surge state changes
- Add 6 surge selector tests + 2 surge tick tests + hack gate test
- Update hack test to require hack_access
- Remove stale comment in calculations test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

This comment was marked as resolved.

The card was computing TD from raw baseProduction * techDebtRatio *
buildingMult, ignoring purchased TD reduction upgrades. Now applies
computeTdReduction() so the displayed rate matches the actual net
TD rate (e.g. "Notebook Best Practices" -40% is reflected).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
showHacks already includes !hideHacks in its computation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

This comment was marked as resolved.

Export getPurchasedSet from selectors and use it in BuildingCard
instead of creating a new Set(purchasedUpgrades) on every render.
The memoized version caches by array reference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

This comment was marked as resolved.

Cleaner buildings (Senior Dev, DevOps, etc.) now show the boosted
cleanup rate in the card, matching the engine's computeCleanerBonus.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

This comment was marked as resolved.

Change truthy check to != null so a hypothetical timestamp of 0
isn't incorrectly treated as null.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

This comment was marked as resolved.

- Rename "Internal helpers" to "TD modifier helpers" since functions
  are now exported
- Restore TD threshold requirement text in Hacks help section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/store/gameStore.ts
// Manage surge state
const surgeActive = selectIsSurgeActive(state);
let surgeStartedAt = state.surgeStartedAt;
if (surgeActive && !surgeStartedAt) {
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surge activation uses if (surgeActive && !surgeStartedAt) which treats any falsy number (e.g. 0) as “not started”. Since surgeStartedAt is number | null, use a nullish check (surgeStartedAt == null) for correctness/consistency with the load path.

Suggested change
if (surgeActive && !surgeStartedAt) {
if (surgeActive && surgeStartedAt == null) {

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping as-is: surgeStartedAt is always either Date.now() (a large positive number) or null. It is never 0 — there is no code path that sets it to 0.

Comment thread src/engine/production.ts

// Apply surge multiplier if active
let surgeMultiplier = 1;
if (state.surgeStartedAt) {
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

computeAllProduction gates surge with if (state.surgeStartedAt). Since surgeStartedAt is number | null, a valid (but falsy) timestamp like 0 would incorrectly disable surge. Prefer state.surgeStartedAt != null (and mirror the same nullish check in selectors/tick) for consistency.

Suggested change
if (state.surgeStartedAt) {
if (state.surgeStartedAt != null) {

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping as-is: same reasoning — surgeStartedAt is set via Date.now() or null. The value 0 is not a valid state.

Comment on lines +27 to +33
getInterval: () => {
const surgeActive = selectIsSurgeActive(useGameStore.getState());
const divisor = surgeActive ? 2 : 1;
return {
min: GAME_CONFIG.buffs.minSpawnIntervalMs / divisor,
max: GAME_CONFIG.buffs.maxSpawnIntervalMs / divisor,
};
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getInterval uses selectIsSurgeActive(...) (mastery-threshold check) to speed up buff spawns. Because selectIsSurgeActive can be true before surgeStartedAt is set (surge production hasn’t started yet), buff spawns can speed up slightly earlier than the actual surge. Consider keying this off useGameStore.getState().surgeStartedAt != null (or a dedicated “surge active” selector) so all surge effects start at the same moment.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping as-is: the one-tick gap between selectIsSurgeActive becoming true and surgeStartedAt being set is 50ms — imperceptible for buff spawn timing.

if (result.productionMultiplier || result.clickMultiplier) {
let duration = result.duration ?? 30;
if (state.prestige.prestigeUpgrades.includes("buff_mastery")) duration *= 2;
if (selectIsSurgeActive(state)) duration *= 2;
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Buff duration doubling is currently based on selectIsSurgeActive(state) (mastery threshold), which can become true before the surge has actually started (surgeStartedAt is set in the next tick). To keep behavior consistent with the production surge, consider checking state.surgeStartedAt != null (or a dedicated “surge active” selector) here instead.

Suggested change
if (selectIsSurgeActive(state)) duration *= 2;
if (state.surgeStartedAt != null) duration *= 2;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping as-is: same as above — one-tick (50ms) delay between mastery threshold and surge start is imperceptible for buff duration.

@Fralleee Fralleee merged commit e876aaf into main Apr 17, 2026
7 checks passed
@Fralleee Fralleee deleted the feat/gameplay-changes branch April 17, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants