# Prestige System - Technical Specification

## Document Status
1. Version: 1.0
2. Date: 2026-03-21
3. Scope: Add a configurable prestige reset loop with editor-authored curve math and permanent run multipliers.

## Problem Statement
The prototype currently has growth, buffs, and unlock goals, but no reset loop that converts late-run progress into long-term power.
Without prestige, the economy has no designed "ladder climb" cycle and balancing eventually relies only on direct cost/production tuning.

## Design Goals
1. Support a prestige reset that grants a permanent currency based on player progress.
2. Keep prestige math data-driven and editable in the Godot inspector for balancing iteration.
3. Support both major prestige archetypes from Kongregate's analysis:
   - Lifetime or max-stat based curves (diminishing gains when resetting at the same point repeatedly).
   - Since-reset/run-only curves (same run depth gives similar rewards each reset).
4. Integrate with existing systems (`GameState`, `BigNumber`, generator/buff runtime) without hardcoding one formula.
5. Persist all prestige state in `user://idle_save.json` alongside existing runtime data.

## Non-Goals (For First Iteration)
1. Multiple prestige currencies.
2. Prestige skill tree/shop UI.
3. Offline simulation changes beyond applying the resulting permanent multiplier.

## Kongregate-Informed Curve Model
From "The Math of Idle Games, Part III", prestige formulas can be modeled as transformed progress stats with fractional exponents.

Core variables:
1. `delta_p`: prestige currency gained on reset.
2. `p`: total prestige currency owned.
3. `c_L`: lifetime currency earned.
4. `c_M`: max currency reached in a run.
5. `c_R`: currency earned since last reset.

Supported formula families for this system:
1. Power curve (generic): `f(x) = scale * (x / threshold)^exponent`.
2. Triangular inverse sqrt (Realm Grinder style): solve `x = threshold * p(p+1)/2` for `p`.
3. Log-like compression (future option, disabled by default).

Behavior groups:
1. Cumulative-stat formulas (`c_L`, `c_M`) compute target total prestige then grant `target_total - current_total`.
2. Run-only formulas (`c_R`) compute direct gain per run.

## Proposed Runtime Architecture
1. Add `PrestigeManager` autoload (`core/prestige/prestige_manager.gd`) as the single authority for prestige state and reset flow.
2. Add `PrestigeConfig` resource (`core/prestige/prestige_config.gd`) authored in inspector and loaded from data assets.
3. `GameState` remains owner of currencies/generator state; `PrestigeManager` orchestrates reset and applies permanent multiplier.
4. Generators read the active prestige multiplier through one accessor (`PrestigeManager.get_total_multiplier()`), then multiply existing `run_multiplier` behavior.

## Data Model

### PrestigeConfig (Resource)
Editor-authored resource fields (all exported):
1. `id: StringName`.
2. `display_name: String`.
3. `prestige_currency_id: StringName` (logical id, not regular wallet currency).
4. `source_currency_id: StringName` (which gameplay currency powers prestige calculation).
5. `basis: BasisType` enum:
   - `LIFETIME_TOTAL`
   - `RUN_TOTAL`
   - `RUN_MAX`
6. `formula: FormulaType` enum:
   - `POWER`
   - `TRIANGULAR_INVERSE`
7. `threshold_mantissa: float` and `threshold_exponent: int` (BigNumber-like threshold).
8. `scale: float`.
9. `exponent: float` (used by `POWER`).
10. `flat_bonus: float`.
11. `minimum_gain: int`.
12. `rounding_mode: RoundingMode` enum (`FLOOR`, `ROUND`, `CEIL`).
13. `allow_prestige_without_gain: bool`.
14. Multiplier tuning:
   - `multiplier_mode: MultiplierMode` enum (`ADDITIVE`, `MULTIPLICATIVE_POWER`).
   - `base_multiplier: float`.
   - `multiplier_per_prestige: float`.
   - `multiplier_exponent: float`.

### Prestige Runtime State
Persisted by `PrestigeManager`:
1. `total_prestige_earned: BigNumber`.
2. `current_prestige_unspent: BigNumber`.
3. `prestige_resets_count: int`.
4. `run_start_total_source_currency: BigNumber`.
5. `run_peak_source_currency: BigNumber`.
6. `last_reset_time: int`.

## Formula Specification

### 1) Basis Value Extraction
Given configured `source_currency_id`:
1. `LIFETIME_TOTAL`: `basis_value = GameState.get_total_currency_acquired_by_id(source_currency_id)`.
2. `RUN_TOTAL`: `basis_value = lifetime_now - run_start_total_source_currency`.
3. `RUN_MAX`: `basis_value = run_peak_source_currency`.

