170 lines
4.8 KiB
GDScript3
170 lines
4.8 KiB
GDScript3
class_name TurnManager
|
|
extends RefCounted
|
|
|
|
## TurnManager - Handles turn and phase progression
|
|
|
|
signal phase_changed(phase: Enums.TurnPhase)
|
|
signal turn_changed(player_index: int)
|
|
signal turn_started(player_index: int, turn_number: int)
|
|
signal turn_ended(player_index: int)
|
|
|
|
var current_phase: Enums.TurnPhase = Enums.TurnPhase.ACTIVE
|
|
var current_player_index: int = 0
|
|
var turn_number: int = 0
|
|
var is_first_turn: bool = true
|
|
|
|
# Attack phase tracking
|
|
var attack_step: Enums.AttackStep = Enums.AttackStep.PREPARATION
|
|
var current_attacker: CardInstance = null
|
|
var current_blocker: CardInstance = null
|
|
|
|
func _init() -> void:
|
|
pass
|
|
|
|
## Start a new game
|
|
func start_game(first_player: int) -> void:
|
|
current_player_index = first_player
|
|
turn_number = 1
|
|
is_first_turn = true
|
|
current_phase = Enums.TurnPhase.ACTIVE
|
|
turn_started.emit(current_player_index, turn_number)
|
|
# Emit phase_changed to trigger the initial Active phase execution
|
|
phase_changed.emit(current_phase)
|
|
|
|
## Advance to the next phase
|
|
func advance_phase() -> Enums.TurnPhase:
|
|
var next_phase = _get_next_phase(current_phase)
|
|
|
|
if next_phase == Enums.TurnPhase.ACTIVE:
|
|
# Starting a new turn
|
|
_end_current_turn()
|
|
_start_new_turn()
|
|
else:
|
|
current_phase = next_phase
|
|
phase_changed.emit(current_phase)
|
|
|
|
return current_phase
|
|
|
|
## Get the next phase in sequence
|
|
func _get_next_phase(phase: Enums.TurnPhase) -> Enums.TurnPhase:
|
|
match phase:
|
|
Enums.TurnPhase.ACTIVE:
|
|
return Enums.TurnPhase.DRAW
|
|
Enums.TurnPhase.DRAW:
|
|
return Enums.TurnPhase.MAIN_1
|
|
Enums.TurnPhase.MAIN_1:
|
|
return Enums.TurnPhase.ATTACK
|
|
Enums.TurnPhase.ATTACK:
|
|
return Enums.TurnPhase.MAIN_2
|
|
Enums.TurnPhase.MAIN_2:
|
|
return Enums.TurnPhase.END
|
|
Enums.TurnPhase.END:
|
|
return Enums.TurnPhase.ACTIVE # Loop back to start new turn
|
|
return Enums.TurnPhase.ACTIVE
|
|
|
|
## End the current turn
|
|
func _end_current_turn() -> void:
|
|
turn_ended.emit(current_player_index)
|
|
|
|
## Start a new turn
|
|
func _start_new_turn() -> void:
|
|
# Switch to other player
|
|
current_player_index = 1 - current_player_index
|
|
turn_number += 1
|
|
is_first_turn = false
|
|
|
|
current_phase = Enums.TurnPhase.ACTIVE
|
|
_reset_attack_state()
|
|
|
|
turn_changed.emit(current_player_index)
|
|
turn_started.emit(current_player_index, turn_number)
|
|
phase_changed.emit(current_phase)
|
|
|
|
## Reset attack phase state
|
|
func _reset_attack_state() -> void:
|
|
attack_step = Enums.AttackStep.PREPARATION
|
|
current_attacker = null
|
|
current_blocker = null
|
|
|
|
## Check if we're in a main phase (can play cards)
|
|
func is_main_phase() -> bool:
|
|
return current_phase == Enums.TurnPhase.MAIN_1 or current_phase == Enums.TurnPhase.MAIN_2
|
|
|
|
## Check if we're in attack phase
|
|
func is_attack_phase() -> bool:
|
|
return current_phase == Enums.TurnPhase.ATTACK
|
|
|
|
## Get cards drawn this turn (2 normally, 1 on first turn for first player)
|
|
func get_draw_count() -> int:
|
|
if is_first_turn:
|
|
return 1
|
|
return 2
|
|
|
|
## Attack phase state management
|
|
|
|
## Start attack declaration (only valid from PREPARATION)
|
|
func start_attack_declaration() -> bool:
|
|
if attack_step != Enums.AttackStep.PREPARATION:
|
|
return false
|
|
attack_step = Enums.AttackStep.DECLARATION
|
|
return true
|
|
|
|
## Set the attacking forward (only valid from DECLARATION)
|
|
func set_attacker(attacker: CardInstance) -> bool:
|
|
if attack_step != Enums.AttackStep.DECLARATION:
|
|
return false
|
|
if attacker == null:
|
|
return false
|
|
current_attacker = attacker
|
|
attack_step = Enums.AttackStep.BLOCK_DECLARATION
|
|
return true
|
|
|
|
## Set the blocking forward (or null for no block) - only valid from BLOCK_DECLARATION
|
|
func set_blocker(blocker: CardInstance) -> bool:
|
|
if attack_step != Enums.AttackStep.BLOCK_DECLARATION:
|
|
return false
|
|
current_blocker = blocker # null is valid (no block)
|
|
attack_step = Enums.AttackStep.DAMAGE_RESOLUTION
|
|
return true
|
|
|
|
## Complete the current attack (only valid from DAMAGE_RESOLUTION)
|
|
func complete_attack() -> bool:
|
|
if attack_step != Enums.AttackStep.DAMAGE_RESOLUTION:
|
|
return false
|
|
current_attacker = null
|
|
current_blocker = null
|
|
attack_step = Enums.AttackStep.DECLARATION
|
|
return true
|
|
|
|
## End the attack phase (no more attacks) - only valid from DECLARATION
|
|
func end_attack_phase() -> bool:
|
|
if attack_step != Enums.AttackStep.DECLARATION and attack_step != Enums.AttackStep.PREPARATION:
|
|
return false
|
|
_reset_attack_state()
|
|
advance_phase()
|
|
return true
|
|
|
|
## Get current phase as string
|
|
func get_phase_string() -> String:
|
|
return Enums.phase_to_string(current_phase)
|
|
|
|
## Get current attack step as string
|
|
func get_attack_step_string() -> String:
|
|
match attack_step:
|
|
Enums.AttackStep.PREPARATION:
|
|
return "Preparation"
|
|
Enums.AttackStep.DECLARATION:
|
|
return "Declare Attacker"
|
|
Enums.AttackStep.BLOCK_DECLARATION:
|
|
return "Declare Blocker"
|
|
Enums.AttackStep.DAMAGE_RESOLUTION:
|
|
return "Damage Resolution"
|
|
return "Unknown"
|
|
|
|
func _to_string() -> String:
|
|
return "[TurnManager: Turn %d, Player %d, Phase: %s]" % [
|
|
turn_number,
|
|
current_player_index + 1,
|
|
get_phase_string()
|
|
]
|