Refactored Game to use StateMachine

This commit is contained in:
2ManyProjects 2025-01-26 00:46:15 -06:00
parent 376bf912c7
commit 08e27e9268
29 changed files with 731 additions and 354 deletions

214
Game.gd
View file

@ -1,214 +0,0 @@
extends Control
const CardDisplay = preload("res://Systems/CardDisplay.gd")
var Selected_Node = ""
var Turn = 0
var Location_X = ""
var Location_Y = ""
var turn_indicator: ColorRect
var p1String: RichTextLabel
var p2String: RichTextLabel
var p1Points = 0
var p2Points = 0
var pos = Vector2(25, 25)
var Areas: PackedStringArray
# this is seperate the Areas for special circumstances, like castling.
var Special_Area: PackedStringArray
var light_style = StyleBoxFlat.new()
var dark_style = StyleBoxFlat.new()
var highlight_style = StyleBoxFlat.new()
var deck_manager: DeckManager
var card_display: CardDisplay
var has_moved = false # Track if piece has moved this turn
var currently_moving_piece = null
func _ready():
deck_manager = DeckManager.new()
card_display = CardDisplay.new()
add_child(deck_manager)
add_child(card_display)
card_display.update_hand(deck_manager.hand)
deck_manager.connect("hand_updated", func(hand): card_display.update_hand(hand))
light_style.bg_color = Color(0.8, 0.8, 0.8, 1)
dark_style.bg_color = Color(0.2, 0.2, 0.2, 1)
highlight_style.bg_color = Color(0, 0.3, 0, 1)
# Get reference to the turn indicator
turn_indicator = $TurnIndicator
p1String = $Player1Points
p2String = $Player2Points
p1String.text = "0"
p2String.text = "0"
# Set initial color for white's turn
update_turn_indicator()
func update_turn_indicator():
if Turn == 0: # White's turn
turn_indicator.color = Color(1, 1, 1, 1) # White
else: # Black's turn
turn_indicator.color = Color(0, 0, 0, 1) # Black
func reset_highlights():
var Flow = get_node("Flow")
for button in Flow.get_children():
var coord = button.name.split("-")
var isWhiteSquare = (int(coord[0]) + int(coord[1])) % 2 == 0
if isWhiteSquare:
button.add_theme_stylebox_override("normal", light_style)
else:
button.add_theme_stylebox_override("normal", dark_style)
func _on_flow_send_location(location: String):
if Selected_Node != "" && Selected_Node == location:
reset_highlights()
Selected_Node = ""
return
# variables for later
var number = 0
Location_X = ""
var node = get_node("Flow/" + location)
# This is to try and grab the X and Y coordinates from the board
while location.substr(number, 1) != "-":
Location_X += location.substr(number, 1)
number += 1
Location_Y = location.substr(number + 1)
# Now... we need to figure out how to select the pieces. If there is a valid move, do stuff.
# If we re-select, just go to that other piece
if Selected_Node == "" && node.get_child_count() != 0 && node.get_child(0).Item_Color == Turn:
Selected_Node = location
Get_Moveable_Areas()
elif Selected_Node != "" && node.get_child_count() != 0 && node.get_child(0).Item_Color == Turn && node.get_child(0).name == "Rook":
# Castling
for i in Areas:
if i == node.name:
var king = get_node("Flow/" + Selected_Node).get_child(0)
var rook = node.get_child(0)
# Using a seperate array because Areas wouldn't be really consistant...
king.reparent(get_node("Flow/" + Special_Area[1]))
rook.reparent(get_node("Flow/" + Special_Area[0]))
king.position = pos
rook.position = pos
# We have to get the parent because it will break lmao.
Update_Game(king.get_parent())
# En Passant
elif Selected_Node != "" && node.get_child_count() != 0 && node.get_child(0).Item_Color != Turn && node.get_child(0).name == "Pawn" && Special_Area.size() != 0 && Special_Area[0] == node.name && node.get_child(0).get("En_Passant") == true:
for i in Special_Area:
if i == node.name:
var pawn = get_node("Flow/" + Selected_Node).get_child(0)
node.get_child(0).free()
pawn.reparent(get_node("Flow/" + Special_Area[1]))
pawn.position = pos
Update_Game(pawn.get_parent())
elif Selected_Node != "" && node.get_child_count() != 0 && node.get_child(0).Item_Color == Turn:
# Re-select
Selected_Node = location
Get_Moveable_Areas()
elif Selected_Node != "" && node.get_child_count() != 0 && node.get_child(0).Item_Color != Turn:
# Taking over a piece
for i in Areas:
if i == node.name:
var Piece = get_node("Flow/" + Selected_Node).get_child(0)
var captured_piece = node.get_child(0)
# Add points to the capturing player
if Turn == 0: # White's turn
p1Points += captured_piece.Points
p1String.text = str(p1Points)
else: # Black's turn
p2Points += captured_piece.Points
p2String.text = str(p2Points)
# Win conditions
if captured_piece.name == "King":
print("Damn, you win!")
node.get_child(0).free()
Piece.reparent(node)
Piece.position = pos
Update_Game(node)
elif Selected_Node != "" && node.get_child_count() == 0:
# Moving a piece
for i in Areas:
if i == node.name:
var Piece = get_node("Flow/" + Selected_Node).get_child(0)
Piece.reparent(node)
Piece.position = pos
Update_Game(node)
func Update_Game(node):
Selected_Node = ""
if Turn == 0:
Turn = 1
else:
Turn = 0
update_turn_indicator()
reset_highlights();
deck_manager.update_card_durations()
has_moved = false
currently_moving_piece = null
var Flow = get_node("Flow")
# get the en-passantable pieces and undo them
var things = Flow.get_children()
for i in things:
if i.get_child_count() != 0 && i.get_child(0).name == "Pawn" && i.get_child(0).Item_Color == Turn && i.get_child(0).En_Passant == true:
i.get_child(0).set("En_Passant", false)
# Remove the abilities once they are either used or not used
if node.get_child(0).name == "Pawn":
if node.get_child(0).Double_Start == true:
node.get_child(0).En_Passant = true
node.get_child(0).Double_Start = false
if node.get_child(0).name == "King":
node.get_child(0).Castling = false
if node.get_child(0).name == "Rook":
node.get_child(0).Castling = false
# Below is the movement that is used for the pieces
func Get_Moveable_Areas():
var Flow = get_node("Flow")
for button in Flow.get_children():
var coord = button.name.split("-")
var isWhiteSquare = (int(coord[0]) + int(coord[1])) % 2 == 0
if isWhiteSquare:
button.add_theme_stylebox_override("normal", light_style)
else:
button.add_theme_stylebox_override("normal", dark_style)
# Clearing the arrays
Areas.clear()
Special_Area.clear()
var Piece = get_node("Flow/" + Selected_Node).get_child(0)
# For the selected piece that we have, we can get the movement that we need here.
var moves = Piece.get_valid_moves(Flow, Selected_Node)
Areas = moves.regular_moves
Special_Area = moves.special_moves
# Highlight valid moves
for move in Areas:
var button = Flow.get_node(move)
var isWhiteSquare = (int(move.split("-")[0]) + int(move.split("-")[1])) % 2 == 0
var baseStyle = dark_style
if isWhiteSquare:
baseStyle = light_style
var combinedStyle = StyleBoxFlat.new()
combinedStyle.bg_color = baseStyle.bg_color + highlight_style.bg_color
button.add_theme_stylebox_override("normal", combinedStyle)
# One function that shortens everything. Its also a pretty good way to see if we went off the board or not.
func Is_Null(Location):
if get_node_or_null("Flow/" + Location) == null:
return true
else:
return false

