162 lines
4.7 KiB
C#
162 lines
4.7 KiB
C#
|
|
using Godot;
|
||
|
|
using System;
|
||
|
|
using Chessistics.Engine.Model;
|
||
|
|
using Chessistics.Engine.Rules;
|
||
|
|
using Chessistics.Scripts.Board;
|
||
|
|
|
||
|
|
namespace Chessistics.Scripts.Input;
|
||
|
|
|
||
|
|
public partial class InputMapper : Node
|
||
|
|
{
|
||
|
|
[Signal]
|
||
|
|
public delegate void PlacementRequestedEventHandler(int kindIndex, int startCol, int startRow, int endCol, int endRow);
|
||
|
|
[Signal]
|
||
|
|
public delegate void RemovalRequestedEventHandler(int pieceId);
|
||
|
|
[Signal]
|
||
|
|
public delegate void CellClickedEventHandler(int col, int row);
|
||
|
|
[Signal]
|
||
|
|
public delegate void CancelledEventHandler();
|
||
|
|
|
||
|
|
public enum PlacementPhase { None, SelectingStart, SelectingEnd }
|
||
|
|
|
||
|
|
private BoardView _boardView = null!;
|
||
|
|
private PieceKind? _selectedKind;
|
||
|
|
private Coords? _selectedStart;
|
||
|
|
private PlacementPhase _phase = PlacementPhase.None;
|
||
|
|
private BoardSnapshot? _snapshot;
|
||
|
|
|
||
|
|
public PlacementPhase CurrentPhase => _phase;
|
||
|
|
|
||
|
|
public void Initialize(BoardView boardView)
|
||
|
|
{
|
||
|
|
_boardView = boardView;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void SetSnapshot(BoardSnapshot snapshot) => _snapshot = snapshot;
|
||
|
|
|
||
|
|
public void SelectPieceKind(PieceKind kind)
|
||
|
|
{
|
||
|
|
_selectedKind = kind;
|
||
|
|
_selectedStart = null;
|
||
|
|
_phase = PlacementPhase.SelectingStart;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Cancel()
|
||
|
|
{
|
||
|
|
_selectedKind = null;
|
||
|
|
_selectedStart = null;
|
||
|
|
_phase = PlacementPhase.None;
|
||
|
|
_boardView.ClearHighlights();
|
||
|
|
EmitSignal(SignalName.Cancelled);
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void _UnhandledInput(InputEvent @event)
|
||
|
|
{
|
||
|
|
if (@event is InputEventMouseButton mouseEvent && mouseEvent.Pressed)
|
||
|
|
{
|
||
|
|
if (mouseEvent.ButtonIndex == MouseButton.Right)
|
||
|
|
{
|
||
|
|
Cancel();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mouseEvent.ButtonIndex == MouseButton.Left)
|
||
|
|
{
|
||
|
|
HandleLeftClick(mouseEvent.GlobalPosition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (@event is InputEventKey keyEvent && keyEvent.Pressed && keyEvent.Keycode == Key.Escape)
|
||
|
|
{
|
||
|
|
Cancel();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void HandleLeftClick(Vector2 globalPos)
|
||
|
|
{
|
||
|
|
var localPos = _boardView.ToLocal(globalPos);
|
||
|
|
var coords = _boardView.PixelToCoords(localPos);
|
||
|
|
|
||
|
|
if (coords == null) return;
|
||
|
|
|
||
|
|
switch (_phase)
|
||
|
|
{
|
||
|
|
case PlacementPhase.SelectingStart:
|
||
|
|
OnStartSelected(coords.Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case PlacementPhase.SelectingEnd:
|
||
|
|
OnEndSelected(coords.Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
EmitSignal(SignalName.CellClicked, coords.Value.Col, coords.Value.Row);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnStartSelected(Coords start)
|
||
|
|
{
|
||
|
|
if (_selectedKind == null || _snapshot == null) return;
|
||
|
|
|
||
|
|
// Build a temporary board state for move validation
|
||
|
|
var boardState = GetBoardStateForValidation();
|
||
|
|
if (boardState == null) return;
|
||
|
|
|
||
|
|
var legalEnds = MoveValidator.GetLegalEndCells(_selectedKind.Value, start, boardState);
|
||
|
|
if (legalEnds.Count == 0) return;
|
||
|
|
|
||
|
|
_selectedStart = start;
|
||
|
|
_phase = PlacementPhase.SelectingEnd;
|
||
|
|
|
||
|
|
_boardView.ClearHighlights();
|
||
|
|
_boardView.HighlightCells(legalEnds, new Color("#4488FF88"));
|
||
|
|
var startCell = _boardView.GetCellView(start);
|
||
|
|
startCell?.SetHighlightColor(new Color("#44FFFF44"));
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnEndSelected(Coords end)
|
||
|
|
{
|
||
|
|
if (_selectedKind == null || _selectedStart == null) return;
|
||
|
|
|
||
|
|
var start = _selectedStart.Value;
|
||
|
|
var kind = _selectedKind.Value;
|
||
|
|
|
||
|
|
EmitSignal(SignalName.PlacementRequested, (int)kind, start.Col, start.Row, end.Col, end.Row);
|
||
|
|
|
||
|
|
// Reset placement state
|
||
|
|
_phase = PlacementPhase.None;
|
||
|
|
_selectedKind = null;
|
||
|
|
_selectedStart = null;
|
||
|
|
_boardView.ClearHighlights();
|
||
|
|
}
|
||
|
|
|
||
|
|
private BoardState? GetBoardStateForValidation()
|
||
|
|
{
|
||
|
|
// Reconstruct a minimal BoardState from snapshot for MoveValidator
|
||
|
|
// This is a read-only usage — we just need the grid and dimensions
|
||
|
|
if (_snapshot == null) return null;
|
||
|
|
|
||
|
|
// We need a LevelDef-like structure to create a BoardState
|
||
|
|
// For validation purposes, we create a fresh one from the snapshot data
|
||
|
|
var level = new LevelDef
|
||
|
|
{
|
||
|
|
Width = _snapshot.Width,
|
||
|
|
Height = _snapshot.Height,
|
||
|
|
Productions = [],
|
||
|
|
Demands = [],
|
||
|
|
Walls = [],
|
||
|
|
Stock = []
|
||
|
|
};
|
||
|
|
|
||
|
|
var state = BoardState.FromLevel(level);
|
||
|
|
|
||
|
|
// Copy grid from snapshot
|
||
|
|
for (int c = 0; c < _snapshot.Width; c++)
|
||
|
|
for (int r = 0; r < _snapshot.Height; r++)
|
||
|
|
state.Grid[c, r] = _snapshot.Grid[c, r];
|
||
|
|
|
||
|
|
return state;
|
||
|
|
}
|
||
|
|
}
|