Files
zfxaction25/DonkeysAndDroids.Godot/ProgramScreen.cs
2026-04-19 00:43:27 +02:00

244 lines
7.6 KiB
C#

using System.Collections.Generic;
using System.Linq;
using DonkeysAndDroids;
using Godot;
using RobotAndDonkey.Game.Cards;
using RobotAndDonkey.Game.Data;
using RobotAndDonkey.Game.Execution;
using RobotAndDonkey.Game.Execution.Commands;
using RobotAndDonkey.Game.Execution.Results;
using RobotAndDonkey.Game.Utils;
public partial class ProgramScreen : Control, IScreen
{
public override void _Ready()
{
m_ProgramRow = GetNode<CardRow>("%ProgramRow");
m_Execute = GetNode<Button>("%Execute");
m_Discard = GetNode<Button>("%Discard");
m_Sort = GetNode<Button>("%Sort");
m_TapeLabel = GetNode<Label>("%TapeLabel");
m_HandLabel = GetNode<Label>("%HandLabel");
m_FlameBackground = GetNode<Node2D>("%FlameBackground");
m_Execute.Pressed += OnExecutePressed;
m_Discard.Pressed += OnDiscardPressed;
m_Sort.Pressed += OnSortPressed;
m_ProgramRow.Connect(CardRow.SignalName.SelectionChanged, new(this, nameof(OnSelectionChanged)));
m_ProgramRow.Connect(CardRow.SignalName.OrderChanged, new(this, nameof(OnOrderChanged)));
m_ProgramRow.CanChangeSelection = CanChangeSelection;
}
private void OnOrderChanged()
{
UpdateLabels();
SendMoveCommand();
}
private void SendMoveCommand()
{
if (Main.Instance.CurrentRequest == null)
return;
var ordered = m_ProgramRow.OrderedCards.Select(card => card.CardId).ToArray();
var selected = m_ProgramRow.SelectedCardIds.ToArray();
Main.Instance.Execute(new MoveCardsCommand(Main.Instance.CurrentRequest.RequestId, ordered, selected));
}
private void UpdateLabels()
{
var selectedIds = m_ProgramRow.SelectedCardIds.ToHashSet();
var tapeSpace = 0;
var handSpace = 0;
foreach (var card in m_ProgramRow.OrderedCards)
{
if (selectedIds.Contains(card.CardId))
tapeSpace += card.OccupiedSpace;
else
handSpace += card.OccupiedSpace;
}
m_TapeLabel.Text = $"{tapeSpace} / {Main.Instance.CoreLoop.Currency.TapeLength}";
m_HandLabel.Text = $"{handSpace} / {Main.Instance.CoreLoop.Currency.HandSize}";
m_Discard.Text = Main.Instance.CoreLoop.PatchDeck.Count.ToString();
m_Discard.TooltipText = $"Discard {selectedIds.Count} instructions. Costs {Balancing.Instance.DiscardEnergyCost} each.";
}
private void RefreshDiscardCommand()
{
if (Main.Instance.CurrentRequest == null)
{
m_DiscardCommand = null;
return;
}
m_DiscardCommand = new(Main.Instance.CurrentRequest.RequestId, m_ProgramRow.SelectedCardIds.ToArray());
if (m_Discard != null)
m_Discard.Disabled = m_DiscardCommand == null || !m_DiscardCommand.IsValid(Main.Instance.CoreLoop, out _);
}
private void OnSelectionChanged(CardControl[] cardControls)
{
RefreshDiscardCommand();
UpdateLabels();
SendMoveCommand();
}
private bool CanChangeSelection(CardControl cardControl, bool selected)
{
var selectedIds = m_ProgramRow.SelectedCardIds.ToHashSet();
if (selected)
selectedIds.Add(cardControl.Card.CardId);
else
selectedIds.Remove(cardControl.Card.CardId);
var tapeSpace = 0;
var handSpace = 0;
foreach (var card in m_ProgramRow.OrderedCards)
{
if (selectedIds.Contains(card.CardId))
tapeSpace += card.OccupiedSpace;
else
handSpace += card.OccupiedSpace;
}
return tapeSpace <= Main.Instance.CoreLoop.Currency.TapeLength && handSpace <= Main.Instance.CoreLoop.Currency.HandSize;
}
private void OnExecutePressed()
{
Main.Instance.Execute(m_RunProgramCommand);
}
private void OnDiscardPressed()
{
Main.Instance.Execute(m_DiscardCommand);
}
private void OnSortPressed()
{
var selectedIds = m_ProgramRow.SelectedCardIds.ToHashSet();
var unselected = m_ProgramRow.OrderedCards.Where(card => !selectedIds.Contains(card.CardId)).ToList();
var sortedUnselected = CardExtensions.SortForHand(unselected);
var ordered = new List<Card>(m_ProgramRow.OrderedCards.Count);
var unselectedIndex = 0;
foreach (var card in m_ProgramRow.OrderedCards)
{
if (selectedIds.Contains(card.CardId))
{
ordered.Add(card);
continue;
}
ordered.Add(sortedUnselected[unselectedIndex]);
unselectedIndex += 1;
}
m_ProgramRow.Configure(ordered, GetTree().CreateTween(), false, false);
m_ProgramRow.ApplySelection(selectedIds, true);
OnOrderChanged();
}
public void Deactivate()
{
}
public void EnableInputs()
{
m_RunProgramCommand ??= new(Main.Instance.CurrentRequest.RequestId);
RefreshDiscardCommand();
m_Sort.Disabled = false;
}
public void DisableInputs()
{
m_RunProgramCommand = null;
m_DiscardCommand = null;
m_Sort.Disabled = true;
}
public void Activate()
{
}
public bool HandleResult(Result result, Tween tween)
{
switch (result)
{
case RunCardResult runCardResult:
{
m_ProgramRow.RunCard(runCardResult.Card, tween);
RefreshDiscardCommand();
UpdateLabels();
return true;
}
case ProgramRowResult programRowResult:
{
m_ProgramRow.Configure(programRowResult.OrderedCards, tween, false, false);
m_ProgramRow.ApplySelection(programRowResult.TapeCardIds, true);
RefreshDiscardCommand();
UpdateLabels();
return true;
}
case ModifyCardResult modifyCardResult:
{
m_ProgramRow.ModifyCard(modifyCardResult.Card, modifyCardResult.Modifier, tween);
UpdateLabels();
return true;
}
case HandResult:
case TapeResult:
{
UpdateLabels();
return true;
}
}
return false;
}
public override void _Process(double delta)
{
if (m_Execute != null)
{
m_Execute.Disabled = m_RunProgramCommand == null;
var lastRun = m_RunProgramCommand?.Preview(Main.Instance.CoreLoop).Any(r => r is RunPhaseResult { NewRunPhase: ERunPhase.Scoring }) ?? false;
if (lastRun)
{
m_FlameBackground.Visible = true;
m_Execute.TooltipText = "Execute last program";
}
else
{
m_FlameBackground.Visible = false;
m_Execute.TooltipText = "Execute";
}
}
}
public void Configure(Tween tween)
{
var coreLoop = Main.Instance.CoreLoop;
var ordered = coreLoop.ProgramRow.ToList();
m_ProgramRow.Configure(ordered, tween, false, false);
m_ProgramRow.ApplySelection(coreLoop.TapeCardIds.ToArray(), true);
m_RunProgramCommand = new(Main.Instance.CurrentRequest.RequestId);
RefreshDiscardCommand();
UpdateLabels();
}
private RunProgramCommand m_RunProgramCommand;
private DiscardCommand m_DiscardCommand;
private CardRow m_ProgramRow;
private Button m_Execute;
private Button m_Discard;
private Button m_Sort;
private Label m_TapeLabel;
private Label m_HandLabel;
private Node2D m_FlameBackground;
}