### 2) Raw Gain
1. POWER: `raw = scale * pow(basis_value / threshold, exponent) + flat_bonus`.
2. TRIANGULAR_INVERSE:
   - `k = basis_value / threshold`
   - `target = (sqrt(1 + 8k) - 1) / 2`
   - if basis is cumulative (`LIFETIME_TOTAL`, `RUN_MAX` interpreted as cumulative target), `raw = target - total_prestige_earned`
   - if basis is run-only, `raw = target`

### 3) Post-Processing
1. Clamp negative to zero.
2. Apply configured rounding.
3. Enforce `minimum_gain` when basis passed threshold and gain > 0.

### 4) Multiplier Application
`get_total_multiplier()` returns one of:
1. Additive mode: `base_multiplier + total_prestige_earned * multiplier_per_prestige`.
2. Multiplicative power mode: `base_multiplier * pow(1 + multiplier_per_prestige, pow(total_prestige_earned, multiplier_exponent))`.

Implementation note: compute large-number powers via `log10` transforms against `BigNumber` to avoid float overflow.

## Reset Flow
1. Player presses prestige button.
2. `PrestigeManager.calculate_pending_gain()` computes gain from configured curve.
3. If gain is zero and `allow_prestige_without_gain` is false, block reset.
4. On confirm:
   - Add gain to `total_prestige_earned` and `current_prestige_unspent`.
   - Increment `prestige_resets_count`.
   - Reset runtime progression (`GameState` currencies, generator owned counts, generator availability that should restart locked).
   - Preserve permanent unlocks only if explicitly marked as persistent in future extensions.
   - Reinitialize run-tracking values (`run_start_total_source_currency`, `run_peak_source_currency`).
   - Emit `prestige_performed(gain, total_prestige)` signal.

## GameState Integration
1. Add APIs for reset-safe state initialization (single call from `PrestigeManager` instead of duplicating clear logic).
2. Keep total-acquired currency behavior explicit:
   - Option A (recommended): reset current currencies and generator ownership, keep lifetime totals for `LIFETIME_TOTAL` basis.
   - Option B: clear totals too and rely on dedicated lifetime accumulator in prestige state.
3. Ensure generator/buff registrations are idempotent after reset (`_ensure_registered` paths already support this pattern).

## Editor Authoring And Balancing Workflow
1. Create `idles/prestige/primary_prestige.tres` using `PrestigeConfig`.
2. Designers tune only exported fields in inspector (no code edits).
3. Provide presets matching Kongregate article examples:
   - Realm Grinder-like: `basis=RUN_MAX`, `formula=TRIANGULAR_INVERSE`, `threshold=1e12`.
   - AdCap-like: `basis=LIFETIME_TOTAL`, `formula=POWER`, `scale=150`, `threshold=1e15`, `exponent=0.5`.
   - Cookie Clicker-like: `basis=LIFETIME_TOTAL`, `formula=POWER`, `threshold=1e12`, `exponent=0.333333`.
   - Egg Inc-like: `basis=RUN_TOTAL`, `formula=POWER`, `threshold=1e6`, `exponent=0.14`.
4. Balance target guidance:
   - For sqrt-like curves, doubling prestige generally needs roughly 3x-4x deeper runs.
   - For cube-root curves, doubling prestige tends toward ~8x deeper runs.
   - For ~1/7 exponent run curves, doubling prestige needs ~128x deeper runs.

## UI Requirements
1. Prestige panel must display:
   - current prestige total
   - pending gain (`delta_p`)
   - resulting multiplier after reset
   - basis stat currently used (`c_L`, `c_R`, or `c_M` equivalent)
2. Reset CTA disabled when pending gain is zero and config disallows zero-gain resets.
3. Confirmation dialog explicitly lists what resets and what is kept.

## Persistence
1. Extend save payload with `prestige_state` object.
2. Serialize all `BigNumber` values with existing `BigNumber.serialize()` pattern.
3. During load, validate dictionaries and apply defaults if fields are missing.
4. Maintain backward compatibility with pre-prestige saves by creating default prestige state when absent.

## Validation Plan
1. Headless parse: `"$GODOT_BIN" --headless --path . --quit`.
2. Script checks once implemented:
   - `"$GODOT_BIN" --headless --check-only --script res://core/prestige/prestige_manager.gd`
   - `"$GODOT_BIN" --headless --check-only --script res://core/prestige/prestige_config.gd`
3. Manual smoke cases:
   - same reset point in cumulative mode yields reduced/zero incremental gain.
   - same reset point in run-only mode yields roughly same gain.
   - multiplier updates production immediately after reset.
   - prestige state survives save/load.

## Implementation Milestones
1. Introduce data classes (`PrestigeConfig`) and one authored `.tres` profile.
2. Implement `PrestigeManager` with gain math + persistence.
3. Add reset integration entrypoint in `GameState`.
4. Wire generator production multiplier to prestige.
5. Add initial prestige UI panel and confirmation flow.
