using System.Threading.Tasks; using Cirno.Scripts.Resources; using Cirno.Scripts.Resources.ScriptableBullets; using Cirno.Scripts.UI; using Godot; using Godot.Collections; namespace Cirno.Scripts.Actors; public partial class Boss : Enemy, IActivable { [Export] public string BossName { get; private set; } //[Export] private Array Phases; [Export] public BossScript BossScript { get; private set; } //[Export] private PackedScene BossHudPrefab; [Export] public Vector2 BossPhaseAnimationStartingPosition = new Vector2(180, 10); private int currentPhaseIndex = 0; private bool _started = false; private bool _waiting = false; private GameManager _gameManager; public GameManager GameManager => _gameManager; private Vector2 _homePosition; public Vector2 HomePosition => _homePosition; private BossPhase CurrentPhase => BossScript.Phases[currentPhaseIndex]; private Marker2D _cameraMarker; [Export] public Vector2 CameraOffset = Vector2.Zero; private TextureRect _animationTextureRect; //[Export] private Texture2D _bossPortraitTexture; private BossHud _bossHud; public override void _Ready() { base._Ready(); if (BossScript is null) { GD.PrintErr($"No boss script defined in {this.Name}"); return; } _gameManager = this.GetGameManager(); _homePosition = this.GlobalPosition; _cameraMarker = new Marker2D(); _gameManager.CallDeferred("add_child", _cameraMarker); _cameraMarker.GlobalPosition = _homePosition + CameraOffset; if (BossScript.HudPrefab is not null) { _bossHud = BossScript.HudPrefab.Instantiate(); _gameManager.CallDeferred("add_child", _bossHud); _bossHud.Name = $"{BossName}_BossHud"; _bossHud.Visible = false; _bossHud.BossName = BossName; _bossHud.BossMaxHealth = this.Health; _bossHud.BossHealth = this._currentHealth; _bossHud.SpellCardName = CurrentPhase.PhaseName; // TODO: Do some translation for health values to match the thresholds this.HealthChanged += (float newValue) => {_bossHud.BossHealth = newValue;}; if (BossScript.PortraitTexture is not null) { // var canvas = new CanvasLayer(); // canvas.Name = "BossPhaseAnimationCanvas"; // _gameManager.CallDeferred("add_child", canvas); _animationTextureRect = new TextureRect(); _animationTextureRect.Texture = BossScript.PortraitTexture; _bossHud.CallDeferred("add_child", _animationTextureRect); _animationTextureRect.Position = BossPhaseAnimationStartingPosition; _animationTextureRect.Visible = false; } } } public override void _Process(double delta) { base._Process(delta); if (!_started) return; if (_waiting) return; CurrentPhase.UpdatePhase(delta); if (_currentHealth <= CurrentPhase.Threshold && currentPhaseIndex + 1 < BossScript.Phases.Count) { currentPhaseIndex++; _bossHud.SpellCardName = CurrentPhase.PhaseName; StartPhase(CurrentPhase); } } protected override void Explode() { if (_bossHud is not null) { _bossHud.QueueFree(); } _gameManager.CameraTargetPlayer(); base.Explode(); } private void StartPhase(BossPhase phase) { if (phase.PlayAnimation) { _waiting = true; _invulnerable = true; _ = Switchphase(phase); } else { phase.Start(this); } } public void TakeDamage(int amount) { if (!_started) return; _currentHealth -= amount; } public void Activate(ActivationType activationType = ActivationType.Toggle) { _started = true; if (_bossHud is not null) { _bossHud.Visible = true; } _gameManager.CameraTargetObject(_cameraMarker); StartPhase(CurrentPhase); } private async Task Switchphase(BossPhase phase) { await PlayAnimation(); _waiting = false; _invulnerable = false; phase.Start(this); } private async Task PlayAnimation() { _animationTextureRect.Modulate = new Color(_animationTextureRect.Modulate.R, _animationTextureRect.Modulate.G, _animationTextureRect.Modulate.B, 0f); _animationTextureRect.Position = BossPhaseAnimationStartingPosition; _animationTextureRect.Visible = true; var tween = GetTree().CreateTween(); tween.SetEase(Tween.EaseType.InOut); tween.SetTrans(Tween.TransitionType.Linear); tween.TweenProperty(_animationTextureRect, "modulate:a", 1f, 0.2f); tween.TweenProperty(_animationTextureRect, "global_position", _animationTextureRect.GlobalPosition + new Vector2(-64f, 20f), 1.5f); tween.TweenProperty(_animationTextureRect, "modulate:a", 0f, 0.2f); //await Task.Delay(800); // Wait for the tween to finish await ToSignal(tween, "finished"); _animationTextureRect.Visible = false; } }