View file

@ -1,106 +0,0 @@
extends FlowContainer
@export var Board_X_Size = 8
@export var Board_Y_Size = 8
@export var Tile_X_Size: int = 50
@export var Tile_Y_Size: int = 50
signal send_location
func _ready():
# stop negative numbers from happening
if Board_X_Size < 0 || Board_Y_Size < 0:
return
var Number_X = 0
var Number_Y = 0
var is_white = true
var light_style = StyleBoxFlat.new()
light_style.bg_color = Color(0.8, 0.8, 0.8, 1)
var dark_style = StyleBoxFlat.new()
dark_style.bg_color = Color(0.2, 0.2, 0.2, 1)
# Set up the board
while Number_Y != Board_Y_Size:
self.size.y += Tile_Y_Size + 5
self.size.x += Tile_X_Size + 5
while Number_X != Board_X_Size:
var temp = Button.new()
temp.set_custom_minimum_size(Vector2(Tile_X_Size, Tile_Y_Size))
if is_white:
temp.add_theme_stylebox_override("normal", light_style)
else:
temp.add_theme_stylebox_override("normal", dark_style)
is_white = !is_white
temp.connect("pressed", func():
emit_signal("send_location", temp.name))
temp.set_name(str(Number_X) + "-" + str(Number_Y))
add_child(temp)
Number_X += 1
is_white = !is_white
Number_Y += 1
Number_X = 0
Regular_Game()
func Regular_Game():
get_node("0-0").add_child(Summon("Rook", 1))
get_node("1-0").add_child(Summon("Knight", 1))
get_node("2-0").add_child(Summon("Bishop", 1))
get_node("3-0").add_child(Summon("Queen", 1))
get_node("4-0").add_child(Summon("King", 1))
get_node("5-0").add_child(Summon("Bishop", 1))
get_node("6-0").add_child(Summon("Knight", 1))
get_node("7-0").add_child(Summon("Rook", 1))
get_node("0-1").add_child(Summon("Pawn", 1))
get_node("1-1").add_child(Summon("Pawn", 1))
get_node("2-1").add_child(Summon("Pawn", 1))
get_node("3-1").add_child(Summon("Pawn", 1))
get_node("4-1").add_child(Summon("Pawn", 1))
get_node("5-1").add_child(Summon("Pawn", 1))
get_node("6-1").add_child(Summon("Pawn", 1))
get_node("7-1").add_child(Summon("Pawn", 1))
get_node("0-7").add_child(Summon("Rook", 0))
get_node("1-7").add_child(Summon("Knight", 0))
get_node("2-7").add_child(Summon("Bishop", 0))
get_node("3-7").add_child(Summon("Queen", 0))
get_node("4-7").add_child(Summon("King", 0))
get_node("5-7").add_child(Summon("Bishop", 0))
get_node("6-7").add_child(Summon("Knight", 0))
get_node("7-7").add_child(Summon("Rook", 0))
get_node("0-6").add_child(Summon("Pawn", 0))
get_node("1-6").add_child(Summon("Pawn", 0))
get_node("2-6").add_child(Summon("Pawn", 0))
get_node("3-6").add_child(Summon("Pawn", 0))
get_node("4-6").add_child(Summon("Pawn", 0))
get_node("5-6").add_child(Summon("Pawn", 0))
get_node("6-6").add_child(Summon("Pawn", 0))
get_node("7-6").add_child(Summon("Pawn", 0))
func Summon(Piece_Name: String, color: int):
var Piece
match Piece_Name:
"Pawn":
Piece = Pawn.new()
Piece.name = "Pawn"
"King":
Piece = King.new()
Piece.name = "King"
"Queen":
Piece = Queen.new()
Piece.name = "Queen"
"Knight":
Piece = Knight.new()
Piece.name = "Knight"
"Rook":
Piece = Rook.new()
Piece.name = "Rook"
"Bishop":
Piece = Bishop.new()
Piece.name = "Bishop"
Piece.Item_Color = color
Piece.position = Vector2(Tile_X_Size / 2, Tile_Y_Size / 2)
return Piece

