168 lines
4.7 KiB
GDScript
168 lines
4.7 KiB
GDScript
@tool
|
|
## Central orchestrator for the card framework system.
|
|
##
|
|
## CardManager coordinates all card-related operations including drag-and-drop,
|
|
## history management, and container registration. It serves as the root node
|
|
## for card game scenes and manages the lifecycle of cards and containers.
|
|
##
|
|
## Key Responsibilities:
|
|
## - Card factory management and initialization
|
|
## - Container registration and coordination
|
|
## - Drag-and-drop event handling and routing
|
|
## - History tracking for undo/redo operations
|
|
## - Debug mode and visual debugging support
|
|
##
|
|
## Setup Requirements:
|
|
## - Must be the parent of all CardContainer instances
|
|
## - Requires card_factory_scene to be assigned in inspector
|
|
## - Configure card_size to match your card assets
|
|
##
|
|
## Usage:
|
|
## [codeblock]
|
|
## # In scene setup
|
|
## CardManager (root)
|
|
## ├── Hand (CardContainer)
|
|
## ├── Foundation (CardContainer)
|
|
## └── Deck (CardContainer)
|
|
## [/codeblock]
|
|
class_name CardManager
|
|
extends Control
|
|
|
|
# Constants
|
|
const CARD_ACCEPT_TYPE = "card"
|
|
|
|
|
|
## Default size for all cards in the game
|
|
@export var card_size := CardFrameworkSettings.LAYOUT_DEFAULT_CARD_SIZE
|
|
## Scene containing the card factory implementation
|
|
@export var card_factory_scene: PackedScene
|
|
## Enables visual debugging for drop zones and interactions
|
|
@export var debug_mode := false
|
|
|
|
|
|
# Core system components
|
|
var card_factory: CardFactory
|
|
var card_container_dict: Dictionary = {}
|
|
var history: Array[HistoryElement] = []
|
|
|
|
|
|
func _init() -> void:
|
|
if Engine.is_editor_hint():
|
|
return
|
|
|
|
|
|
func _ready() -> void:
|
|
if not _pre_process_exported_variables():
|
|
return
|
|
|
|
if Engine.is_editor_hint():
|
|
return
|
|
|
|
card_factory.card_size = card_size
|
|
card_factory.preload_card_data()
|
|
|
|
|
|
## Undoes the last card movement operation.
|
|
## Restores cards to their previous positions using stored history.
|
|
func undo() -> void:
|
|
if history.is_empty():
|
|
return
|
|
|
|
var last = history.pop_back()
|
|
if last.from != null:
|
|
last.from.undo(last.cards, last.from_indices)
|
|
|
|
|
|
## Clears all history entries, preventing further undo operations.
|
|
func reset_history() -> void:
|
|
history.clear()
|
|
|
|
|
|
func _add_card_container(id: int, card_container: CardContainer) -> void:
|
|
card_container_dict[id] = card_container
|
|
card_container.debug_mode = debug_mode
|
|
|
|
|
|
func _delete_card_container(id: int) -> void:
|
|
card_container_dict.erase(id)
|
|
|
|
|
|
# Handles dropped cards by finding suitable container
|
|
func _on_drag_dropped(cards: Array) -> void:
|
|
if cards.is_empty():
|
|
return
|
|
|
|
# Store original mouse_filter states and temporarily disable input during drop processing
|
|
var original_mouse_filters = {}
|
|
for card in cards:
|
|
original_mouse_filters[card] = card.mouse_filter
|
|
card.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
# Find first container that accepts the cards
|
|
for key in card_container_dict.keys():
|
|
var card_container = card_container_dict[key]
|
|
var result = card_container.check_card_can_be_dropped(cards)
|
|
if result:
|
|
var index = card_container.get_partition_index()
|
|
# Restore mouse_filter before move_cards (DraggableObject will manage it from here)
|
|
for card in cards:
|
|
card.mouse_filter = original_mouse_filters[card]
|
|
card_container.move_cards(cards, index)
|
|
return
|
|
|
|
for card in cards:
|
|
# Restore mouse_filter before return_card (DraggableObject will manage it from here)
|
|
card.mouse_filter = original_mouse_filters[card]
|
|
card.return_card()
|
|
|
|
|
|
func _add_history(to: CardContainer, cards: Array) -> void:
|
|
var from = null
|
|
var from_indices = []
|
|
|
|
# Record indices FIRST, before any movement operations
|
|
for i in range(cards.size()):
|
|
var c = cards[i]
|
|
var current = c.card_container
|
|
if i == 0:
|
|
from = current
|
|
else:
|
|
if from != current:
|
|
push_error("All cards must be from the same container!")
|
|
return
|
|
|
|
# Record index immediately to avoid race conditions
|
|
if from != null:
|
|
var original_index = from._held_cards.find(c)
|
|
if original_index == -1:
|
|
push_error("Card not found in source container during history recording!")
|
|
return
|
|
from_indices.append(original_index)
|
|
|
|
var history_element = HistoryElement.new()
|
|
history_element.from = from
|
|
history_element.to = to
|
|
history_element.cards = cards
|
|
history_element.from_indices = from_indices
|
|
history.append(history_element)
|
|
|
|
|
|
func _is_valid_directory(path: String) -> bool:
|
|
var dir = DirAccess.open(path)
|
|
return dir != null
|
|
|
|
|
|
func _pre_process_exported_variables() -> bool:
|
|
if card_factory_scene == null:
|
|
push_error("CardFactory is not assigned! Please set it in the CardManager Inspector.")
|
|
return false
|
|
|
|
var factory_instance = card_factory_scene.instantiate() as CardFactory
|
|
if factory_instance == null:
|
|
push_error("Failed to create an instance of CardFactory! CardManager imported an incorrect card factory scene.")
|
|
return false
|
|
|
|
add_child(factory_instance)
|
|
card_factory = factory_instance
|
|
return true
|