using System.Linq; using DonkeysAndDroids; using Godot; using RobotAndDonkey.Game.Execution.Commands; using RobotAndDonkey.Game.Execution.Results; using RobotAndDonkey.Game.GameState; using System.Text; using RobotAndDonkey.Game.Data; using RobotAndDonkey.Game.Pois; public partial class VictoryScreen : Control, IScreen { public override void _Ready() { ContinueButton.Pressed += OnContinueButtonPressed; if (StatsLabel != null) { StatsLabel.BbcodeEnabled = true; StatsLabel.AutowrapMode = TextServer.AutowrapMode.Word; StatsLabel.Clear(); } } public override void _Process(double delta) { UpdateGamepadScroll((float)delta); } private void UpdateGamepadScroll(float delta) { if (StatsLabel == null || !Visible) return; var axis = Input.GetActionStrength("tooltip_scroll_down") - Input.GetActionStrength("tooltip_scroll_up"); if (Mathf.Abs(axis) < 0.1f) return; var verticalScrollBar = StatsLabel.GetVScrollBar(); if (verticalScrollBar == null) return; verticalScrollBar.Value += axis * GamepadScrollSpeed * delta; } public void OnContinueButtonPressed() { if (m_Victory) { Main.Instance.StartMetaGame(); } else { Main.Instance.Execute(new NextAssignmentCommand(Main.Instance.CurrentRequest.RequestId)); } } public void Deactivate() { } public void EnableInputs() { ContinueButton.Disabled = false; } public void DisableInputs() { ContinueButton.Disabled = true; } public void Activate() { } public void Configure(CoreLoop coreLoop, Tween tween) { if (StatsLabel == null || tween == null) return; DisableInputs(); BuildStats(coreLoop); StatsLabel.Modulate = new(1f, 1f, 1f, 0f); ContinueButton.Modulate = new(1f, 1f, 1f, 0f); tween.TweenProperty(StatsLabel, "modulate:a", 1.0f, 0.6f).SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out); tween.TweenInterval(0.2f); tween.TweenProperty(ContinueButton, "modulate:a", 1.0f, 0.4f).SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out); tween.TweenCallback(Callable.From(EnableInputs)); } public bool HandleResult(Result result, Tween tween) { return false; } private void BuildStats(CoreLoop coreLoop) { var sheds = coreLoop.Board.Cells.Select(c => c.Poi as Shed).Where(s => s != null).ToArray(); m_Victory = sheds.Sum(s => s.Remaining) == 0; ContinueButton.Text = m_Victory ? "New assignment" : "Continue"; m_Builder.Clear(); AppendTitle("Execution report", GetAssignmentSubtitle(coreLoop)); AppendSectionHeader("Programs"); AppendKeyValue("Programs executed", coreLoop.ProgramsExecuted.ToString()); AppendKeyValue("Programs remaining", coreLoop.ProgramCount.ToString()); AppendKeyValue("Instructions used", coreLoop.InstructionsUsed.ToString()); AppendKeyValue("Instructions remaining", coreLoop.PatchDeck.Count.ToString()); AppendSectionHeader("Stats"); var deliveries = coreLoop.Board.Cells.Select(c => c.Poi as Shed).Where(s => s != null).Sum(s => s!.Remaining); var deliveryColor = deliveries == 0 ? ColorGood : ColorBad; AppendKeyValue("Deliveries pending", WrapColor(deliveries.ToString(), deliveryColor)); var patchColor = coreLoop.PatchDeck.Count == 0 ? ColorBad : ColorGood; AppendKeyValue("Cards not drawn", WrapColor(coreLoop.PatchDeck.Count.ToString(), patchColor)); var energyLeft = coreLoop.Currency.Energy - Balancing.Instance.EndOfProgramEnergyReplenish; var energyLeftColor = energyLeft == 0 ? ColorBad : ColorGood; AppendKeyValue("Remaining energy", WrapColor(energyLeft.ToString(), energyLeftColor)); AppendSectionHeader("Movement"); AppendKeyValue("Path length", coreLoop.PathLength.ToString()); AppendKeyValue("Tiles visited", coreLoop.CellsVisited.Count.ToString()); AppendSectionHeader("Efficiency"); var energyColor = coreLoop.EnergyWasted == 0 ? ColorGood : ColorBad; AppendKeyValue("Energy wasted", WrapColor(coreLoop.EnergyWasted.ToString(), energyColor)); var overspillText = coreLoop.Overspill > 0 ? WrapColor(coreLoop.Overspill.ToString(), ColorBad) : WrapColor(coreLoop.Overspill.ToString(), ColorGood); AppendKeyValue("Overspill", overspillText); // Assignment / deliveries AppendSectionHeader("Assignment"); AppendKeyValue("Total delivery", coreLoop.Currency.Delivery.ToString()); AppendKeyValue("Glitches deferred", coreLoop.DeferGlitchCount.ToString()); AppendKeyValue("Shop rerolls", coreLoop.RerollCount.ToString()); StatsLabel.Text = m_Builder.ToString(); StatsLabel.ScrollToLine(0); } private string GetAssignmentSubtitle(CoreLoop coreLoop) { if (m_Victory) return WrapColor("Victory! All goods delivered", ColorGood); if (coreLoop.Currency.Delivery <= 0) return WrapColor("No deliveries completed", ColorBad); if (coreLoop.EnergyWasted == 0 && coreLoop.Overspill == 0) return WrapColor("Perfectly efficient run", ColorGood); if (coreLoop.EnergyWasted <= 3 && coreLoop.Overspill <= 1) return WrapColor("Very efficient run", ColorGood); return WrapColor("Lots of room for optimization", ColorSubtitle); } // ---------------------------------------------------------------------- // Small helpers, mirroring Tooltip.cs style // ---------------------------------------------------------------------- private static string WrapColor(string text, string colorHex) { return $"[color={colorHex}]{text}[/color]"; } private void AppendTitle(string title, string subtitle = null) { m_Builder.Append(WrapColor($"[b]{title}[/b]", ColorTitle)); if (!string.IsNullOrEmpty(subtitle)) { m_Builder.Append('\n'); m_Builder.Append(subtitle); } m_Builder.Append('\n'); } private void AppendSectionHeader(string title) { m_Builder.Append('\n'); m_Builder.Append(WrapColor($"[b]{title}[/b]", ColorHeader)); m_Builder.Append('\n'); } private void AppendKeyValue(string key, string value) { m_Builder.Append(WrapColor($"{key}: ", ColorLabel)).Append(WrapColor(value, ColorText)).Append('\n'); } private const string ColorTitle = "#ffd65c"; private const string ColorSubtitle = "#aaaaaa"; private const string ColorHeader = "#a5d6ff"; private const string ColorLabel = "#cccccc"; private const string ColorText = "#ffffff"; private const string ColorGood = "#a5d6a7"; private const string ColorBad = "#ef9a9a"; private const string ColorMuted = "#9e9e9e"; private readonly StringBuilder m_Builder = new(); [Export] public float GamepadScrollSpeed = 800f; [ExportGroup("Buttons")] [Export] private Button ContinueButton; [ExportGroup("Stats")] [Export] private RichTextLabel StatsLabel; private bool m_Victory; }