View file

@ -16,27 +16,27 @@ const CARD_BASE_COSTS = {
}
func _init():
initialize_starting_deck()
initializeStartingDeck()
func initialize_starting_deck():
func initializeStartingDeck():
# Add basic Rank 3 and 4 cards as per design doc
for i in range(10):
deck.append(Card.new()) # Basic movement cards
shuffle_deck()
draw_starting_hand()
shuffleDeck()
drawStartingHand()
func shuffle_deck():
func shuffleDeck():
deck.shuffle()
func draw_starting_hand():
func drawStartingHand():
for i in range(min(hand_size, deck.size())):
draw_card()
drawCard()
func draw_card():
func drawCard():
if deck.is_empty() && !discard.is_empty():
deck = discard.duplicate()
discard.clear()
shuffle_deck()
shuffleDeck()
if !deck.is_empty() && hand.size() < hand_size:
hand.append(deck.pop_back())
@ -46,7 +46,7 @@ signal hand_updated
func play_card(card: Card, target_piece: Pawn, board_flow = null, game_state = null):
func playCard(card: Card, target_piece: Pawn, board_flow = null, game_state = null):
if !hand.has(card):
return false
emit_signal("hand_updated", hand)
@ -65,7 +65,7 @@ func play_card(card: Card, target_piece: Pawn, board_flow = null, game_state = n
discard.append(card)
Card.Rank.RANK_3:
deck.append(card)
shuffle_deck()
shuffleDeck()
if card.duration > 0:
attached_cards[target_piece.get_instance_id()] = card
@ -73,7 +73,7 @@ func play_card(card: Card, target_piece: Pawn, board_flow = null, game_state = n
return true
return false
func update_card_durations():
func updateCardDurations():
var expired_cards = []
for piece_id in attached_cards:
var card = attached_cards[piece_id]
@ -85,22 +85,22 @@ func update_card_durations():
attached_cards.erase(piece_id)
# Shop functionality
func get_shop_cards(num_cards: int = 3) -> Array:
func getShopCards(num_cards: int = 3) -> Array:
var shop_cards = []
# Generate random shop selection
#for i in range(num_cards):
#var card = generate_random_card()
#shop_cards.append({
#"card": card,
#"cost": calculate_card_cost(card)
#"cost": calculateCardCost(card)
#})
return shop_cards
func calculate_card_cost(card: Card) -> int:
func calculateCardCost(card: Card) -> int:
var base_cost = CARD_BASE_COSTS[card.rank]
# Add modifiers based on card effects
return base_cost
func upgrade_card(card: Card) -> bool:
func upgradeCard(card: Card) -> bool:
# Implement card upgrading logic
return false

465
Systems/Game/ChessGame.gd Normal file
View file

@ -0,0 +1,465 @@
class_name ChessGame extends Control
const WHITE = "white"
const BLACK = "black"
var currentPlayer: String = WHITE
var board: Array
var activeEffects: Array
var currentHand: Array
var selectedNode: String = ""
var locationX: String = ""
var locationY: String = ""
var areas: PackedStringArray
var specialArea: PackedStringArray
var hasMoved: bool = false
var currentlyMovingPiece = null
var p1Points: int = 0
var p2Points: int = 0
var Turn: int = 0
@onready var turnIndicator: ColorRect = $TurnIndicator
@onready var p1String: RichTextLabel = $Player1Points
@onready var p2String: RichTextLabel = $Player2Points
@onready var deckManager: DeckManager
@onready var cardDisplay: CardDisplay
@export var boardXSize = 8
@export var boardYSize = 8
@export var tileXSize: int = 50
@export var tileYSize: int = 50
@onready var boardContainer: FlowContainer = $Flow
@onready var stateMachine: StateMachine = $StateMachine
var lightStyle = null
var darkStyle = null
var highlightStyle = null
func _ready() -> void:
initializeGame()
func _unhandled_input(event: InputEvent) -> void:
stateMachine.unhandledInput(event)
func _process(delta: float) -> void:
stateMachine.process(delta)
func initializeGame() -> void:
setupStyles()
initializeBoard()
setupUI()
initializeDeckSystem()
# func initializeBoard() -> void:
# setupStyles()
# if boardXSize < 0 || boardYSize < 0:
# return
# var numberX = 0
# var numberY = 0
# var isWhite = true
# board = []
# for i in range(8):
# var row = []
# for j in range(8):
# row.append(null)
# board.append(row)
# while numberY != boardYSize:
# boardContainer.size.y += tileYSize + 5
# boardContainer.size.x += tileXSize + 5
# while numberX != boardXSize:
# var tile = Button.new()
# tile.set_custom_minimum_size(Vector2(tileXSize, tileYSize))
# if isWhite:
# tile.add_theme_stylebox_override("normal", lightStyle)
# else:
# tile.add_theme_stylebox_override("normal", darkStyle)
# isWhite = !isWhite
# tile.pressed.connect(func(): _onTilePressed(tile.name))
# tile.set_name(str(numberX) + "-" + str(numberY))
# boardContainer.add_child(tile)
# numberX += 1
# isWhite = !isWhite
# numberY += 1
# numberX = 0
# setupPieces()
# updateTurnIndicator()
func initializeBoard() -> void:
board = []
for i in range(8):
var row = []
for j in range(8):
row.append(null)
board.append(row)
createBoard()
setupPieces()
func setupUI() -> void:
p1String.text = "0"
p2String.text = "0"
updateTurnIndicator()
func initializeDeckSystem() -> void:
deckManager = DeckManager.new()
cardDisplay = CardDisplay.new()
add_child(deckManager)
add_child(cardDisplay)
cardDisplay.update_hand(deckManager.hand)
deckManager.connect("hand_updated", func(hand): cardDisplay.update_hand(hand))
func createBoard() -> void:
boardContainer.add_to_group("Flow")
var numberX = 0
var numberY = 0
var isWhite = true
while numberY != boardYSize:
boardContainer.size.y += tileYSize + 5
boardContainer.size.x += tileXSize + 5
while numberX != boardXSize:
createTile(numberX, numberY, isWhite)
isWhite = !isWhite
numberX += 1
isWhite = !isWhite
numberY += 1
numberX = 0
func createTile(x: int, y: int, isWhite: bool) -> void:
# print("CreateTile x ", x, " y ", y);
var tile = Button.new()
tile.set_custom_minimum_size(Vector2(tileXSize, tileYSize))
tile.add_theme_stylebox_override("normal", lightStyle if isWhite else darkStyle)
tile.pressed.connect(func(): handleTileSelection(tile.name))
tile.set_name(str(x) + "-" + str(y))
boardContainer.add_child(tile)
func handleTileSelection(location: String) -> void:
# Deselect current piece
if selectedNode == location:
resetHighlights()
selectedNode = ""
return
var node = get_node("Flow/" + location)
parseLocation(location)
# First selection of a piece
if selectedNode == "" && node.get_child_count() != 0 && node.get_child(0).Item_Color == Turn:
selectedNode = location
getMovableAreas()
# Castling
elif isCastlingMove(node, location):
handleCastling(node)
# En Passant
elif isEnPassantMove(node, location):
handleEnPassant(node)
# Reselect piece
elif isReselectMove(node):
selectedNode = location
getMovableAreas()
# Capture piece
elif isCaptureMove(node):
handleCapture(node)
# Regular move
elif isRegularMove(node):
handleRegularMove(node)
func isCastlingMove(node: Node, location: String) -> bool:
return selectedNode != "" && node.get_child_count() != 0 && node.get_child(0).Item_Color == Turn && node.get_child(0).name == "Rook"
func isEnPassantMove(node: Node, location: String) -> bool:
return selectedNode != "" && node.get_child_count() != 0 && node.get_child(0).Item_Color != Turn && \
node.get_child(0).name == "Pawn" && specialArea.size() != 0 && specialArea[0] == node.name && \
node.get_child(0).get("En_Passant") == true
func isReselectMove(node: Node) -> bool:
return selectedNode != "" && node.get_child_count() != 0 && node.get_child(0).Item_Color == Turn
func isCaptureMove(node: Node) -> bool:
return selectedNode != "" && node.get_child_count() != 0 && node.get_child(0).Item_Color != Turn
func isRegularMove(node: Node) -> bool:
return selectedNode != "" && node.get_child_count() == 0
func handleCastling(node: Node) -> void:
print("handleCastling")
for i in areas:
if i == node.name:
var king = get_node("Flow/" + selectedNode).get_child(0)
var rook = node.get_child(0)
king.reparent(get_node("Flow/" + specialArea[1]))
rook.reparent(get_node("Flow/" + specialArea[0]))
king.position = Vector2(25, 25)
rook.position = Vector2(25, 25)
currentlyMovingPiece = king
resolveMoveEffects()
func handleEnPassant(node: Node) -> void:
print("handleEnPassant")
for i in specialArea:
if i == node.name:
var pawn = get_node("Flow/" + selectedNode).get_child(0)
node.get_child(0).free()
pawn.reparent(get_node("Flow/" + specialArea[1]))
pawn.position = Vector2(25, 25)
currentlyMovingPiece = pawn
resolveMoveEffects()
func handleCapture(node: Node) -> void:
print("handleCapture")
for i in areas:
if i == node.name:
var piece = get_node("Flow/" + selectedNode).get_child(0)
var capturedPiece = node.get_child(0)
updatePoints(capturedPiece)
if capturedPiece.name == "King":
print("Game Over!")
capturedPiece.free()
piece.reparent(node)
piece.position = Vector2(25, 25)
piece.position = Vector2(25, 25)
currentlyMovingPiece = piece
resolveMoveEffects()
func handleRegularMove(node: Node) -> void:
print("handleRegularMove")
for i in areas:
if i == node.name:
var piece = get_node("Flow/" + selectedNode).get_child(0)
piece.reparent(node)
piece.position = Vector2(25, 25)
currentlyMovingPiece = piece
resolveMoveEffects()
func updatePoints(capturedPiece: Node) -> void:
if Turn == 0:
p1Points += capturedPiece.Points
p1String.text = str(p1Points)
else:
p2Points += capturedPiece.Points
p2String.text = str(p2Points)
func parseLocation(location: String) -> void:
var number = 0
locationX = ""
while location.substr(number, 1) != "-":
locationX += location.substr(number, 1)
number += 1
locationY = location.substr(number + 1)
func setupStyles() -> void:
lightStyle = StyleBoxFlat.new()
lightStyle.bg_color = Color(0.8, 0.8, 0.8, 1)
darkStyle = StyleBoxFlat.new()
darkStyle.bg_color = Color(0.2, 0.2, 0.2, 1)
highlightStyle = StyleBoxFlat.new()
highlightStyle.bg_color = Color(0, 0.3, 0, 1)
func updateTurnIndicator():
if Turn == 0: # White's turn
turnIndicator.color = Color(1, 1, 1, 1) # White
else: # Black's turn
turnIndicator.color = Color(0, 0, 0, 1) # Black
func _onTilePressed(tileName: String) -> void:
boardContainer.emit_signal("send_location", tileName)
func setupPieces() -> void:
# White pieces
placePiece("0-0", "Rook", 1)
placePiece("1-0", "Knight", 1)
placePiece("2-0", "Bishop", 1)
placePiece("3-0", "Queen", 1)
placePiece("4-0", "King", 1)
placePiece("5-0", "Bishop", 1)
placePiece("6-0", "Knight", 1)
placePiece("7-0", "Rook", 1)
for x in range(8):
placePiece(str(x) + "-1", "Pawn", 1)
# Black pieces
placePiece("0-7", "Rook", 0)
placePiece("1-7", "Knight", 0)
placePiece("2-7", "Bishop", 0)
placePiece("3-7", "Queen", 0)
placePiece("4-7", "King", 0)
placePiece("5-7", "Bishop", 0)
placePiece("6-7", "Knight", 0)
placePiece("7-7", "Rook", 0)
for x in range(8):
placePiece(str(x) + "-6", "Pawn", 0)
func placePiece(position: String, pieceName: String, color: int) -> void:
var piece = summonPiece(pieceName, color)
boardContainer.get_node(position).add_child(piece)
var coords = position.split("-")
board[int(coords[1])][int(coords[0])] = piece
func summonPiece(pieceName: String, color: int) -> Node:
var piece
match pieceName:
"Pawn":
piece = Pawn.new()
piece.name = "Pawn"
"King":
piece = King.new()
piece.name = "King"
"Queen":
piece = Queen.new()
piece.name = "Queen"
"Knight":
piece = Knight.new()
piece.name = "Knight"
"Rook":
piece = Rook.new()
piece.name = "Rook"
"Bishop":
piece = Bishop.new()
piece.name = "Bishop"
piece.Item_Color = color
piece.position = Vector2(tileXSize / 2, tileYSize / 2)
return piece
func prepareHand() -> void:
pass
func drawCards() -> void:
pass
func updateEffectDurations() -> void:
pass
func applyTileEffects() -> void:
pass
func attachSelectedCards() -> void:
pass
func applyCardEffects() -> void:
pass
func isValidMove(location: String) -> bool:
var node = get_node("Flow/" + location)
if node.get_child_count() == 0 || node.get_child(0).Item_Color != Turn:
for area in areas:
if area == node.name:
return true
return false
func getMovableAreas() -> void:
resetHighlights()
areas.clear()
specialArea.clear()
var piece = get_node("Flow/" + selectedNode).get_child(0)
# print("Flow/" + selectedNode)
var flowNodes = get_tree().get_nodes_in_group("Flow")
# print("Flow nodes:", flowNodes)
var moves = piece.getValidMoves(boardContainer, selectedNode)
areas = moves.regular_moves
specialArea = moves.special_moves
highlightValidMoves()
func highlightValidMoves() -> void:
for move in areas:
var button = boardContainer.get_node(move)
var isWhiteSquare = (int(move.split("-")[0]) + int(move.split("-")[1])) % 2 == 0
var baseStyle = lightStyle if isWhiteSquare else darkStyle
var combinedStyle = StyleBoxFlat.new()
combinedStyle.bg_color = baseStyle.bg_color + highlightStyle.bg_color
button.add_theme_stylebox_override("normal", combinedStyle)
func executeMove(targetLocation: String) -> void:
print("executeMove")
var targetNode = get_node("Flow/" + targetLocation)
var piece = get_node("Flow/" + selectedNode).get_child(0)
print("piece", piece)
if targetNode.get_child_count() != 0:
var capturedPiece = targetNode.get_child(0)
if Turn == 0:
p1Points += capturedPiece.Points
p1String.text = str(p1Points)
else:
p2Points += capturedPiece.Points
p2String.text = str(p2Points)
capturedPiece.free()
piece.reparent(targetNode)
piece.position = Vector2(25, 25)
print("piece2", piece)
hasMoved = true
currentlyMovingPiece = piece
resetHighlights()
func resolveMoveEffects() -> void:
print("resolveMoveEffects")
print("currentlyMovingPiece", currentlyMovingPiece)
var piece = currentlyMovingPiece
if piece.name == "Pawn":
if piece.Double_Start:
piece.En_Passant = true
piece.Double_Start = false
elif piece.name == "King":
piece.Castling = false
elif piece.name == "Rook":
piece.Castling = false
selectedNode = ""
Turn = 1 if Turn == 0 else 0
updateTurnIndicator()
resetHighlights()
deckManager.updateCardDurations()
hasMoved = false
currentlyMovingPiece = null
func resetHighlights():
for button in boardContainer.get_children():
var coord = button.name.split("-")
var isWhiteSquare = (int(coord[0]) + int(coord[1])) % 2 == 0
if isWhiteSquare:
button.add_theme_stylebox_override("normal", lightStyle)
else:
button.add_theme_stylebox_override("normal", darkStyle)
func isCheckmate() -> bool:
return false
func isDraw() -> bool:
return false
func endGame(reason: String) -> void:
pass
func cleanupPhase() -> void:
pass
func isNull(location: String) -> bool:
return get_node_or_null("Flow/" + location) == null

View file

@ -0,0 +1,20 @@
class_name ChessGameState extends Node
signal finished(nextStatePath: String, data: Dictionary)
const ChessGame = preload("res://Systems/Game/ChessGame.gd")
@export var game: ChessGame
func _ready() -> void:
assert(game != null, "ChessGameState must have a ChessGame reference")
func enter(_previous: String, _data := {}) -> void:
pass
func exit() -> void:
pass
func handleInput(_event: InputEvent) -> void:
pass
func update(_delta: float) -> void:
pass

View file

@ -0,0 +1,17 @@
extends Node
const WHITE_TURN = "WhiteTurn"
const BLACK_TURN = "BlackTurn"
const HAND_SETUP = "HandSetup"
const DRAW_PHASE = "DrawPhase"
const PERSISTENT_EFFECTS = "ResolvePersistentEffects"
const TILE_EFFECTS = "ApplyTileEffects"
const PRE_MOVE = "PreMovePhase"
const ATTACH_CARDS = "AttachCards"
const APPLY_CARD_EFFECTS = "ApplyCardEffects"
const MOVEMENT = "Movement"
const POST_MOVE = "PostMovePhase"
const EVALUATE_POSITION = "EvaluatePosition"
const CLEANUP = "CleanupPhase"
const ROUND_END = "RoundEnd"

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.applyCardEffects()
finished.emit(Constants.MOVEMENT)

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.applyTileEffects()
finished.emit(Constants.PRE_MOVE)

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.attachSelectedCards()
finished.emit(Constants.APPLY_CARD_EFFECTS)

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.currentPlayer = game.BLACK
finished.emit(Constants.HAND_SETUP)

View file

@ -0,0 +1,11 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, data := {}) -> void:
game.cleanupPhase()
if "endCondition" in data:
finished.emit(Constants.ROUND_END)
elif game.currentPlayer == game.WHITE:
finished.emit(Constants.BLACK_TURN)
else:
finished.emit(Constants.WHITE_TURN)

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.drawCards()
finished.emit(Constants.PERSISTENT_EFFECTS)

View file

@ -0,0 +1,11 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
if game.isCheckmate():
game.endGame("checkmate")
finished.emit(Constants.CLEANUP, {"endCondition": "checkmate"})
elif game.isDraw():
game.endGame("draw")
finished.emit(Constants.CLEANUP, {"endCondition": "draw"})
else:
finished.emit(Constants.CLEANUP)

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.prepareHand()
finished.emit(Constants.DRAW_PHASE)

View file

@ -0,0 +1,17 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.resetHighlights()
if game.selectedNode != "":
game.getValidMoves()
func handleMovement(location: String) -> void:
var node = game.get_node("Flow/" + location)
if game.selectedNode == "":
if node.get_child_count() != 0 && node.get_child(0).Item_Color == game.Turn:
game.selectedNode = location
game.getMovableAreas()
else:
if game.isValidMove(location):
game.executeMove(location)
finished.emit(Constants.POST_MOVE)

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.resolveMoveEffects()
finished.emit(Constants.EVALUATE_POSITION)

View file

@ -0,0 +1,8 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
pass
func handleInput(event: InputEvent) -> void:
if event.is_action_pressed("playCard"):
finished.emit(Constants.ATTACH_CARDS)

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.updateEffectDurations()
finished.emit(Constants.TILE_EFFECTS)

View file

@ -0,0 +1,21 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, data := {}) -> void:
# Check win condition
if "endCondition" in data:
match data["endCondition"]:
"checkmate":
handleCheckmate()
"draw":
handleDraw()
# Reset state for next round
game.resetBoard()
finished.emit(Constants.WHITE_TURN)
func handleCheckmate() -> void:
var winner = "White" if game.turn == 1 else "Black"
print("Checkmate! " + winner + " wins!")
func handleDraw() -> void:
print("Game ended in draw")

