Skip to main content
Core

# TDGS PROGRESSION - AI REFERENCE

Document 12 | Structured specification for AI parsing

## CORE CONCEPT

XP_CONCEPT: - XP is earned by overcoming challenges - The harder the challenge relative to YOUR capabilities, the more you learn - Same enemy = different XP for different characters (Personal Difficulty)

## DIFFICULTY FORMULA

DIFFICULTY = 11 - (Your_Stat - Their_Stat) - Modifiers // This is the Resolution formula rearranged: // Resolution: d20 + Delta + Mods >= 11 (Did I succeed?) // Difficulty: 11 - Delta - Mods (What do I need to roll?) // Same math, different question.

## DIFFICULTY SPECTRUM

DIFFICULTY_SPECTRUM = { "trivial": {"range": "<=2", "success_xp": 1, "failure_xp": 0}, "simple": {"range": "3-4", "success_xp": 3, "failure_xp": 0}, "easy": {"range": "5-6", "success_xp": 6, "failure_xp": 0}, "routine": {"range": "7-8", "success_xp": 10, "failure_xp": 0}, "moderate": {"range": "9-10", "success_xp": 15, "failure_xp": 0}, "challenging": {"range": "11-12", "success_xp": 25, "failure_xp": 0}, "difficult": {"range": "13-14", "success_xp": 40, "failure_xp": 20}, "hard": {"range": "15-16", "success_xp": 60, "failure_xp": 30}, "heroic": {"range": "17-18", "success_xp": 85, "failure_xp": 42}, "legendary": {"range": "19-20", "success_xp": 120, "failure_xp": 60}, "mythic": {"range": "21+", "success_xp": 175, "failure_xp": 87} } // Difficulty <= 0: No XP (too easy) // Failure XP: Only Tier 7+ (Difficult and above) // Failure XP: Half of success, requires survival

## XP CALCULATION FUNCTION

function calculate_xp(your_stat, their_stat, modifiers, succeeded, survived): delta = your_stat - their_stat difficulty = 11 - delta - modifiers if difficulty <= 0: return 0 // Too easy, no growth tier = get_tier_from_difficulty(difficulty) if succeeded: return tier.success_xp elif tier.failure_xp > 0 and survived: return tier.failure_xp else: return 0

## XP TIMING

XP_TIMING: when: "End of encounter" per: "Challenge overcome" // "Overcome" = defeated, bypassed, resolved, solved, concluded // Three goblins = three XP awards // One negotiation = one XP award

## LEVELING COST BRACKETS

LEVELING_BRACKETS = { "1-5": 80, "6-10": 160, "11-15": 280, "16-20": 500, "21-30": 800, "31-40": 1200, "41-50": 2000, "51-60": 3500, "61-70": 6000, "71-80": 10000, "81-90": 16000, "91-100": 25000 } CUMULATIVE_XP = { 20: 4600, 40: 23900, 60: 76600, 80: 230100, 100: 625100 } // Cost curve is continuous and exponential // No single wall; every bracket costs more than the last

## STAT INCREASE COSTS

STAT_INCREASE_COST = { "1-5": 50, "6-10" : 100, "11-20": 300, "21-30": 500, "31-40": 800, "41+": 1000 } function get_stat_increase_cost(current_stat): if current_stat <= 5: return 50 if current_stat <= 10: return 100 if current_stat <= 20: return 300 if current_stat <= 30: return 500 if current_stat <= 40: return 800 return 1000 // Cost based on CURRENT stat before increase // No hard cap; cost IS the soft cap

## WHAT XP BUYS

XP_PURCHASES = ["class_levels", "stat_increases"] // XP does NOT buy: // - Individual skills // - Individual spells // - Individual traits // - Items // - Narrative outcomes // Skills from outside class: narrative only (items, training, GM)

## MULTICLASSING

MULTICLASSING: restrictions: None xp_pool: Single (player chooses split) level_costs: Per-class (based on level in THAT class) level_1_exception: true // Example: // Fighter 25 / Mage 5 // Next Fighter level (26): 800 XP (21-30 bracket) // Next Mage level (6): 80 XP (1-5 bracket) // Level 1 Exception: // Taking Level 1 of new class never adds to existing skills // Prevents multiclass dipping abuse

## XP SPENDING TIMING

