Skip to main content

Prestige & Ascension System

Prestige & Ascension System

Status: DESIGN APPROVED 2026-04-17 — Implementation in progress

Last updated: August 30, 2026

Lineage — Prestige & Ascension System Design

Status: DESIGN APPROVED 2026-04-17 — Implementation in progress

Engine-side companion: documents the service layer (, , ), persistence, schedulers, and cross-game wiring. This doc is the player-facing design (pillars, UX, rollout phases, postmortems).

The Prestige & Ascension system rewards high-investment players through two complementary tracks:

  • Track A — Ancient Bloodline (Cross-Game Prestige): Account-level tier that recognizes player investment across games (Dark Tower level, Darkness Falls level, Lineage victories). Applied once per kingdom creation. Grants flavor + a small stat boost on the founding ruler.
  • Track B — Dynasty Ascension (New Game+): Per-player carryover that lets victorious players start their next Blood Lineage kingdom with perks earned in the prior run. Accumulates across runs.

The tracks are complementary, not duplicative — A recognizes what you did elsewhere, B recognizes what you did in this game. Cap-and-compose rules prevent stacking from trivializing a new kingdom.

Origin

Player AMAR7HH5ZWRSV feedback (IDs 310-322, 2026-04-14) requested:

"Level 2000-2500 players in DC should have special perks when transferring to Blood Lineage. It would reduce your work since only a few players are active at that level, and those players would get recognized for the investment."

The literal ask (DC→BL level-gated transfer) is partially addressed by user_design . This design generalizes the intent into a reusable cross-game prestige system (A) while adding a parallel in-game progression track (B) that rewards repeat Blood Lineage victors.

Design Pillars

  1. Recognition without steamrolling — Bonuses are meaningful but do not let a fresh kingdom skip early-game challenges.
  2. Composable, not multiplicative — A grants identity (trait, flavor, small stat bump), B grants mechanical headstart (resources, carried traits). They compose additively with hard caps.
  3. Small cohort visibility — Tier 4-5 should feel rare and earned; most players should land at tier 0-2.
  4. Incremental shippability — Phase 1 = Track A only; Phase 2 adds Track B; Phase 3 adds cross-game live level readers. Each phase is useful alone.

Track A — Ancient Bloodline (Cross-Game Prestige Tier)

Tier Thresholds

Tier is computed from the player's peak activity across games. The highest-qualifying signal wins (OR semantics, not AND).

Retune 2026-05-12: Original thresholds (100/500/1000/2000/2500) were authored against speculative DF progression. Real player distribution as of 2026-05-12 is max DF character_level=74, so every threshold above 75 was unreachable — 50/58 prestige rows persisted as tier 0. Resolution of user_decision 19068 chose Option 1 (retune to real data). New thresholds match actual percentiles: T5 ≥50 (top ~1.3%, 16 players), T4 ≥25 (top ~1.6%), T3 ≥15 (top ~3%), T2 ≥10 (top ~9%), T1 ≥5 (top ~25%). Bonus magnitudes unchanged because they were calibrated for rarity intent, which the new thresholds preserve. DT thresholds mirror DF (DT level stub still returns 0 pending Phase 3). Lineage victory thresholds unchanged.

Tier Name Threshold (any ONE qualifies) Grant
0 Commoner Default Nothing (base game)
1 Ascendant DF level ≥ 5 / DT level ≥ 5 / Lineage victory count ≥ 1 +5 to one ruler stat (player chooses on first kingdom)
2 Noble Blood DF level ≥ 10 / DT level ≥ 10 / Lineage victory count ≥ 3 +5 to two ruler stats, LEGITIMIZED trait auto-granted to founding ruler
3 Royal Lineage DF level ≥ 15 / DT level ≥ 15 / Lineage victory count ≥ 5 +10 to two ruler stats, LEGITIMIZED trait, +100 starting prestige points
4 Ancient Bloodline DF level ≥ 25 / DT level ≥ 25 / Lineage victory count ≥ 10 +10 to all ruler stats, DRAGONBLOOD trait, +250 prestige, custom sigil
5 Mythic Progenitor DF level ≥ 50 / DT level ≥ 50 / Lineage victory count ≥ 20 +15 to all ruler stats, DRAGONBLOOD + LEGITIMIZED traits, +500 prestige, "Mythic" tier badge in chat, dynasty motto slot

Storage

CREATE TABLE claude.user_account_prestige (
    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
    account_ref   VARCHAR(255) NOT NULL UNIQUE,
    tier          INT NOT NULL DEFAULT 0,
    source_game   VARCHAR(32),              -- which game awarded the current tier ('DARKNESS_FALLS','DARK_TOWER','LINEAGE')
    source_value  INT,                      -- the raw number that qualified (e.g. DF level, victory count)
    computed_at   TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    notes         TEXT,
    INDEX idx_tier (tier)
);

Compute Logic

Service:

