2026-04-10 14:58:03 +02:00
|
|
|
using Godot;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using Chessistics.Engine.Model;
|
2026-04-10 23:21:38 +02:00
|
|
|
using Chessistics.Scripts.Pieces;
|
2026-04-10 14:58:03 +02:00
|
|
|
|
|
|
|
|
namespace Chessistics.Scripts.UI;
|
|
|
|
|
|
|
|
|
|
public partial class PieceStockPanel : VBoxContainer
|
|
|
|
|
{
|
|
|
|
|
[Signal]
|
|
|
|
|
public delegate void PieceSelectedEventHandler(int kindIndex);
|
|
|
|
|
|
|
|
|
|
private readonly Dictionary<PieceKind, (Button button, Label countLabel, int remaining)> _entries = new();
|
|
|
|
|
private PieceKind? _selectedKind;
|
|
|
|
|
|
|
|
|
|
public PieceKind? SelectedKind => _selectedKind;
|
|
|
|
|
|
2026-04-10 23:21:38 +02:00
|
|
|
private static readonly Color NormalBg = new("#2A2A2E");
|
|
|
|
|
private static readonly Color SelectedBg = new("#3D6B8E");
|
|
|
|
|
private static readonly Color HoverBg = new("#353538");
|
|
|
|
|
private static readonly Color DisabledBg = new("#1E1E20");
|
|
|
|
|
private static readonly Color BorderNormal = new("#444448");
|
|
|
|
|
private static readonly Color BorderSelected = new("#5A9ECC");
|
|
|
|
|
|
2026-04-10 14:58:03 +02:00
|
|
|
public void Setup(IReadOnlyList<PieceStock> stock)
|
|
|
|
|
{
|
|
|
|
|
foreach (var child in GetChildren())
|
|
|
|
|
child.QueueFree();
|
|
|
|
|
_entries.Clear();
|
|
|
|
|
_selectedKind = null;
|
|
|
|
|
|
|
|
|
|
var title = new Label { Text = "PIECES" };
|
|
|
|
|
title.AddThemeFontSizeOverride("font_size", 16);
|
2026-04-10 23:21:38 +02:00
|
|
|
title.AddThemeColorOverride("font_color", new Color("#B8942A"));
|
2026-04-10 14:58:03 +02:00
|
|
|
AddChild(title);
|
|
|
|
|
|
|
|
|
|
AddChild(new HSeparator());
|
|
|
|
|
|
|
|
|
|
foreach (var entry in stock)
|
|
|
|
|
{
|
|
|
|
|
var hbox = new HBoxContainer();
|
2026-04-10 23:21:38 +02:00
|
|
|
hbox.AddThemeConstantOverride("separation", 8);
|
|
|
|
|
|
|
|
|
|
// Color dot matching piece color
|
|
|
|
|
var dot = new ColorRect
|
|
|
|
|
{
|
|
|
|
|
CustomMinimumSize = new Vector2(10, 10),
|
|
|
|
|
Size = new Vector2(10, 10),
|
|
|
|
|
Color = PieceView.GetPieceColor(entry.Kind),
|
|
|
|
|
MouseFilter = Control.MouseFilterEnum.Ignore
|
|
|
|
|
};
|
|
|
|
|
var dotCenter = new CenterContainer { CustomMinimumSize = new Vector2(14, 32) };
|
|
|
|
|
dotCenter.AddChild(dot);
|
|
|
|
|
hbox.AddChild(dotCenter);
|
2026-04-10 14:58:03 +02:00
|
|
|
|
|
|
|
|
var button = new Button
|
|
|
|
|
{
|
|
|
|
|
Text = GetPieceName(entry.Kind),
|
|
|
|
|
CustomMinimumSize = new Vector2(120, 32),
|
2026-04-10 23:21:38 +02:00
|
|
|
ToggleMode = false // We manage selection state ourselves
|
2026-04-10 14:58:03 +02:00
|
|
|
};
|
2026-04-10 23:21:38 +02:00
|
|
|
ApplyButtonStyle(button, false);
|
2026-04-10 14:58:03 +02:00
|
|
|
|
|
|
|
|
var countLabel = new Label { Text = $"x{entry.Count}" };
|
2026-04-10 23:21:38 +02:00
|
|
|
countLabel.AddThemeFontSizeOverride("font_size", 13);
|
|
|
|
|
countLabel.AddThemeColorOverride("font_color", new Color("#999999"));
|
2026-04-10 14:58:03 +02:00
|
|
|
|
|
|
|
|
var kind = entry.Kind;
|
|
|
|
|
button.Pressed += () => OnPieceButtonPressed(kind);
|
|
|
|
|
|
|
|
|
|
hbox.AddChild(button);
|
|
|
|
|
hbox.AddChild(countLabel);
|
|
|
|
|
AddChild(hbox);
|
|
|
|
|
|
|
|
|
|
_entries[entry.Kind] = (button, countLabel, entry.Count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnPieceButtonPressed(PieceKind kind)
|
|
|
|
|
{
|
|
|
|
|
if (_selectedKind == kind)
|
|
|
|
|
{
|
|
|
|
|
_selectedKind = null;
|
|
|
|
|
UpdateButtonStates();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_selectedKind = kind;
|
|
|
|
|
UpdateButtonStates();
|
|
|
|
|
EmitSignal(SignalName.PieceSelected, (int)kind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateButtonStates()
|
|
|
|
|
{
|
|
|
|
|
foreach (var (k, (button, _, remaining)) in _entries)
|
|
|
|
|
{
|
2026-04-10 23:21:38 +02:00
|
|
|
bool selected = k == _selectedKind;
|
2026-04-10 14:58:03 +02:00
|
|
|
button.Disabled = remaining <= 0;
|
2026-04-10 23:21:38 +02:00
|
|
|
ApplyButtonStyle(button, selected);
|
2026-04-10 14:58:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 23:21:38 +02:00
|
|
|
private static void ApplyButtonStyle(Button button, bool selected)
|
|
|
|
|
{
|
|
|
|
|
var bg = selected ? SelectedBg : NormalBg;
|
|
|
|
|
var border = selected ? BorderSelected : BorderNormal;
|
|
|
|
|
|
|
|
|
|
var normal = MakeStyle(bg, border);
|
|
|
|
|
var hover = MakeStyle(selected ? SelectedBg.Lightened(0.1f) : HoverBg, border);
|
|
|
|
|
var disabled = MakeStyle(DisabledBg, new Color("#2A2A2E"));
|
|
|
|
|
|
|
|
|
|
button.AddThemeStyleboxOverride("normal", normal);
|
|
|
|
|
button.AddThemeStyleboxOverride("hover", hover);
|
|
|
|
|
button.AddThemeStyleboxOverride("pressed", MakeStyle(bg.Darkened(0.15f), border));
|
|
|
|
|
button.AddThemeStyleboxOverride("disabled", disabled);
|
|
|
|
|
button.AddThemeFontSizeOverride("font_size", 12);
|
|
|
|
|
button.AddThemeColorOverride("font_color", selected ? Colors.White : new Color("#CCCCCC"));
|
|
|
|
|
button.AddThemeColorOverride("font_disabled_color", new Color("#555555"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static StyleBoxFlat MakeStyle(Color bg, Color border)
|
|
|
|
|
{
|
|
|
|
|
return new StyleBoxFlat
|
|
|
|
|
{
|
|
|
|
|
BgColor = bg,
|
|
|
|
|
BorderColor = border,
|
|
|
|
|
BorderWidthBottom = 1, BorderWidthTop = 1,
|
|
|
|
|
BorderWidthLeft = 1, BorderWidthRight = 1,
|
|
|
|
|
CornerRadiusTopLeft = 4, CornerRadiusTopRight = 4,
|
|
|
|
|
CornerRadiusBottomLeft = 4, CornerRadiusBottomRight = 4,
|
|
|
|
|
ContentMarginLeft = 8, ContentMarginRight = 8,
|
|
|
|
|
ContentMarginTop = 4, ContentMarginBottom = 4
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 14:58:03 +02:00
|
|
|
public void UpdateCount(PieceKind kind, int remaining)
|
|
|
|
|
{
|
|
|
|
|
if (!_entries.TryGetValue(kind, out var entry)) return;
|
|
|
|
|
_entries[kind] = (entry.button, entry.countLabel, remaining);
|
|
|
|
|
entry.countLabel.Text = $"x{remaining}";
|
|
|
|
|
entry.button.Disabled = remaining <= 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ClearSelection()
|
|
|
|
|
{
|
|
|
|
|
_selectedKind = null;
|
|
|
|
|
UpdateButtonStates();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string GetPieceName(PieceKind kind) => kind switch
|
|
|
|
|
{
|
Add Pion piece, surplus stock, and levels 4-6
- Pion (Pawn): orthogonal range 1, social status 1 (lowest), green color
- All existing levels get surplus stock including pawns for player choice
- Level 4 "Le Carrefour": 8x8, dual cargo diagonal routes, center wall block
- Level 5 "Le Labyrinthe": 8x6, wall corridors, knights essential for shortcuts
- Level 6 "Trois Royaumes": 10x8, 3 productions + 3 demands, full network puzzle
- Production interval concept removed (all produce every turn)
- GDD updated with Pion section and 6 level descriptions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:03:36 +02:00
|
|
|
PieceKind.Pawn => "Pion",
|
2026-04-10 14:58:03 +02:00
|
|
|
PieceKind.Rook => "Tour II",
|
|
|
|
|
PieceKind.Bishop => "Fou II",
|
|
|
|
|
PieceKind.Knight => "Cavalier",
|
2026-04-10 23:24:14 +02:00
|
|
|
PieceKind.Queen => "Dame",
|
2026-04-10 14:58:03 +02:00
|
|
|
_ => kind.ToString()
|
|
|
|
|
};
|
|
|
|
|
}
|