INTEGRADED AI
This commit is contained in:
parent
42ea425656
commit
086b114853
12 changed files with 502 additions and 81 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
|||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
/android/
|
||||
stockfish
|
||||
Assets/ChessEngines
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@ stateDiagram
|
|||
HandSetup --> DrawPhase
|
||||
DrawPhase --> ResolvePersistentEffects : Draw/Discard
|
||||
|
||||
ResolvePersistentEffects --> ApplyTileEffects : Update Durations
|
||||
ApplyTileEffects --> PreMovePhase
|
||||
ResolvePersistentEffects --> PreMovePhase : Update Durations
|
||||
|
||||
PreMovePhase --> AttachCards : Play Cards
|
||||
AttachCards --> ApplyCardEffects
|
||||
ApplyCardEffects --> Movement
|
||||
|
||||
Movement --> PostMovePhase
|
||||
PostMovePhase --> EvaluatePosition : Resolve Move Effects
|
||||
PostMovePhase --> ApplyTileEffects : Resolve Move Effects
|
||||
ApplyTileEffects --> EvaluatePosition
|
||||
|
||||
state EvaluatePosition {
|
||||
[*] --> CheckStatus
|
||||
|
|
|
|||
181
Systems/FairyStockfish/Stockfish.gd
Normal file
181
Systems/FairyStockfish/Stockfish.gd
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
# Stockfish.gd
|
||||
extends Node
|
||||
|
||||
# References to game objects
|
||||
var board: Array
|
||||
var game: ChessGame
|
||||
|
||||
# Engine state
|
||||
var engine_path: String = ""
|
||||
var mutex: Mutex
|
||||
var running := false
|
||||
|
||||
# Game state
|
||||
var moves: Array = []
|
||||
var move_time: int = 1000 # in ms
|
||||
var generated_move: Dictionary = {} # Stores the last generated move
|
||||
|
||||
# Piece type mapping
|
||||
var symbol_from_piece_type := {
|
||||
"PAWN": "p", "KNIGHT": "n", "BISHOP": "b",
|
||||
"ROOK": "r", "QUEEN": "q", "KING": "k"
|
||||
}
|
||||
|
||||
var piece_type_from_symbol := {
|
||||
"p": "PAWN", "n": "KNIGHT", "b": "BISHOP",
|
||||
"r": "ROOK", "q": "QUEEN", "k": "KING"
|
||||
}
|
||||
|
||||
func _init(boardRef: Array):
|
||||
board = boardRef
|
||||
mutex = Mutex.new()
|
||||
|
||||
func _ready():
|
||||
game = get_parent() as ChessGame
|
||||
|
||||
func _exit_tree():
|
||||
disconnect_engine()
|
||||
|
||||
func connect_to_engine(path: String) -> bool:
|
||||
if running:
|
||||
return false
|
||||
|
||||
engine_path = path
|
||||
|
||||
# Test if we can execute stockfish
|
||||
var output = []
|
||||
var exit_code = OS.execute(engine_path, ["uci"], output, true)
|
||||
print("Exit code: ", exit_code)
|
||||
print("Output: ", output)
|
||||
if exit_code != OK:
|
||||
printerr("Failed to start Stockfish engine: ", exit_code)
|
||||
return false
|
||||
|
||||
running = true
|
||||
print("Connected to engine: ", engine_path)
|
||||
|
||||
# Initialize with current game state
|
||||
load_fen(game.getCurrentFen())
|
||||
return true
|
||||
|
||||
func disconnect_engine():
|
||||
if running:
|
||||
mutex.lock()
|
||||
var output = []
|
||||
OS.execute(engine_path, ["quit"], output, true)
|
||||
mutex.unlock()
|
||||
running = false
|
||||
engine_path = ""
|
||||
print("Disconnected from engine")
|
||||
|
||||
func limit_strength_to(elo_value: int):
|
||||
mutex.lock()
|
||||
if elo_value != -1: # Using -1 instead of int.MaxValue
|
||||
_send_command("setoption name UCI_LimitStrength value true")
|
||||
_send_command("setoption name UCI_Elo value " + str(elo_value))
|
||||
else:
|
||||
_send_command("setoption name UCI_LimitStrength value false")
|
||||
mutex.unlock()
|
||||
|
||||
func stop_calculating():
|
||||
mutex.lock()
|
||||
_send_command("stop")
|
||||
mutex.unlock()
|
||||
|
||||
func load_fen(fen: String):
|
||||
moves.clear()
|
||||
update_position(fen)
|
||||
|
||||
func update_position(fen: String):
|
||||
mutex.lock()
|
||||
_send_command("position fen " + fen)
|
||||
mutex.unlock()
|
||||
|
||||
func generateMove(think_time_ms: int = 1000) -> void:
|
||||
if not running:
|
||||
return
|
||||
|
||||
move_time = think_time_ms
|
||||
|
||||
# Update position first
|
||||
mutex.lock()
|
||||
var command = "position fen " + game.getCurrentFen()
|
||||
if moves.size() > 0:
|
||||
command += " moves " + " ".join(moves)
|
||||
print(command)
|
||||
var output = _send_command(command)
|
||||
|
||||
# Then get move
|
||||
output = _send_command("go movetime " + str(move_time))
|
||||
if output.size() == 0:
|
||||
return
|
||||
print(type_string(typeof(output[0])))
|
||||
var lines = output[0].split("\n")
|
||||
mutex.unlock()
|
||||
# Parse the output
|
||||
for line in lines:
|
||||
# print("-")
|
||||
# print(line)
|
||||
# print("-")
|
||||
if line.begins_with("bestmove"):
|
||||
var parts = line.split(" ")
|
||||
print( parts)
|
||||
if parts.size() >= 2:
|
||||
generated_move = {
|
||||
"move": parts[1],
|
||||
"ponder": parts[3]
|
||||
}
|
||||
print("Generated move: ", generated_move)
|
||||
return
|
||||
|
||||
generated_move = {}
|
||||
|
||||
func getGeneratedMove() -> Dictionary:
|
||||
var move = generated_move.duplicate()
|
||||
generated_move.clear() # Clear after retrieving
|
||||
return move
|
||||
|
||||
func from_move_to_string(move_data: Dictionary) -> String:
|
||||
var board_size = len(board)
|
||||
|
||||
# Get source and target squares
|
||||
var source_i = move_data.source % board_size
|
||||
var source_j = move_data.source / board_size
|
||||
var target_i = move_data.target % board_size
|
||||
var target_j = move_data.target / board_size
|
||||
|
||||
# Convert to algebraic notation
|
||||
var letters = "abcdefghijklmnopqrstuvwxyz".substr(0, board_size)
|
||||
var str_move = "%s%d%s%d" % [
|
||||
letters[source_i],
|
||||
board_size - source_j,
|
||||
letters[target_i],
|
||||
board_size - target_j
|
||||
]
|
||||
|
||||
# Add promotion piece if needed
|
||||
if move_data.get("flags", "") == "PROMOTION":
|
||||
str_move += symbol_from_piece_type[move_data.promotion_piece]
|
||||
|
||||
return str_move
|
||||
|
||||
func send_move(move_data: Dictionary):
|
||||
var str_move = from_move_to_string(move_data)
|
||||
moves.append(str_move)
|
||||
print("move: ", str_move)
|
||||
|
||||
# Update engine with the new move
|
||||
mutex.lock()
|
||||
var command = "position fen " + game.getCurrentFen()
|
||||
if moves.size() > 0:
|
||||
command += " moves " + " ".join(moves)
|
||||
_send_command(command)
|
||||
mutex.unlock()
|
||||
|
||||
func _send_command(command: String) -> Array:
|
||||
if not running:
|
||||
return []
|
||||
|
||||
var output = []
|
||||
OS.execute(engine_path, [command], output, true)
|
||||
return output
|
||||
|
|
@ -8,6 +8,11 @@ signal send_location(location: String)
|
|||
signal turn_changed
|
||||
var currentPlayer: String = WHITE
|
||||
var board: Array
|
||||
var isWhiteToMove: bool = true
|
||||
var castlingRights: String = "KQkq"
|
||||
var enPassantTarget: String = "-"
|
||||
var halfMoveClock: int = 0
|
||||
var moveCount: int = 1
|
||||
var currentHand: Array
|
||||
var selectedNode: String = ""
|
||||
var locationX: String = ""
|
||||
|
|
@ -21,7 +26,9 @@ var currentlyMovingPiece = null
|
|||
var p1Points: int = 0
|
||||
var p2Points: int = 0
|
||||
var Turn: int = 0
|
||||
|
||||
const StockfishController = preload("res://Systems/FairyStockfish/Stockfish.gd")
|
||||
var stockfishController: StockfishController
|
||||
var stockfishPath = "res://Assets/ChessEngines/stockfish/stockfish.exe"
|
||||
@onready var turnIndicator: ColorRect = $TurnIndicator
|
||||
@onready var p1String: RichTextLabel = $Player1Points
|
||||
@onready var p2String: RichTextLabel = $Player2Points
|
||||
|
|
@ -41,18 +48,31 @@ var Turn: int = 0
|
|||
@onready var boardContainer: FlowContainer = $Flow
|
||||
@onready var stateMachine: StateMachine = $StateMachine
|
||||
|
||||
var currentFen = ""
|
||||
var lightStyle = null
|
||||
|
||||
var darkStyle = null
|
||||
var highlightStyle = null
|
||||
var cpuElo = 1500
|
||||
|
||||
func _ready() -> void:
|
||||
if OS.get_name() == "Windows":
|
||||
stockfishPath = "res://Assets/ChessEngines/stockfish/stockfish.exe"
|
||||
else:
|
||||
stockfishPath = ProjectSettings.globalize_path("res://Assets/ChessEngines/Fairy-Stockfish/src/stockfish")
|
||||
add_to_group("ChessGame")
|
||||
currentFen = FEN
|
||||
DisplayServer.window_set_size(Vector2i(windowXSize, windowYSize))
|
||||
initializeGame()
|
||||
initializeTiles()
|
||||
stateMachine.transitionToNextState(Constants.WHITE_TURN)
|
||||
|
||||
stockfishController = StockfishController.new(board)
|
||||
add_child(stockfishController)
|
||||
if stockfishController.connect_to_engine(stockfishPath):
|
||||
stockfishController.limit_strength_to(cpuElo)
|
||||
|
||||
func _exit_tree():
|
||||
stockfishController.disconnect_engine()
|
||||
|
||||
func initializeTiles() -> void:
|
||||
tileManager = TileManager.new($Flow, self)
|
||||
|
|
@ -83,6 +103,45 @@ func initializeCardPreview() -> void:
|
|||
|
||||
|
||||
|
||||
func getCurrentFen() -> String:
|
||||
var fen = ""
|
||||
|
||||
# For a standard chess board, we want to generate FEN from top (black side, rank 8)
|
||||
# to bottom (white side, rank 1)
|
||||
for y in range(boardYSize):
|
||||
var emptySquares = 0
|
||||
for x in range(boardXSize):
|
||||
# print("CHECKING ", str(x) + "-" + str(y))
|
||||
var container = boardContainer.get_node(str(x) + "-" + str(y)) as PieceContainer
|
||||
var piece = container.get_piece()
|
||||
if piece == null:
|
||||
emptySquares += 1
|
||||
else:
|
||||
if emptySquares > 0:
|
||||
fen += str(emptySquares)
|
||||
emptySquares = 0
|
||||
# Convert piece to FEN notation
|
||||
var fenChar = getPieceFenChar(piece)
|
||||
fen += fenChar
|
||||
|
||||
# Add any remaining empty squares at the end of the rank
|
||||
if emptySquares > 0:
|
||||
fen += str(emptySquares)
|
||||
|
||||
# Add rank separator (except for the last rank)
|
||||
if y < boardYSize - 1:
|
||||
fen += "/"
|
||||
|
||||
# Add the rest of the FEN string components
|
||||
fen += " %s %s %s %d %d" % [
|
||||
"w" if isWhiteToMove else "b",
|
||||
castlingRights,
|
||||
enPassantTarget,
|
||||
halfMoveClock,
|
||||
moveCount
|
||||
]
|
||||
|
||||
return fen
|
||||
func initializeBoard() -> void:
|
||||
# Parse FEN to get board dimensions
|
||||
# rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
|
||||
|
|
@ -485,3 +544,99 @@ func cleanupPhase() -> void:
|
|||
|
||||
func isNull(location: String) -> bool:
|
||||
return get_node_or_null("Flow/" + location) == null
|
||||
|
||||
|
||||
func getPieceFenChar(piece: Pawn) -> String:
|
||||
if piece == null:
|
||||
return ""
|
||||
var fenChar = ""
|
||||
match piece.name:
|
||||
"Pawn": fenChar = "p"
|
||||
"Knight": fenChar = "n"
|
||||
"Bishop": fenChar = "b"
|
||||
"Rook": fenChar = "r"
|
||||
"Queen": fenChar = "q"
|
||||
"King": fenChar = "k"
|
||||
|
||||
# In our system, Item_Color == 1 is white, 0 is black
|
||||
return fenChar.to_upper() if piece.Item_Color == 0 else fenChar
|
||||
|
||||
func updateStateFromMove(fromIdx: int, toIdx: int) -> void:
|
||||
# Update game state based on the move
|
||||
isWhiteToMove = !isWhiteToMove
|
||||
if isWhiteToMove:
|
||||
moveCount += 1
|
||||
|
||||
# Update castling rights if needed
|
||||
updateCastlingRights(fromIdx, toIdx)
|
||||
|
||||
# Update en passant target
|
||||
updateEnPassantTarget(fromIdx, toIdx)
|
||||
|
||||
# Update halfmove clock
|
||||
updateHalfMoveClock(fromIdx, toIdx)
|
||||
|
||||
func updateCastlingRights(fromIdx: int, toIdx: int) -> void:
|
||||
var piece = board[fromIdx]
|
||||
if piece == null:
|
||||
return
|
||||
|
||||
# Remove castling rights when king or rook moves
|
||||
match piece.type:
|
||||
"king":
|
||||
if piece.isWhite:
|
||||
castlingRights = castlingRights.replace("K", "").replace("Q", "")
|
||||
else:
|
||||
castlingRights = castlingRights.replace("k", "").replace("q", "")
|
||||
"rook":
|
||||
var startRank = 7 if piece.isWhite else 0
|
||||
if fromIdx == startRank * 8: # Queen-side rook
|
||||
castlingRights = castlingRights.replace("Q" if piece.isWhite else "q", "")
|
||||
elif fromIdx == startRank * 8 + 7: # King-side rook
|
||||
castlingRights = castlingRights.replace("K" if piece.isWhite else "k", "")
|
||||
|
||||
if castlingRights == "":
|
||||
castlingRights = "-"
|
||||
|
||||
func updateEnPassantTarget(fromIdx: int, toIdx: int) -> void:
|
||||
var piece = board[fromIdx]
|
||||
if piece == null or piece.type != "pawn":
|
||||
enPassantTarget = "-"
|
||||
return
|
||||
|
||||
# Check for double pawn move
|
||||
var fromRank = fromIdx / 8
|
||||
var toRank = toIdx / 8
|
||||
if abs(fromRank - toRank) == 2:
|
||||
var file = fromIdx % 8
|
||||
var targetRank = (fromRank + toRank) / 2
|
||||
enPassantTarget = "%s%d" % [char(97 + file), 8 - targetRank]
|
||||
else:
|
||||
enPassantTarget = "-"
|
||||
|
||||
func updateHalfMoveClock(fromIdx: int, toIdx: int) -> void:
|
||||
var piece = board[fromIdx]
|
||||
if piece == null:
|
||||
return
|
||||
|
||||
# Reset on pawn move or capture
|
||||
if piece.type == "pawn" or board[toIdx] != null:
|
||||
halfMoveClock = 0
|
||||
else:
|
||||
halfMoveClock += 1
|
||||
|
||||
|
||||
func _on_ai_move_generated(move: String) -> void:
|
||||
if Turn == 1: # Only process AI moves during black's turn
|
||||
# The move will be automatically handled by the Movement state
|
||||
# which is listening for the moveGenerated signal
|
||||
pass
|
||||
|
||||
func executeAiMove(fromLocation: String, toLocation: String) -> void:
|
||||
selectedNode = fromLocation
|
||||
executeMove(toLocation)
|
||||
|
||||
func convertNotationToLocation(notation: String) -> String:
|
||||
var file = notation[0].unicode_at(0) - 'a'.unicode_at(0)
|
||||
var rank = 8 - int(notation[1])
|
||||
return str(file) + "-" + str(rank)
|
||||
|
|
|
|||
|
|
@ -78,4 +78,5 @@ func get_overlay(overlay_name: String) -> Node:
|
|||
return null
|
||||
|
||||
func has_piece() -> bool:
|
||||
return piece != null
|
||||
return piece != null
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ extends "res://Systems/StateMachine/ChessGameState.gd"
|
|||
func enter(_previous: String, _data := {}) -> void:
|
||||
print("ENTERING STATE ", Constants.TILE_EFFECTS)
|
||||
game.applyTileEffects()
|
||||
finished.emit(Constants.PRE_MOVE)
|
||||
finished.emit(Constants.EVALUATE_POSITION)
|
||||
|
|
@ -1,6 +1,31 @@
|
|||
extends "res://Systems/StateMachine/ChessGameState.gd"
|
||||
|
||||
|
||||
var moveTimer: Timer
|
||||
|
||||
func _ready() -> void:
|
||||
moveTimer = Timer.new()
|
||||
moveTimer.one_shot = true # Timer only fires once
|
||||
moveTimer.connect("timeout", _on_move_timer_timeout)
|
||||
add_child(moveTimer)
|
||||
|
||||
func enter(_previous: String, _data := {}) -> void:
|
||||
print("ENTERING STATE ", Constants.BLACK_TURN)
|
||||
game.currentPlayer = game.BLACK
|
||||
finished.emit(Constants.HAND_SETUP)
|
||||
|
||||
# Delay to avoid duplication during animation
|
||||
if game.stockfishController:
|
||||
moveTimer.start(2)
|
||||
|
||||
func _on_move_timer_timeout() -> void:
|
||||
# Generate AI move after delay
|
||||
print("------------------GENERATING MOVE --------------------")
|
||||
if game.stockfishController:
|
||||
print("------------------STARTING GENERATING MOVE --------------------")
|
||||
game.stockfishController.generateMove(1000) # 1 second think time
|
||||
finished.emit(Constants.HAND_SETUP)
|
||||
|
||||
func exit() -> void:
|
||||
moveTimer.stop()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,19 @@ var multiMoving = ""
|
|||
func _ready() -> void:
|
||||
print("Movement state ready")
|
||||
|
||||
func _setup_movement_modifiers() -> void:
|
||||
for piece_id in game.deckManager.attached_cards:
|
||||
var card = game.deckManager.attached_cards[piece_id]
|
||||
if card.effectType == Card.EffectType.MOVEMENT_MODIFIER:
|
||||
var effects = card.modify_moves()
|
||||
moves_remaining[piece_id] = effects.get("extra_moves", 0) + 1
|
||||
|
||||
|
||||
func enter(_previous: String, _data := {}) -> void:
|
||||
print("ENTERING STATE ", Constants.MOVEMENT)
|
||||
print("ENTERING STATE ", Constants.MOVEMENT, " ", game.currentPlayer)
|
||||
|
||||
|
||||
_setup_movement_modifiers()
|
||||
if !game.boardContainer.is_connected("tile_pressed", handleMovement):
|
||||
game.boardContainer.connect("tile_pressed", handleMovement)
|
||||
if game.selectedNode != "":
|
||||
|
|
@ -31,16 +42,49 @@ func enter(_previous: String, _data := {}) -> void:
|
|||
moves_remaining[piece_id] += effects.get("extra_moves", 0)
|
||||
else:
|
||||
moves_remaining[piece_id] = effects.get("extra_moves", 0) + 1
|
||||
|
||||
if game.currentPlayer == game.BLACK and game.stockfishController:
|
||||
var move = game.stockfishController.getGeneratedMove()
|
||||
print("GENERATED MOVE ", move)
|
||||
if move:
|
||||
var move_str = move.move # e.g., "e2e4"
|
||||
var source_square = move_str.substr(0, 2) # "e2"
|
||||
var target_square = move_str.substr(2, 2) # "e4"
|
||||
|
||||
# First select the piece
|
||||
var source_location = convert_algebraic_to_location(source_square)
|
||||
game.selectedNode = source_location
|
||||
print("source_location ", source_location)
|
||||
|
||||
# Then make the move
|
||||
var target_location = convert_algebraic_to_location(target_square)
|
||||
print("target_location ", target_location)
|
||||
handleMovement(target_location, true)
|
||||
return
|
||||
|
||||
func exit() -> void:
|
||||
if game.boardContainer.is_connected("tile_pressed", handleMovement):
|
||||
game.boardContainer.disconnect("tile_pressed", handleMovement)
|
||||
|
||||
func handleMovement(location: String) -> void:
|
||||
|
||||
func convert_algebraic_to_location(square: String) -> String:
|
||||
var file = square[0] # letter (a-h)
|
||||
var rank = int(square[1]) # number (1-8)
|
||||
|
||||
# Convert file letter to number (a=0, b=1, etc)
|
||||
var file_num = file.unicode_at(0) - 'a'.unicode_at(0)
|
||||
|
||||
# Convert rank to 0-based index from bottom
|
||||
var rank_num = rank - 1
|
||||
|
||||
# Return location in your game's format
|
||||
return "%d-%d" % [file_num, rank_num]
|
||||
|
||||
func handleMovement(location: String, generated: bool = false) -> void:
|
||||
# we need to prevent swapping of focus between peices after the double move process has started
|
||||
# maybe once u start nmoving a peice global stat var is set
|
||||
# and any moving peice needs ot match that
|
||||
# print("HANDLING MOVEMENT ", location, " | ", multiMoving, " | ", game.selectedNode)
|
||||
print("HANDLING MOVEMENT ", location, " | ", multiMoving, " | ", game.selectedNode)
|
||||
var node = game.get_node("Flow/" + location) as PieceContainer
|
||||
|
||||
# Only try to get piece if we have a selected node
|
||||
|
|
@ -89,17 +133,16 @@ func handleMovement(location: String) -> void:
|
|||
if piece_id in moves_remaining:
|
||||
moves_remaining.erase(piece_id)
|
||||
# finished.emit(Constants.POST_MOVE)
|
||||
|
||||
if game.selectedNode == location:
|
||||
if !is_multi_moving and multiMoving == "":
|
||||
print("CLEAR SELECTION*************")
|
||||
game.clearSelection()
|
||||
elif isCastlingMove(node, location):
|
||||
handleCastling(node)
|
||||
handleCastling(node, generated)
|
||||
finished.emit(Constants.POST_MOVE)
|
||||
# En Passant
|
||||
elif isEnPassantMove(node, location):
|
||||
handleEnPassant(node)
|
||||
handleEnPassant(node, generated)
|
||||
# Reselect piece
|
||||
elif isReselectMove(node):
|
||||
if !is_multi_moving and multiMoving == "":
|
||||
|
|
@ -108,17 +151,17 @@ func handleMovement(location: String) -> void:
|
|||
game.getMovableAreas()
|
||||
# Capture piece
|
||||
elif isCaptureMove(node):
|
||||
handleCapture(node)
|
||||
handleCapture(node, generated)
|
||||
finished.emit(Constants.POST_MOVE)
|
||||
# Regular move
|
||||
# elif isRegularMove(node):
|
||||
# handleRegularMove(node)
|
||||
# finished.emit(Constants.POST_MOVE)
|
||||
else:
|
||||
if game.isValidMove(location):
|
||||
if game.isValidMove(location) || generated:
|
||||
# executeMove(location)
|
||||
|
||||
handleRegularMove(node, consumeMove)
|
||||
handleRegularMove(node, consumeMove, generated)
|
||||
if consumeMove:
|
||||
multiMoving = ""
|
||||
game.clearSelection()
|
||||
|
|
@ -167,86 +210,107 @@ func isCaptureMove(node: PieceContainer) -> bool:
|
|||
func isRegularMove(node: PieceContainer) -> bool:
|
||||
return game.selectedNode != "" && node.get_piece() != null
|
||||
|
||||
func handleCastling(node: PieceContainer) -> void:
|
||||
func handleCastling(node: PieceContainer, generated: bool = false) -> void:
|
||||
print("handleCastling")
|
||||
if generated:
|
||||
castleMovement(node)
|
||||
return
|
||||
for i in game.areas:
|
||||
if i == node.name:
|
||||
var kingContainer = game.get_node("Flow/" + game.selectedNode) as PieceContainer
|
||||
var rookContainer = node as PieceContainer
|
||||
var kingTargetContainer = game.get_node("Flow/" + game.specialArea[1]) as PieceContainer
|
||||
var rookTargetContainer = game.get_node("Flow/" + game.specialArea[0]) as PieceContainer
|
||||
castleMovement(node)
|
||||
func castleMovement(node: PieceContainer) -> void:
|
||||
var kingContainer = game.get_node("Flow/" + game.selectedNode) as PieceContainer
|
||||
var rookContainer = node as PieceContainer
|
||||
var kingTargetContainer = game.get_node("Flow/" + game.specialArea[1]) as PieceContainer
|
||||
var rookTargetContainer = game.get_node("Flow/" + game.specialArea[0]) as PieceContainer
|
||||
|
||||
var king = kingContainer.get_piece()
|
||||
var rook = rookContainer.get_piece()
|
||||
var king = kingContainer.get_piece()
|
||||
var rook = rookContainer.get_piece()
|
||||
|
||||
# kingContainer.remove_piece(true)
|
||||
# rookContainer.remove_piece(true)
|
||||
# kingTargetContainer.set_piece(king)
|
||||
# rookTargetContainer.set_piece(rook)
|
||||
# kingContainer.remove_piece(true)
|
||||
# rookContainer.remove_piece(true)
|
||||
# kingTargetContainer.set_piece(king)
|
||||
# rookTargetContainer.set_piece(rook)
|
||||
|
||||
kingTargetContainer.animate_movement(kingContainer, king);
|
||||
kingTargetContainer.animate_movement(kingContainer, king);
|
||||
|
||||
rookTargetContainer.animate_movement(rookContainer, rook);
|
||||
rookTargetContainer.animate_movement(rookContainer, rook);
|
||||
|
||||
|
||||
|
||||
game.currentlyMovingPiece = king
|
||||
game.resolveMoveEffects()
|
||||
game.currentlyMovingPiece = king
|
||||
game.resolveMoveEffects()
|
||||
|
||||
func handleEnPassant(node: PieceContainer) -> void:
|
||||
func handleEnPassant(node: PieceContainer, generated: bool = false) -> void:
|
||||
print("handleEnPassant")
|
||||
for i in game.specialArea:
|
||||
if generated:
|
||||
handleEnPassantMovement(node)
|
||||
return
|
||||
for i in game.areas:
|
||||
if i == node.name:
|
||||
var targetContainer = game.get_node("Flow/" + game.selectedNode) as PieceContainer
|
||||
var pawn = (game.get_node("Flow/" + game.selectedNode) as PieceContainer).get_piece()
|
||||
# node.remove_piece()
|
||||
# targetContainer.set_piece(pawn)
|
||||
game.currentlyMovingPiece = pawn
|
||||
handleEnPassantMovement(node)
|
||||
|
||||
|
||||
targetContainer.animate_movement(node, pawn);
|
||||
game.resolveMoveEffects()
|
||||
func handleEnPassantMovement(node: PieceContainer) -> void:
|
||||
var targetContainer = game.get_node("Flow/" + game.selectedNode) as PieceContainer
|
||||
var pawn = (game.get_node("Flow/" + game.selectedNode) as PieceContainer).get_piece()
|
||||
# node.remove_piece()
|
||||
# targetContainer.set_piece(pawn)
|
||||
game.currentlyMovingPiece = pawn
|
||||
|
||||
func handleCapture(node: PieceContainer) -> void:
|
||||
|
||||
targetContainer.animate_movement(node, pawn);
|
||||
game.resolveMoveEffects()
|
||||
|
||||
func handleCapture(node: PieceContainer, generated: bool = false) -> void:
|
||||
print("handleCapture")
|
||||
if generated:
|
||||
handleCaptureMovement(node)
|
||||
return
|
||||
for i in game.areas:
|
||||
if i == node.name:
|
||||
|
||||
|
||||
var source_container = game.get_node("Flow/" + game.selectedNode) as PieceContainer
|
||||
|
||||
|
||||
var moving_piece = source_container.get_piece()
|
||||
var captured_piece = node.get_piece()
|
||||
|
||||
if moving_piece && captured_piece:
|
||||
await game.animatePieceCapture(captured_piece)
|
||||
game.updatePointsAndCapture(captured_piece, false)
|
||||
node.animate_movement(source_container, moving_piece);
|
||||
var tile = game.tileManager.get_tile(node.name)
|
||||
if tile:
|
||||
tile.apply_effect(moving_piece)
|
||||
handleCaptureMovement(node)
|
||||
|
||||
|
||||
game.currentlyMovingPiece = moving_piece
|
||||
game.resolveMoveEffects()
|
||||
func handleCaptureMovement(node: PieceContainer) -> void:
|
||||
var source_container = game.get_node("Flow/" + game.selectedNode) as PieceContainer
|
||||
|
||||
|
||||
var moving_piece = source_container.get_piece()
|
||||
var captured_piece = node.get_piece()
|
||||
|
||||
if moving_piece && captured_piece:
|
||||
await game.animatePieceCapture(captured_piece)
|
||||
game.updatePointsAndCapture(captured_piece, false)
|
||||
node.animate_movement(source_container, moving_piece);
|
||||
var tile = game.tileManager.get_tile(node.name)
|
||||
if tile:
|
||||
tile.apply_effect(moving_piece)
|
||||
|
||||
func handleRegularMove(node: PieceContainer, consume: bool) -> void:
|
||||
|
||||
game.currentlyMovingPiece = moving_piece
|
||||
game.resolveMoveEffects()
|
||||
|
||||
|
||||
func handleRegularMove(node: PieceContainer, consume: bool, generated: bool = false) -> void:
|
||||
print("handleRegularMove", node, game.selectedNode)
|
||||
if generated:
|
||||
moveAndConsume(node, consume)
|
||||
return
|
||||
for i in game.areas:
|
||||
if i == node.name:
|
||||
print(i)
|
||||
var sourceContainer = game.get_node("Flow/" + game.selectedNode) as PieceContainer
|
||||
var piece = sourceContainer.get_piece()
|
||||
print("Removing Piece 1")
|
||||
node.animate_movement(sourceContainer, piece);
|
||||
game.currentlyMovingPiece = piece
|
||||
if consume:
|
||||
game.resolveMoveEffects()
|
||||
else:
|
||||
game.togglePieceChessEffect()
|
||||
|
||||
moveAndConsume(node, consume)
|
||||
|
||||
func moveAndConsume(node: PieceContainer, consume: bool) -> void:
|
||||
var sourceContainer = game.get_node("Flow/" + game.selectedNode) as PieceContainer
|
||||
var piece = sourceContainer.get_piece()
|
||||
print("Removing Piece 1")
|
||||
node.animate_movement(sourceContainer, piece);
|
||||
game.currentlyMovingPiece = piece
|
||||
if consume:
|
||||
game.resolveMoveEffects()
|
||||
else:
|
||||
game.togglePieceChessEffect()
|
||||
|
||||
|
||||
func executeMove(targetLocation: String) -> void:
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@ func enter(_previous: String, _data := {}) -> void:
|
|||
game.updateEffectDurations()
|
||||
# if (game.isPlayerTurn()):
|
||||
# game.deckManager.updateCardDurations()
|
||||
finished.emit(Constants.EVALUATE_POSITION)
|
||||
finished.emit(Constants.TILE_EFFECTS)
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ extends "res://Systems/StateMachine/ChessGameState.gd"
|
|||
func enter(_previous: String, _data := {}) -> void:
|
||||
print("ENTERING STATE ", Constants.PERSISTENT_EFFECTS)
|
||||
|
||||
finished.emit(Constants.TILE_EFFECTS)
|
||||
finished.emit(Constants.PRE_MOVE)
|
||||
|
|
|
|||
|
|
@ -27,13 +27,6 @@ offset_bottom = -5.0
|
|||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_fkb2r")
|
||||
boardXSize = null
|
||||
boardYSize = null
|
||||
tileXSize = null
|
||||
tileYSize = null
|
||||
windowXSize = null
|
||||
windowYSize = null
|
||||
FEN = null
|
||||
|
||||
[node name="Flow" type="FlowContainer" parent="."]
|
||||
layout_mode = 1
|
||||
|
|
|
|||
|
|
@ -33,4 +33,4 @@ import/blender/enabled=false
|
|||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method="mobile"
|
||||
|
|
|
|||
Loading…
Reference in a new issue