View file

@ -0,0 +1,5 @@
extends "res://Systems/StateMachine/ChessGameState.gd"
func enter(_previous: String, _data := {}) -> void:
game.currentPlayer = game.WHITE
finished.emit(Constants.HAND_SETUP)

View file

@ -1,14 +1,17 @@
class_name StateMachine extends Node
@export var initialState: State = null
@export var initialState: ChessGameState = null
@onready var state: State = (func getInitialState() -> State:
@onready var state: ChessGameState = (func getInitialState() -> State:
return initialState if initialState != null else get_child(0)
).call()
@onready var parent = get_parent()
var previouseState = null
func ready() -> void:
for stateNode: State in find_children("*", "State"):
for stateNode: ChessGameState in find_children("*", "ChessGameState"):
stateNode.finished.connect(transitionToNextState)
await owner.ready
@ -21,14 +24,15 @@ func unhandledInput(event: InputEvent) -> void:
func process(delta: float) -> void:
state.update(delta)
func transitionToNextState(targetStatePath: String, data: Dictionary = {}) -> void:
if not has_node(targetStatePath):
printerr(owner.name + ": Trying to transition to state " + targetStatePath + " but it does not exist.")
return
var previousStatePath := state.name
previouseState = state.name
state.exit()
state = get_node(targetStatePath)
state.enter(previousStatePath, data)
state.enter(previouseState, data)

View file

@ -15,7 +15,7 @@ func _process(_delta):
self.texture = load("res://addons/Chess/Textures/BBishop.svg")
func get_valid_moves(board_flow, current_location: String) -> Dictionary:
func getValidMoves(board_flow, current_location: String) -> Dictionary:
var moves = {
"regular_moves": [],
"special_moves": []

View file

@ -17,7 +17,7 @@ func _process(_delta):
self.texture = load("res://addons/Chess/Textures/BKing.svg")
# King.gd
func get_valid_moves(board_flow, current_location: String) -> Dictionary:
func getValidMoves(board_flow, current_location: String) -> Dictionary:
var moves = {
"regular_moves": [],
"special_moves": []

View file

@ -13,7 +13,7 @@ func _process(_delta):
self.texture = load("res://addons/Chess/Textures/WKnight.svg")
elif Item_Color == 1:
self.texture = load("res://addons/Chess/Textures/BKnight.svg")
func get_valid_moves(board_flow, current_location: String) -> Dictionary:
func getValidMoves(board_flow, current_location: String) -> Dictionary:
var moves = {
"regular_moves": [],
"special_moves": []

View file

@ -29,7 +29,7 @@ func _process(_delta):
# Movement interface method that all pieces will implement
# In Pawn.gd
func get_valid_moves(board_flow, current_location: String) -> Dictionary:
func getValidMoves(board_flow, current_location: String) -> Dictionary:
var moves = {
"regular_moves": [],
"special_moves": []

View file

@ -13,7 +13,7 @@ func _process(_delta):
elif Item_Color == 1:
self.texture = load("res://addons/Chess/Textures/BQueen.svg")
func get_valid_moves(board_flow, current_location: String) -> Dictionary:
func getValidMoves(board_flow, current_location: String) -> Dictionary:
var moves = {
"regular_moves": [],
"special_moves": []

View file

@ -16,7 +16,7 @@ func _process(_delta):
elif Item_Color == 1:
self.texture = load("res://addons/Chess/Textures/BRook.svg")
func get_valid_moves(board_flow, current_location: String) -> Dictionary:
func getValidMoves(board_flow, current_location: String) -> Dictionary:
var moves = {
"regular_moves": [],
"special_moves": []

View file

@ -1,7 +1,21 @@
[gd_scene load_steps=3 format=3 uid="uid://d0qyk6v20uief"]
[gd_scene load_steps=17 format=3 uid="uid://d0qyk6v20uief"]
[ext_resource type="Script" path="res://Generator.gd" id="1_ckrtr"]
[ext_resource type="Script" path="res://Game.gd" id="1_f1l42"]
[ext_resource type="Script" path="res://Systems/Game/ChessGame.gd" id="1_fkb2r"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/WhiteTurn.gd" id="3_276ip"]
[ext_resource type="Script" path="res://Systems/StateMachine/StateMachine.gd" id="3_lw81y"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/BlackTurn.gd" id="4_tl1oh"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/HandSetup.gd" id="5_4xbce"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/DrawPhase.gd" id="6_xlfb1"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/ResolvePersistentEffects.gd" id="7_1ufry"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/ApplyTileEffects.gd" id="8_h8ea3"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/PreMovePhase.gd" id="9_vq75e"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/AttachCards.gd" id="10_mkypi"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/ApplyCardEffects.gd" id="11_fqmmt"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/Movement.gd" id="12_l81sw"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/PostMovePhase.gd" id="13_d4fiw"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/EvaluatePosition.gd" id="14_icem8"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/CleanupPhase.gd" id="15_m58r8"]
[ext_resource type="Script" path="res://Systems/StateMachine/GameStates/RoundEnd.gd" id="16_8h5do"]
[node name="Board" type="Control"]
layout_mode = 3
@ -10,7 +24,7 @@ anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_f1l42")
script = ExtResource("1_fkb2r")
[node name="Flow" type="FlowContainer" parent="."]
layout_mode = 1
@ -20,7 +34,6 @@ anchor_right = 0.5
offset_left = -252.0
offset_right = -252.0
grow_horizontal = 2
script = ExtResource("1_ckrtr")
[node name="Player1Points" type="RichTextLabel" parent="."]
layout_mode = 1
@ -72,4 +85,61 @@ offset_right = 20.0
grow_horizontal = 2
grow_vertical = 0
[connection signal="send_location" from="Flow" to="." method="_on_flow_send_location"]
[node name="StateMachine" type="Node" parent="."]
script = ExtResource("3_lw81y")
[node name="WhiteTurn" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("3_276ip")
game = NodePath("../..")
[node name="BlackTurn" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("4_tl1oh")
game = NodePath("../..")
[node name="HandSetup" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("5_4xbce")
game = NodePath("../..")
[node name="DrawPhase" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("6_xlfb1")
game = NodePath("../..")
[node name="ResolvePersistentEffects" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("7_1ufry")
game = NodePath("../..")
[node name="ApplyTileEffects" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("8_h8ea3")
game = NodePath("../..")
[node name="PreMovePhase" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("9_vq75e")
game = NodePath("../..")
[node name="AttachCards" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("10_mkypi")
game = NodePath("../..")
[node name="ApplyCardEffects" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("11_fqmmt")
game = NodePath("../..")
[node name="Movement" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("12_l81sw")
game = NodePath("../..")
[node name="PostMovePhase" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("13_d4fiw")
game = NodePath("../..")
[node name="EvaluatePosition" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("14_icem8")
game = NodePath("../..")
[node name="CleanupPhase" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("15_m58r8")
game = NodePath("../..")
[node name="RoundEnd" type="Node" parent="StateMachine" node_paths=PackedStringArray("game")]
script = ExtResource("16_8h5do")
game = NodePath("../..")

View file

@ -15,6 +15,14 @@ run/main_scene="res://board.tscn"
config/features=PackedStringArray("4.3", "Forward Plus")
config/icon="res://icon.svg"
[autoload]
Constants="*res://Systems/StateMachine/Constants.gd"
[editor]
use_spaces=true
[editor_plugins]
enabled=PackedStringArray()