XP_SPENDING: default: "Between scenes" override: "GM discretion" // No mid-combat level ups by default // GMs can change ANY ruling for their table

## SKILLS OUTSIDE CLASS

SKILLS_OUTSIDE_CLASS: xp_purchase: false sources: ["items", "narrative", "gm_discretion", "transformation"] // Want Power Strike without Fighter? // Find mentor, find item, convince GM // Cannot buy directly with XP

## GROUP XP RULES

GROUP_XP_MODEL: Participation Gate + Group Multiplier // Personal Difficulty still drives individual XP // Participation gate determines eligibility // Group multiplier adjusts for shared effort // No cap based on other members' stats PARTICIPATION_GATE: Eligible if AT LEAST ONE of: CATEGORY_1 (Combat Engagement): Initiated or was target of at least one resolution roll against the enemy // Must enter the d20 resolution system // Standing idle does not qualify // Tagging for 1 damage without a resolution roll does not qualify CATEGORY_2 (Support): Provided healing or mitigation to a character eligible under another category // Healers earn XP by supporting real combatants // Cannot chain eligibility between non-combatants // "Eligible under another category" prevents carry-heals-carry loops CATEGORY_3 (Objective): Spent an action that directly advanced the win condition // Covers objective-based and non-combat encounters NOT_ELIGIBLE: 0 XP for that encounter GROUP_SIZE_MULTIPLIER = { 1: 1.00, 2: 0.80, 3: 0.67, 4: 0.57, 5: 0.50, 6: 0.44, 7: 0.40, 8: 0.36 } GROUP_XP_FORMULA: XP_award = floor(Personal_XP × GroupMultiplier) If Personal_XP > 0 and XP_award == 0: award 1 XP (minimum-after-multiplier) function calculate_group_xp(characters, encounter): eligible = [c for c in characters if meets_participation_gate(c, encounter)] n = len(eligible) multiplier = GROUP_SIZE_MULTIPLIER[min(n, 8)] for character in characters: if character not in eligible: character.xp_award = 0 continue personal_xp = calculate_xp(character, encounter) // From Difficulty Spectrum award = floor(personal_xp * multiplier) if personal_xp > 0 and award == 0: award = 1 // minimum-after-multiplier character.xp_award = award function meets_participation_gate(character, encounter): // Category 1: Resolution engagement if character in encounter.resolution_participants: return true // Category 2: Support (must support someone eligible under another category) if character.healed_or_mitigated_for(encounter.resolution_participants): return true if character.healed_or_mitigated_for(encounter.objective_participants): return true // Category 3: Objective if character in encounter.objective_participants: return true return false // ANTI-POWERLEVELING: // Carry cannot qualify Category 1: can't survive resolution vs enemies 30+ stats above // Carry cannot qualify Category 2: must support someone already eligible // Carry cannot qualify Category 3: only applies to objective encounters // Result: carry gets 0 XP. Other players keep their Personal XP.

## LUCK AND XP

LUCK_IN_XP: false // LUK does not factor into Difficulty calculation // Difficulty uses effort/capability stats only // Lucky roll against dragon = still fought a dragon

## KEY CONSTANTS

BASE_DIFFICULTY = 11 FAILURE_XP_THRESHOLD = 7 // Tier "Difficult" and above FAILURE_XP_MULTIPLIER = 0.5 NO_XP_THRESHOLD = 0 // Difficulty <= 0 = no XP LEVEL_80_COST = 10000 // High-tier bracket LEVEL_91_COST = 25000 // Maximum bracket // Cost curve is exponential; no single wall GROUP_MULTIPLIER_MIN = 0.36 // 8 players GROUP_MULTIPLIER_MAX = 1.00 // Solo MINIMUM_AFTER_MULTIPLIER = 1 // If Personal_XP > 0 and award rounds to 0

## DESIGN NOTES

DESIGN_PRINCIPLES: - Difficulty is the resolution formula rearranged - Personal Difficulty means same enemy = different XP for different characters - Failure XP requires survival ("the dead learn nothing") - No group penalty on Personal Difficulty; participation gate + group multiplier handle groups - Participation gate requires resolution engagement, support of eligible combatant, or objective action - Stats-only builds are allowed but naturally punished (no abilities) - Exponential cost curve filters high-level characters naturally - GMs can override XP spending timing - Skills outside class go through narrative, not XP