Files
TheriapolisV3/Theriapolis.Core/Rules/Stats/XpTable.cs
T
Christopher Wiebe b451f83174 Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback
anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md).
All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:40:51 -07:00

53 lines
1.4 KiB
C#

namespace Theriapolis.Core.Rules.Stats;
/// <summary>
/// Standard d20 XP-to-level table. Phase 5 awards XP and persists it but
/// does not act on level-up — <see cref="LevelForXp"/> is exposed for the
/// HUD to display "next level in N XP" without requiring a level-up
/// flow yet.
/// </summary>
public static class XpTable
{
/// <summary>XP threshold for each level 1..20. <c>Threshold[1] = 0</c> by convention.</summary>
public static readonly int[] Threshold = new[]
{
0, // index 0 unused
0, // level 1
300, // level 2
900,
2_700,
6_500,
14_000,
23_000,
34_000,
48_000,
64_000,
85_000,
100_000,
120_000,
140_000,
165_000,
195_000,
225_000,
265_000,
305_000,
355_000, // level 20
};
public static int LevelForXp(int xp)
{
if (xp < 0) throw new ArgumentOutOfRangeException(nameof(xp));
for (int lv = 20; lv >= 1; lv--)
if (xp >= Threshold[lv]) return lv;
return 1;
}
public static int XpRequiredForNextLevel(int currentLevel)
{
if (currentLevel < 1 || currentLevel > 20)
throw new ArgumentOutOfRangeException(nameof(currentLevel));
if (currentLevel == 20) return int.MaxValue;
return Threshold[currentLevel + 1];
}
}