saumwacht-godot/scripts/luneraria/core/lune_waves.gd
Martin Stickelbroeck b565546c37 M1: autoritativer Drei-Lane-Kern (Karte, Kampf, Partie, Wellen, Bots)
LuneMap spiegelsymmetrisch mit 16 Türmen und 2 Ancients, LuneCombat mit
reihenfolgeunabhängigem Zweiphasenschritt und Gebäudesperren für jede
Schadensquelle, LuneMatch mit Planungsentwürfen, atomarer Übernahme,
Einmal-Belohnung und Kernsieg/Unentschieden, endlose LuneWaves, Bots über
dieselbe Befehlsschnittstelle. 87 Kernprüfungen bestanden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:57:37 +02:00

38 lines
2.1 KiB
GDScript

class_name LuneWaves
extends RefCounted
## Endless monster waves. Both teams receive the identical composition per lane, so the
## waves never favour a side. Count is capped; strength grows through stats and later types.
const MELEE: Array[String] = ["e01", "e02", "e05"]
static func strength(balance: LuneBalance, round_number: int, growth: float) -> float:
var r: float = float(maxi(1, round_number) - 1)
return 1.0 + growth * r + balance.wave_growth_quadratic * r * r
static func monster_count(balance: LuneBalance, round_number: int) -> int:
var extra: int = (maxi(1, round_number) - 1) / maxi(1, balance.wave_count_every)
return mini(balance.wave_max_count, balance.wave_base_count + extra)
static func unlocked_types(balance: LuneBalance, round_number: int) -> PackedStringArray:
var pool: PackedStringArray = balance.monster_pool
var available: int = clampi(1 + (maxi(1, round_number) - 1) / 2, 1, pool.size())
return pool.slice(0, available)
## Definitions for one lane of one team, melee first so they lead the march.
static func build(balance: LuneBalance, round_number: int) -> Array[Dictionary]:
var types: PackedStringArray = unlocked_types(balance, round_number)
var hp_factor: float = strength(balance, round_number, balance.wave_hp_growth)
var damage_factor: float = strength(balance, round_number, balance.wave_damage_growth)
var bounty_factor: float = balance.monster_bounty_scale * (1.0 + balance.bounty_growth * float(maxi(1, round_number) - 1))
var melee: Array[Dictionary] = []
var ranged: Array[Dictionary] = []
for index: int in range(monster_count(balance, round_number)):
var type_id: String = types[(index + round_number) % types.size()]
var source: Dictionary = DataCatalog.ENEMIES[type_id]
var monster: Dictionary = source.duplicate(true)
monster.max_hp = float(source.max_hp) * hp_factor
monster.damage = float(source.damage) * damage_factor
monster.hp_factor = hp_factor
monster.bounty = int(clampf(roundf(float(source.bounty) * bounty_factor), 1.0, 1.0e12))
(melee if type_id in MELEE else ranged).append(monster)
return melee + ranged