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
- Recognition without steamrolling — Bonuses are meaningful but do not let a fresh kingdom skip early-game challenges.
- Composable, not multiplicative — A grants identity (trait, flavor, small stat bump), B grants mechanical headstart (resources, carried traits). They compose additively with hard caps.
- Small cohort visibility — Tier 4-5 should feel rare and earned; most players should land at tier 0-2.
- 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_updatedchange)
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_prestigecreated - 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_ascensioncreated - 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.levelJSON - 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=localfounded a fresh dynasty and wroteid=2, tier=0, notes='Auto-resolved by '. - Unwired auto-trigger — RULED OUT. The
view dynasty->yesprompt path routes through (actionFOUND_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_countincremented to ≥1. - Starting their NEXT Lineage kingdom (after a victory) grants them
+1 generationNumberand 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.