maxDfLevel = SELECT MAX(character_level) FROM claude.game_leaderboard
             WHERE customer_id = :accountRef AND game_type = 'DARKNESS_FALLS'

maxDtLevel = (Phase 3 — stub returns 0 for now; TODO: integrate dark_citadel.character_dark_citadel.level JSON read)

lineageVictories = SELECT COUNT(*) FROM lineage.dynasties WHERE account_ref = :accountRef AND had_victory = 1
                   -- OR read from user_lineage_ascension.victory_count once Track B ships

tier = max(
    tierFromLevel(maxDfLevel),
    tierFromLevel(maxDtLevel),
    tierFromVictoryCount(lineageVictories)
)

persist to claude.user_account_prestige (upsert by account_ref)
return tier + (source_game, source_value)

Application

Hooked into :

tierInfo = accountPrestigeService.resolveTier(kingdom.ownerUserId)
prestigeGrant = .getGrantForTier(tierInfo.tier)

foundingRuler.leadership += prestigeGrant.leadershipBonus
foundingRuler.warfare    += prestigeGrant.warfareBonus
foundingRuler.diplomacy  += prestigeGrant.diplomacyBonus
foundingRuler.magic      += prestigeGrant.magicBonus
for trait in prestigeGrant.autoTraits:
    foundingRuler.traits.add(trait)
dynasty.prestigePoints += prestigeGrant.bonusPrestige
dynasty.tierBadge = tierInfo.tierName  // for UI/chat display

Refresh Cadence

  • Lazy: Recomputed on kingdom creation (one query per new kingdom — cheap)
  • On demand: Admin endpoint /api/lineage/admin/prestige/refresh/{accountRef} for manual re-computation
  • Scheduled: Nightly job that refreshes tier for any player who leveled up in DF today (detects via claude.game_leaderboard.last_updated change)

Track B — Dynasty Ascension (New Game+)

Storage

CREATE TABLE lineage.user_lineage_ascension (
    id                   BIGINT AUTO_INCREMENT PRIMARY KEY,
    account_ref          VARCHAR(255) NOT NULL UNIQUE,
    victory_count        INT NOT NULL DEFAULT 0,
    highest_generation   INT NOT NULL DEFAULT 0,
    carried_traits       JSON,            -- list of trait IDs to apply to next founding ruler
    carried_prestige     INT NOT NULL DEFAULT 0,
    last_victory_type    VARCHAR(32),
    last_victory_at      TIMESTAMP NULL,
    updated_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_victory_count (victory_count)
);

Earn Logic — On Victory

Hooked into .onKingdomVictory(kingdom, victoryType):

ascension = getOrCreateAscension(kingdom.ownerUserId)
ascension.victoryCount += 1
ascension.highestGeneration = max(ascension.highestGeneration, kingdom.dynasty.generationNumber)
ascension.lastVictoryType = victoryType
ascension.lastVictoryAt = NOW()

-- Player picks ONE trait from the victorious ruler to carry forward
-- If no choice made within 7 days, system auto-picks the rarest trait (BLOODLINE category preferred)
ascension.carriedTraits += [chosenTrait]
if ascension.carriedTraits.size > 3:
    drop oldest   -- cap at 3 carried traits max

ascension.carriedPrestige = min(ascension.carriedPrestige + kingdom.dynasty.prestigePoints / 10, 2000)
-- 10% of final dynasty prestige carries forward, cap at 2000

Apply Logic — On New Kingdom

Also hooked into (runs AFTER Track A):

ascension = ascensionService.getByAccountRef(kingdom.ownerUserId)
if ascension == null: skip

for trait in ascension.carriedTraits:
    foundingRuler.traits.add(trait)       -- composes with Track A traits

dynasty.prestigePoints += ascension.carriedPrestige
dynasty.generationNumber += min(ascension.victoryCount, 5)   -- starting generation bonus, capped
dynasty.newGamePlusCount = ascension.victoryCount

Cap-and-Compose Rules

To prevent Track A + Track B from trivializing a new kingdom:

Cap Value
Total founding-ruler traits 5 max (excess rolled by rarity priority: BLOODLINE > MENTAL > PERSONALITY > PHYSICAL)
Total stat bonuses per stat +20 absolute cap vs base (50) — so a Mythic + 3-time-victor gets +15 from A, +5 from B = 70 base leadership
Total starting prestige 2500 max (Track A's 500 + Track B's 2000 cap = 2500)
Starting generation bonus +5 max (Track B only)

Ascension Carryover UX

On victory, the handler produces a voice prompt:

"Victory! Your dynasty has achieved [VICTORY_TYPE]. Choose a trait from your final ruler to pass into your next kingdom: Brilliant, Dragonblood, or Diplomatic?"

Player picks one. If no response in 7 days, auto-picks the rarest trait from the victorious ruler (BLOODLINE first).

On new kingdom, the intro text mentions carried perks:

"Your bloodline remembers. Generation III begins with the wisdom of your ancestor [RulerName] — Dragonblood trait carries forward, +200 starting prestige."


Rollout Phases

Phase 1 — Track A foundation (MVP — THIS SESSION)

  • Design doc written (this file)
  • Table claude.user_account_prestige created
  • Service implemented (tier compute + grant resolution)
  • Hook in applies Track A bonuses
  • Tier compute uses DF leaderboard + (stubbed) DT level + Lineage victory count
  • Java build passes
  • Backend deployed
  • Smoke test: new Blood Lineage kingdom for a tier-0 and tier-1+ user shows expected bonuses

Phase 2 — Track B foundation (THIS SESSION)

  • Table lineage.user_lineage_ascension created
  • extended with ascension read/write methods OR new
  • Hook in on victory: increment counter + persist carryover
  • Hook in applies Track B carryover (ordered AFTER Track A)
  • Cap-and-compose rules enforced (max 5 traits, +20 stat cap, +5 generation cap)
  • Java build passes
  • Backend deployed

Phase 3 — Live DT Integration (FUTURE — NOT THIS SESSION)

  • Read Dark Tower character level from dark_citadel.character_dark_citadel.level JSON
  • Add implementation
  • Nightly scheduled recompute job for active accounts
  • Handle class-based level differences (DT has per-class levels; take the max)

Phase 4 — Carryover UX polish (PARTIAL — carried-trait choice shipped 2026-06-19)

  • Voice prompt on victory asks player to pick carried trait (capped 3-option; , deferred via user_lineage_ascension.pending_trait_choice). See empire-4x-layer.md Pillar 2a.
  • 7-day auto-pick scheduler ( → , bloodline-first)
  • Intro text on new kingdom mentions inherited perks by name (the New Game Plus headstart summary + the founding-legacy choice, empire-4x-layer.md Pillar 2b)
  • Chat badge showing tier ("Mythic Progenitor") visible to other players

Phase 5 — Cross-Game UX (FUTURE)

  • Announce tier-up when a player crosses a threshold in DF/DT ("Your Blood Lineage bloodline has ascended to Royal!")
  • Add a "Prestige" menu item inside Blood Lineage showing current tier + next threshold
  • Cross-game leaderboard showing top Ancient Bloodlines

Verification Notes — 2026-05-11

Symptom: claude.user_account_prestige reported 0 rows globally as of 2026-05-11, despite lineage.user_lineage_ascension containing 7 post-deploy victors (earliest 2026-04-23).

Surviving cause: short-circuits when kingdom.hasDynasty() is true, so every player whose dynasty was founded BEFORE the 2026-04-17 prestige-feature deploy hit that branch on every subsequent session and never reached applyToFoundingRuler. Their Track A prestige row was never written. The other two candidates were ruled out:

  • Silent upsert failure — RULED OUT. Reproduced locally on 2026-05-11: play_game target=local founded a fresh dynasty and wrote id=2, tier=0, notes='Auto-resolved by '.
  • Unwired auto-trigger — RULED OUT. The view dynasty -> yes prompt path routes through (action FOUND_DYNASTY), and 45 rows landed in a single 5-hour window on 2026-05-11 once players exercised the fresh-founder path.

Fix already shipped: LineageGameLoader.resolvePrestigeForSession (added alongside ensureDynastyForSession) calls on every Lineage session load, independent of dynasty state. resolveTier upserts by account_ref, so the table self-heals as pre-existing players return. Idempotent on subsequent loads.

One-time backfill (2026-05-11): Seven ascension-row players who had not loaded a Lineage session since the hook deployed were backfilled at tier 1 (Ascendant) via direct INSERT, with notes flagging the backfill source. The lazy-resolve hook will overwrite these on next session load with freshly-computed values (e.g., if their DF level since climbed past a threshold).

Regression shield: Scenario test #589 (Track B dynasty lazy-init) already exercises the same LineageGameLoader.load() code path that calls resolvePrestigeForSession — removing the prestige resolve call would not break #589, but removing the entire load-time block would. A new scenario test pins the prestige-specific behavior at the same load checkpoint. scenario_tests assertion grammar (contains_text, option_key, state_field) does not support direct DB-row assertions, so the regression test is a load-path smoke that fires the hook indirectly. A direct-row check belongs in a Java integration test if/when one is added.


Acceptance Criteria (Phase 1 + 2 MVP)

  • Starting a new Blood Lineage kingdom runs the Track A tier resolver and produces expected stat bonus + traits on the founding ruler, based on DF leaderboard level.
  • A player who wins a Lineage game has user_lineage_ascension.victory_count incremented to ≥1.
  • Starting their NEXT Lineage kingdom (after a victory) grants them +1 generationNumber and carried prestige.
  • Java build passes + backend deploys cleanly.
  • Verified via context({ sql: "SELECT ... FROM claude.user_account_prestige" }) that tier rows are written on first kingdom creation.