using System.Collections.Generic; using Godot; using Godot.Collections; public partial class SurvivalZombieSpawner : Node { // Zombie pools // Points from pools go in that order: support -> tank -> horde -> bank // Horde pool is allowed to shrink during runtime [Export] private Array supportPool; [Export] private Array tankPool; [Export] private Array hordePool; private List cachedSupportPool; private List cachedTankPool; private List cachedHordePool; private float minSupportPoints; private float minTankPoints; private float minHordePoints; [Export] private float points = 0; [Export] private float huge_wave_points; [Export] private Curve velocity_curve; private float velocity = 0; [Export] private double time = 0.0; private float fin_a; private RandomNumberGenerator rng = new(); public override void _Ready() { rng.Randomize(); cachedSupportPool = LoadFromRegistry(supportPool); cachedTankPool = LoadFromRegistry(tankPool); cachedHordePool = LoadFromRegistry(hordePool); cachedTankPool.Sort((x, y) => { return (int)(x.Cost - y.Cost); }); cachedHordePool.Sort((x, y) => { return (int)(x.Cost - y.Cost); }); minSupportPoints = cachedSupportPool[0].Cost; minTankPoints = cachedTankPool[0].Cost; minHordePoints = cachedHordePool[0].Cost; fin_a = (velocity_curve.Sample(velocity_curve.MaxDomain) - velocity_curve.Sample(velocity_curve.MaxDomain - 0.001f)) / 0.001f; } public override void _Process(double delta) { points += velocity * (float)delta; if (time > velocity_curve.MaxDomain) { velocity += fin_a * (float)delta; } else { velocity = velocity_curve.Sample((float)time); } time += delta; } public void SummonWave() { bool big_wave = false; if ((int)time % 300 == 0) { points += velocity/velocity_curve.Sample((float)time)*huge_wave_points; big_wave = true; } float support_points = points * 0.2f; float tank_points = points * 0.5f; float horde_points = points * 0.3f; points = 0; List wave = []; var remaining = SummonTank(tank_points, wave); support_points += remaining * 0.8f; horde_points += remaining * 0.2f; horde_points += SummonSupport(support_points, wave); points += SummonHorde(horde_points, wave, big_wave); wave.Sort((x, y) => { return rng.RandiRange(-1, 1); }); foreach (var zom in wave) { ZombieSequencer.Instance.Add(zom.internal_id); } big_wave = false; } private float SummonSupport(float given_points, List wave) { if (cachedSupportPool.Count == 0) { return given_points; } while (given_points >= minSupportPoints) { var chosen_zombie = cachedSupportPool[rng.RandiRange(0, cachedSupportPool.Count - 1)]; if (given_points - chosen_zombie.Cost >= 0) { wave.Add(chosen_zombie); given_points -= chosen_zombie.Cost; } } return given_points; } private float SummonTank(float given_points, List wave) { if (cachedTankPool.Count == 0) { return given_points; } int zombieIndex = cachedTankPool.Count - 1; while (given_points >= minSupportPoints && zombieIndex > -1) { if (cachedTankPool[zombieIndex].Cost > given_points) { zombieIndex--; continue; } var chosen_zombie = cachedTankPool[zombieIndex]; wave.Add(chosen_zombie); given_points -= chosen_zombie.Cost; } return given_points; } private float SummonHorde(float given_points, List wave, bool is_big) { if (cachedHordePool.Count == 0) { return given_points; } while (is_big == false && cachedHordePool.Count > 1 && cachedHordePool[1].Cost * 15 <= given_points) { cachedHordePool.RemoveAt(0); minHordePoints = cachedHordePool[0].Cost; } while (given_points >= minHordePoints) { var chosen_zombie = cachedHordePool[rng.RandiRange(0, cachedHordePool.Count - 1)]; if (given_points - chosen_zombie.Cost >= 0) { wave.Add(chosen_zombie); given_points -= chosen_zombie.Cost; } } return given_points; } private List LoadFromRegistry(Array pool) { List list = []; foreach (var res in pool) { list.Add(GameRegistry.GetEntityByName(res) as ZombieResource); } return list; } }