using Godot; using Newlon.Components.Zombies; using System.Collections.Generic; namespace Newlon.Components.Level; [GlobalClass] public partial class LevelRunner : Node { private AdventureLevelResource resource; private int waveIndex = -1; private bool hugeWaveApproaching = false; public float waveHealth = 0; public float waveHealthMax = 0; public List zombies = []; [Export] private MoneyReward defaultReward; [Export] private RowSpawner rowSpawner; [Export] private Timer waveTimer; [Export] private float approachNotificationTime; [Export] private AnimationPlayer player; [Export] private Node rewardParent; [Export] private AudioStream firstWaveSound; [Signal] public delegate void ResourceChangedEventHandler(AdventureLevelResource resource); [Signal] public delegate void WaveChangedEventHandler(int to); [Signal] public delegate void HugeWaveApproachingCallbackEventHandler(); [Signal] public delegate void HugeWaveInitiatedEventHandler(int waveNumber); [Signal] public delegate void FinalWaveInitiatedEventHandler(); public override void _Ready() { waveTimer.Timeout += SummonWave; } public override void _Process(double delta) { if (RuntimeLevelData.Instance.GetLevelState() != RuntimeLevelData.LevelStates.Game) return; if (waveIndex == resource.waves.Count - 1) return; if (waveTimer.TimeLeft < approachNotificationTime && resource.waves[waveIndex + 1].isHugeWave && hugeWaveApproaching == false) { hugeWaveApproaching = true; EmitSignal(SignalName.HugeWaveApproachingCallback); } } public void SetLevelResource(AdventureLevelResource data) { resource = data; waveTimer.Stop(); waveTimer.WaitTime = resource.initialWaveDelay; waveTimer.Start(); EmitSignal(SignalName.ResourceChanged, resource); } private void SummonWave() { waveIndex += 1; hugeWaveApproaching = false; EmitSignal(SignalName.WaveChanged, waveIndex); if (resource.waves[waveIndex].isHugeWave) EmitSignal(SignalName.HugeWaveInitiated, waveIndex); rowSpawner.Add(resource.waves[waveIndex].zombiesOrdered); ClearZombies(); if (waveIndex == resource.waves.Count - 1) { EmitSignal(SignalName.FinalWaveInitiated); return; } if (waveIndex == 0) { AudioSequencer.Play("fl_wave",firstWaveSound); } waveTimer.WaitTime = resource.waves[waveIndex].customWaveDelay > 0 ? resource.waves[waveIndex].customWaveDelay : resource.standardWaveDelay; waveTimer.Start(); } private void OnHPChanged(float delta) { waveHealth += delta; if (waveIndex == resource.waves.Count - 1) return; if (waveHealth / waveHealthMax <= resource.wavePercentage) { if (resource.waves[waveIndex + 1].isHugeWave && waveTimer.TimeLeft > 6) { waveTimer.WaitTime = 6; waveTimer.Start(); ClearZombies(); } else { waveTimer.Stop(); SummonWave(); } } } public void ClearZombies() { foreach (var zom in zombies) { if (zom != null) { zom.HPChangedMixed -= OnHPChanged; } } waveHealthMax = 0; waveHealth = waveHealthMax; zombies.Clear(); } public void AddZombie(RuntimeZombieData zombie) { zombies.Add(zombie); waveHealthMax += zombie.GetMaxHPMixed(); waveHealth = waveHealthMax; zombie.HPChangedMixed += OnHPChanged; if (waveIndex == resource.waves.Count - 1) { zombie.HasBeenKilled += OnLastZombieKilled; } } private void OnLastZombieKilled(RuntimeZombieData who) { if (waveHealth > 0) return; RuntimeLevelData.Instance.SetLevelState(RuntimeLevelData.LevelStates.Win); DroppableItem reward; if (resource.reward.Redeem()) { reward = resource.reward.Scene.Instantiate(); LevelController.Instance.SetReward(resource.reward); } else { defaultReward.Redeem(); reward = defaultReward.Scene.Instantiate(); LevelController.Instance.SetReward(defaultReward); } if (reward is DroppableSeedpacket seedpacket && resource.reward is PlantReward plantReward) { seedpacket.plant = plantReward.Plant; } Callable.From(() => { rewardParent.AddChild(reward); reward.GlobalPosition = who.GlobalPosition + Vector2.Up * FieldParams.TileHeight * 0.5f; var dropmover = new DropMover(); reward.AddChild(dropmover); }).CallDeferred(); reward.PickedUp += () => { player.Play("win"); var tween = CreateTween(); var camera = GetViewport().GetCamera2D(); tween.TweenProperty(reward, "global_position", camera.GlobalPosition, 4.0); tween.Parallel().TweenProperty(reward, "global_scale", new Vector2(3.0f, 3.0f), 4.0); tween.TweenInterval(1.0); tween.TweenCallback(Callable.From(LevelController.Instance.EndLevel)); reward.InputPickable = false; }; } }