Randoloot/scripts/levels/level_balance.gd
2026-10-10 21:21:58 +02:00

46 lines
1.8 KiB
GDScript

extends RefCounted
const MAX_LEVEL := 1000
const COUNT_POINTS := [Vector2(1, 5), Vector2(10, 10), Vector2(50, 18), Vector2(100, 23), Vector2(250, 29), Vector2(500, 34), Vector2(1000, 40)]
# x = level, y = elite fraction, z = boss fraction.
const TIER_POINTS := [Vector3(10, 0, 0), Vector3(50, 0.15, 0), Vector3(100, 0.25, 0.05), Vector3(500, 0.45, 0.10), Vector3(1000, 0.55, 0.15)]
static func enemy_count(level: int) -> int:
var clamped_level := clampi(level, 1, MAX_LEVEL)
for index in range(1, COUNT_POINTS.size()):
var before: Vector2 = COUNT_POINTS[index - 1]
var after: Vector2 = COUNT_POINTS[index]
if clamped_level <= after.x:
return roundi(lerpf(before.y, after.y, inverse_lerp(before.x, after.x, clamped_level)))
return 40
static func enemy_tiers(level: int) -> Array[int]:
var count := enemy_count(level)
var fractions := Vector2.ZERO
for index in range(1, TIER_POINTS.size()):
var before: Vector3 = TIER_POINTS[index - 1]
var after: Vector3 = TIER_POINTS[index]
if level <= after.x:
var progress := clampf(inverse_lerp(before.x, after.x, level), 0.0, 1.0)
fractions = Vector2(lerpf(before.y, after.y, progress), lerpf(before.z, after.z, progress))
break
if level >= MAX_LEVEL:
fractions = Vector2(0.55, 0.15)
var bosses := roundi(count * fractions.y)
var elites := roundi(count * fractions.x)
if level >= 100:
bosses = maxi(1, bosses)
# Every boss begins a cluster with at least two elite escorts.
elites = mini(count - bosses, maxi(elites, bosses * 2))
var tiers: Array[int] = []
for boss in bosses:
tiers.append_array([2, 1, 1])
for elite in elites - bosses * 2:
tiers.append(1)
for normal in count - bosses - elites:
tiers.append(0)
return tiers
static func power_scale(level: int) -> float:
return 1.0 + 0.05 * (clampi(level, 1, MAX_LEVEL) - 1)