396 lines
14 KiB
GDScript
396 lines
14 KiB
GDScript
@tool
|
|
extends Sprite2D
|
|
class_name Pawn
|
|
|
|
@export var Current_X_Position = 0
|
|
@export var Current_Y_Position = 0
|
|
|
|
# Item_Color = 0; White
|
|
# Item_Color = 1; Black
|
|
@export var Item_Color = 0
|
|
|
|
@export var Points = 1
|
|
|
|
|
|
var game: ChessGame = null
|
|
var duration_label: Label
|
|
var Temp_Color = 0
|
|
var Double_Start = true
|
|
var En_Passant = false
|
|
const BASE_SIZE = Vector2(40, 40)
|
|
const CARD_TINT_COLOR = Color(0.3, 0.8, 0.3, 0.5) # Green tint for card effects
|
|
const EFFECT_TINT_COLOR = Color(0.8, 0.2, 0.2, 0.5)
|
|
var id: String = Utils.generate_guid()
|
|
var original_movement_string: String = "mfWcfF"
|
|
var current_movement_string: String = original_movement_string
|
|
|
|
const DIRECTIONS = {
|
|
"b": [0, 1], # backward
|
|
"f": [0, -1], # forward
|
|
"l": [-1, 0], # right
|
|
"r": [1, 0], # left
|
|
"bl": [-1, 1], # forward-right
|
|
"br": [1, 1], # forward-left
|
|
"fl": [-1, -1], # backward-right
|
|
"fr": [1, -1] # backward-left
|
|
}
|
|
|
|
func _ready():
|
|
modulate = Color.WHITE if Item_Color == 0 else Color.BLACK
|
|
|
|
func _init(chess: ChessGame) -> void:
|
|
game = chess
|
|
self.texture = load("res://addons/Chess/Textures/WPawn.svg")
|
|
var background_style = StyleBoxFlat.new()
|
|
background_style.bg_color = Color.WHITE
|
|
background_style.corner_radius_top_left = 2
|
|
background_style.corner_radius_top_right = 2
|
|
background_style.corner_radius_bottom_left = 2
|
|
background_style.corner_radius_bottom_right = 2
|
|
background_style.content_margin_left = 2
|
|
background_style.content_margin_right = 2
|
|
background_style.content_margin_top = 1
|
|
background_style.content_margin_bottom = 1
|
|
duration_label = Label.new()
|
|
duration_label.add_theme_stylebox_override("normal", background_style)
|
|
duration_label.add_theme_color_override("font_color", Color.BLACK)
|
|
duration_label.position = Vector2(-20, -20) # Position above the piece
|
|
add_child(duration_label)
|
|
duration_label.hide()
|
|
|
|
func update_appearance() -> void:
|
|
# print("update_appearance")
|
|
var chess_game = game
|
|
if !is_instance_valid(get_tree()) || !chess_game:
|
|
return
|
|
|
|
if !chess_game.deckManager:
|
|
return
|
|
|
|
var deck_manager = chess_game.deckManager
|
|
var has_card = deck_manager.attached_cards.has(get_instance_id())
|
|
var has_effect = deck_manager.attached_effects.has(get_instance_id())
|
|
var base_color = Color.WHITE if Item_Color == 0 else Color.BLACK
|
|
|
|
if has_effect and deck_manager.attached_effects[get_instance_id()].size() > 0:
|
|
modulate = base_color * ( EFFECT_TINT_COLOR)
|
|
if has_card:
|
|
# Apply tint while keeping the piece color
|
|
modulate = base_color * CARD_TINT_COLOR
|
|
|
|
|
|
# Update duration display
|
|
var card = deck_manager.attached_cards[get_instance_id()]
|
|
if is_instance_valid(duration_label):
|
|
duration_label.text = str(card.remaining_turns)
|
|
duration_label.show()
|
|
else:
|
|
# Reset to normal color
|
|
modulate = Color.WHITE if Item_Color == 0 else Color.BLACK
|
|
if is_instance_valid(duration_label):
|
|
duration_label.hide()
|
|
|
|
|
|
|
|
|
|
func on_card_effect_changed() -> void:
|
|
update_appearance()
|
|
# Movement interface method that all pieces will implement
|
|
func getValidMoves(board_flow, current_location: String) -> Dictionary:
|
|
var moves = {
|
|
"regular_moves": [],
|
|
"special_moves": []
|
|
}
|
|
|
|
var loc = current_location.split("-")
|
|
var x = int(loc[0])
|
|
var y = int(loc[1])
|
|
|
|
# Invert directions if black
|
|
var direction_multiplier = 1 if Item_Color == 1 else -1
|
|
|
|
# Parse the Betza notation
|
|
var atoms = parseBetzaNotation(current_movement_string)
|
|
|
|
# Process each atom
|
|
for atom in atoms:
|
|
var can_move = "m" in atom.modifiers || (!("m" in atom.modifiers) && !("c" in atom.modifiers))
|
|
var can_capture = "c" in atom.modifiers || (!("m" in atom.modifiers) && !("c" in atom.modifiers))
|
|
|
|
# Get directions for this atom
|
|
var directions = getDirectionsForAtom(atom)
|
|
|
|
# Process each direction
|
|
for dir in directions:
|
|
var dir_vector = DIRECTIONS[dir].duplicate()
|
|
|
|
# Adjust direction based on color
|
|
if Item_Color == 1: # If black
|
|
if "f" in dir:
|
|
dir_vector[1] *= -1
|
|
if "b" in dir:
|
|
dir_vector[1] *= -1
|
|
if "l" in dir:
|
|
dir_vector[0] *= -1
|
|
if "r" in dir:
|
|
dir_vector[0] *= -1
|
|
|
|
# Handle different atom types
|
|
match atom.type:
|
|
"W": # Wazir (orthogonal step)
|
|
processStep(board_flow, moves, x, y, dir_vector, can_move, can_capture)
|
|
"F": # Ferz (diagonal step)
|
|
processStep(board_flow, moves, x, y, dir_vector, can_move, can_capture)
|
|
"R": # Rook (orthogonal slider)
|
|
processSlider(board_flow, moves, x, y, dir_vector, can_move, can_capture, atom.range)
|
|
"B": # Bishop (diagonal slider)
|
|
processSlider(board_flow, moves, x, y, dir_vector, can_move, can_capture, atom.range)
|
|
"N": # Knight
|
|
processKnightMove(board_flow, moves, x, y, dir_vector, can_move, can_capture)
|
|
|
|
# Add special pawn moves if this is a pawn
|
|
if original_movement_string == "mfWcfF":
|
|
addSpecialPawnMoves(board_flow, moves, x, y)
|
|
|
|
return moves
|
|
|
|
# Helper method for all pieces
|
|
func is_valid_cell(board_flow, location: String) -> bool:
|
|
var node = board_flow.get_node_or_null(location)
|
|
return node != null
|
|
|
|
# Helper for checking if cell is empty or contains enemy
|
|
func can_move_to_cell(board_flow, location: String, is_capture: bool = false) -> bool:
|
|
var container = board_flow.get_node(location) as PieceContainer
|
|
var game = board_flow.get_parent() as ChessGame
|
|
var tile = game.tileManager.get_tile(location)
|
|
if tile && !tile.passable:
|
|
return false
|
|
if is_capture:
|
|
var piece = container.get_piece()
|
|
return piece != null && piece.Item_Color != self.Item_Color
|
|
return !container.has_piece()
|
|
|
|
func set_current_movement_string(mvmnt: String):
|
|
current_movement_string = mvmnt
|
|
|
|
func get_current_movement_string() -> String:
|
|
return current_movement_string
|
|
|
|
func get_original_movement_string() -> String:
|
|
return original_movement_string
|
|
|
|
func animate_movement(target_position: Vector2, duration: float = 0.5) -> void:
|
|
# print("--------------STARTING ANIM--------------", position, " ", target_position)
|
|
z_index = 1
|
|
var tween = create_tween()
|
|
# Make sure the tween is configured properly
|
|
tween.set_trans(Tween.TRANS_LINEAR) # or TRANS_CUBIC for smoother movement
|
|
tween.set_ease(Tween.EASE_IN_OUT)
|
|
|
|
var start_pos = position
|
|
tween.tween_property(self, "global_position", target_position, duration)
|
|
#.from(start_pos)
|
|
|
|
# Wait for animation to complete
|
|
await tween.finished
|
|
# print("--------------FINISHED ANIM--------------")
|
|
|
|
func animate_capture(duration: float = 0.5) -> void:
|
|
z_index = 1 # Ensure piece is visible above others during animation
|
|
var tween = create_tween()
|
|
tween.set_trans(Tween.TRANS_LINEAR)
|
|
tween.set_ease(Tween.EASE_IN_OUT)
|
|
|
|
# First turn red
|
|
tween.tween_property(self, "modulate", Color.RED, duration/2)
|
|
# Then shrink to nothing
|
|
tween.tween_property(self, "scale", Vector2.ZERO, duration/2)
|
|
# Finally remove the piece
|
|
tween.tween_callback(queue_free)
|
|
|
|
await tween.finished
|
|
|
|
|
|
# ========================BETZA NOTATION================
|
|
|
|
# Parse the Betza notation string into a list of atoms
|
|
func parseBetzaNotation(notation: String) -> Array:
|
|
var atoms = []
|
|
var i = 0
|
|
|
|
while i < notation.length():
|
|
var atom = {
|
|
"type": "",
|
|
"modifiers": [],
|
|
"range": -1 # -1 unlimited
|
|
}
|
|
|
|
# Collect modifiers before the atom type
|
|
while i < notation.length() && ["m", "c"].has(notation[i]):
|
|
atom.modifiers.append(notation[i])
|
|
i += 1
|
|
|
|
# direction modifiers
|
|
var directions = ""
|
|
while i < notation.length() && ["f", "b", "l", "r"].has(notation[i]):
|
|
directions += notation[i]
|
|
i += 1
|
|
|
|
if directions:
|
|
atom.modifiers.append(directions)
|
|
|
|
# atom type
|
|
if i < notation.length():
|
|
atom.type = notation[i]
|
|
i += 1
|
|
|
|
# range specification
|
|
var range_str = ""
|
|
while i < notation.length() && notation[i].is_valid_int():
|
|
range_str += notation[i]
|
|
i += 1
|
|
|
|
if range_str:
|
|
atom.range = int(range_str)
|
|
|
|
atoms.append(atom)
|
|
|
|
return atoms
|
|
|
|
# Directions for an atom based on its modifiers
|
|
func getDirectionsForAtom(atom) -> Array:
|
|
var base_directions = []
|
|
var direction_modifiers = []
|
|
|
|
# Extract direction modifiers
|
|
for modifier in atom.modifiers:
|
|
if modifier.length() > 1 || ["f", "b", "l", "r"].has(modifier):
|
|
for char in modifier:
|
|
if ["f", "b", "l", "r"].has(char):
|
|
direction_modifiers.append(char)
|
|
|
|
# Set base directions based on atom type
|
|
match atom.type:
|
|
"W": # Wazir
|
|
base_directions = ["f", "b", "l", "r"]
|
|
"F": # Ferz
|
|
base_directions = ["fl", "fr", "bl", "br"]
|
|
"R": # Rook
|
|
base_directions = ["f", "b", "l", "r"]
|
|
"B": # Bishop
|
|
base_directions = ["fl", "fr", "bl", "br"]
|
|
"Q": # Queen
|
|
base_directions = ["f", "b", "l", "r", "fl", "fr", "bl", "br"]
|
|
"K": # King
|
|
base_directions = ["f", "b", "l", "r", "fl", "fr", "bl", "br"]
|
|
"N": # Knight - directions handled specially
|
|
base_directions = ["f", "b", "l", "r"]
|
|
|
|
# Filter directions based on modifiers - NEW LOGIC HERE
|
|
if direction_modifiers:
|
|
var filtered_directions = []
|
|
|
|
for dir in base_directions:
|
|
# For each direction, check if it CONTAINS any of the modifiers
|
|
# (doesn't need to match all characters)
|
|
var contains_modifier = false
|
|
for mod in direction_modifiers:
|
|
if dir.contains(mod):
|
|
contains_modifier = true
|
|
break
|
|
|
|
if contains_modifier:
|
|
filtered_directions.append(dir)
|
|
|
|
return filtered_directions
|
|
|
|
return base_directions
|
|
|
|
# Process a single step move
|
|
func processStep(board_flow, moves, x, y, dir_vector, can_move, can_capture):
|
|
var new_x = x + dir_vector[0]
|
|
var new_y = y + dir_vector[1]
|
|
var target = str(new_x) + "-" + str(new_y)
|
|
print("processStep " + target )
|
|
|
|
if is_valid_cell(board_flow, target):
|
|
if can_move && can_move_to_cell(board_flow, target, false):
|
|
if !moves.regular_moves.has(target):
|
|
moves.regular_moves.append(target)
|
|
elif can_capture && can_move_to_cell(board_flow, target, true):
|
|
if !moves.regular_moves.has(target):
|
|
moves.regular_moves.append(target)
|
|
|
|
# Process a slider move (rook, bishop, queen)
|
|
func processSlider(board_flow, moves, x, y, dir_vector, can_move, can_capture, max_range):
|
|
var step = 1
|
|
var blocked = false
|
|
|
|
while !blocked && (max_range == -1 || step <= max_range):
|
|
var new_x = x + (dir_vector[0] * step)
|
|
var new_y = y + (dir_vector[1] * step)
|
|
var target = str(new_x) + "-" + str(new_y)
|
|
|
|
if !is_valid_cell(board_flow, target):
|
|
blocked = true
|
|
continue
|
|
|
|
var target_cell = board_flow.get_node(target) as PieceContainer
|
|
if target_cell.get_piece() == null:
|
|
if can_move:
|
|
if !moves.regular_moves.has(target):
|
|
moves.regular_moves.append(target)
|
|
else:
|
|
if can_capture && target_cell.get_piece().Item_Color != self.Item_Color:
|
|
if !moves.regular_moves.has(target):
|
|
moves.regular_moves.append(target)
|
|
blocked = true
|
|
|
|
step += 1
|
|
|
|
# Process knight move
|
|
func processKnightMove(board_flow, moves, x, y, dir_vector, can_move, can_capture):
|
|
# Knight directions regardless of the dir_vector
|
|
var knight_offsets = [
|
|
[1, 2], [2, 1], [2, -1], [1, -2],
|
|
[-1, -2], [-2, -1], [-2, 1], [-1, 2]
|
|
]
|
|
|
|
for offset in knight_offsets:
|
|
var new_x = x + offset[0]
|
|
var new_y = y + offset[1]
|
|
var target = str(new_x) + "-" + str(new_y)
|
|
|
|
if is_valid_cell(board_flow, target):
|
|
var has_piece = board_flow.get_node(target).get_piece() != null
|
|
var enemy_piece = has_piece && board_flow.get_node(target).get_piece().Item_Color != self.Item_Color
|
|
|
|
if ((can_move && !has_piece) || (can_capture && enemy_piece)):
|
|
if !moves.regular_moves.has(target):
|
|
moves.regular_moves.append(target)
|
|
|
|
# Add special pawn moves (double move, en passant)
|
|
func addSpecialPawnMoves(board_flow, moves, x, y):
|
|
var direction = 1 if Item_Color == 1 else -1
|
|
|
|
# Double move on first turn
|
|
if Double_Start:
|
|
var single_forward = str(x) + "-" + str(y + direction)
|
|
var double_forward = str(x) + "-" + str(y + (direction * 2))
|
|
|
|
if is_valid_cell(board_flow, single_forward) and is_valid_cell(board_flow, double_forward) and can_move_to_cell(board_flow, single_forward) and can_move_to_cell(board_flow, double_forward):
|
|
if !moves.regular_moves.has(double_forward):
|
|
moves.regular_moves.append(double_forward)
|
|
|
|
# En Passant
|
|
for dx in [-1, 1]:
|
|
var adjacent = str(x + dx) + "-" + str(y)
|
|
var capture = str(x + dx) + "-" + str(y + direction)
|
|
|
|
if is_valid_cell(board_flow, adjacent) and is_valid_cell(board_flow, capture):
|
|
var adjacent_cell = board_flow.get_node(adjacent) as PieceContainer
|
|
if adjacent_cell.get_piece() != null:
|
|
var adjacent_piece = adjacent_cell.get_piece()
|
|
if adjacent_piece.name == "Pawn" and adjacent_piece.En_Passant and adjacent_piece.Item_Color != self.Item_Color:
|
|
moves.special_moves.append([adjacent, capture])
|