194 lines
5.3 KiB
GDScript
194 lines
5.3 KiB
GDScript
class_name UndoSystem
|
|
extends RefCounted
|
|
|
|
## UndoSystem - Tracks the last action for undo capability
|
|
|
|
signal undo_available_changed(available: bool)
|
|
signal action_undone(action_name: String)
|
|
|
|
# Action types that can be undone
|
|
enum ActionType {
|
|
NONE,
|
|
DISCARD_FOR_CP,
|
|
DULL_BACKUP_FOR_CP,
|
|
PLAY_CARD
|
|
}
|
|
|
|
# Stored action data for undo
|
|
class UndoAction:
|
|
var type: ActionType = ActionType.NONE
|
|
var player_index: int = -1
|
|
var card: CardInstance = null
|
|
var description: String = ""
|
|
# Additional data depending on action type
|
|
var cp_element: Enums.Element = Enums.Element.FIRE
|
|
var cp_amount: int = 0
|
|
var previous_card_state: Enums.CardState = Enums.CardState.ACTIVE
|
|
var from_zone: Enums.ZoneType = Enums.ZoneType.HAND
|
|
var to_zone: Enums.ZoneType = Enums.ZoneType.FIELD_FORWARDS
|
|
|
|
var last_action: UndoAction = null
|
|
var game_state: GameState = null
|
|
|
|
func _init(state: GameState = null) -> void:
|
|
game_state = state
|
|
|
|
## Set the game state reference
|
|
func set_game_state(state: GameState) -> void:
|
|
game_state = state
|
|
|
|
## Check if undo is available
|
|
func can_undo() -> bool:
|
|
return last_action != null and last_action.type != ActionType.NONE
|
|
|
|
## Record a discard for CP action
|
|
func record_discard_for_cp(player_index: int, card: CardInstance, element: Enums.Element) -> void:
|
|
var action = UndoAction.new()
|
|
action.type = ActionType.DISCARD_FOR_CP
|
|
action.player_index = player_index
|
|
action.card = card
|
|
action.cp_element = element
|
|
action.cp_amount = 2
|
|
action.description = "Discard " + card.get_display_name() + " for CP"
|
|
|
|
last_action = action
|
|
undo_available_changed.emit(true)
|
|
|
|
## Record a dull backup for CP action
|
|
func record_dull_backup_for_cp(player_index: int, card: CardInstance, element: Enums.Element) -> void:
|
|
var action = UndoAction.new()
|
|
action.type = ActionType.DULL_BACKUP_FOR_CP
|
|
action.player_index = player_index
|
|
action.card = card
|
|
action.cp_element = element
|
|
action.cp_amount = 1
|
|
action.previous_card_state = Enums.CardState.ACTIVE # Was active before dulling
|
|
action.description = "Dull " + card.get_display_name() + " for CP"
|
|
|
|
last_action = action
|
|
undo_available_changed.emit(true)
|
|
|
|
## Record playing a card
|
|
func record_play_card(player_index: int, card: CardInstance, to_zone: Enums.ZoneType, _cp_spent: Dictionary) -> void:
|
|
var action = UndoAction.new()
|
|
action.type = ActionType.PLAY_CARD
|
|
action.player_index = player_index
|
|
action.card = card
|
|
action.from_zone = Enums.ZoneType.HAND
|
|
action.to_zone = to_zone
|
|
action.description = "Play " + card.get_display_name()
|
|
|
|
last_action = action
|
|
undo_available_changed.emit(true)
|
|
|
|
## Clear the undo history (called when phase changes, combat happens, etc.)
|
|
func clear_history() -> void:
|
|
last_action = null
|
|
undo_available_changed.emit(false)
|
|
|
|
## Execute undo of the last action
|
|
func undo() -> bool:
|
|
if not can_undo() or not game_state:
|
|
return false
|
|
|
|
var action = last_action
|
|
var success = false
|
|
|
|
match action.type:
|
|
ActionType.DISCARD_FOR_CP:
|
|
success = _undo_discard_for_cp(action)
|
|
ActionType.DULL_BACKUP_FOR_CP:
|
|
success = _undo_dull_backup_for_cp(action)
|
|
ActionType.PLAY_CARD:
|
|
success = _undo_play_card(action)
|
|
|
|
if success:
|
|
var description = action.description
|
|
last_action = null
|
|
undo_available_changed.emit(false)
|
|
action_undone.emit(description)
|
|
|
|
return success
|
|
|
|
## Undo a discard for CP action
|
|
func _undo_discard_for_cp(action: UndoAction) -> bool:
|
|
var player = game_state.get_player(action.player_index)
|
|
if not player:
|
|
return false
|
|
|
|
# Remove card from break zone
|
|
if not player.break_zone.has_card(action.card):
|
|
return false
|
|
|
|
player.break_zone.remove_card(action.card)
|
|
|
|
# Add card back to hand
|
|
player.hand.add_card(action.card)
|
|
|
|
# Remove the CP that was generated
|
|
player.cp_pool.add_cp(action.cp_element, -action.cp_amount)
|
|
|
|
return true
|
|
|
|
## Undo a dull backup for CP action
|
|
func _undo_dull_backup_for_cp(action: UndoAction) -> bool:
|
|
var player = game_state.get_player(action.player_index)
|
|
if not player:
|
|
return false
|
|
|
|
# Check card is still on field
|
|
if not player.field_backups.has_card(action.card):
|
|
return false
|
|
|
|
# Reactivate the backup
|
|
action.card.activate()
|
|
|
|
# Remove the CP that was generated
|
|
player.cp_pool.add_cp(action.cp_element, -action.cp_amount)
|
|
|
|
return true
|
|
|
|
## Undo playing a card
|
|
func _undo_play_card(action: UndoAction) -> bool:
|
|
var player = game_state.get_player(action.player_index)
|
|
if not player:
|
|
return false
|
|
|
|
var card = action.card
|
|
|
|
# Remove from field
|
|
var removed = false
|
|
if action.to_zone == Enums.ZoneType.FIELD_FORWARDS:
|
|
if player.field_forwards.has_card(card):
|
|
player.field_forwards.remove_card(card)
|
|
removed = true
|
|
elif action.to_zone == Enums.ZoneType.FIELD_BACKUPS:
|
|
if player.field_backups.has_card(card):
|
|
player.field_backups.remove_card(card)
|
|
removed = true
|
|
|
|
if not removed:
|
|
return false
|
|
|
|
# Return to hand
|
|
player.hand.add_card(card)
|
|
|
|
# Reset card state
|
|
card.state = Enums.CardState.ACTIVE
|
|
card.turns_on_field = 0
|
|
|
|
# Refund the CP (we don't track exact CP spent, so this is simplified)
|
|
# In a full implementation, we'd track what CP was spent
|
|
# For now, we'll add back CP equal to the card cost
|
|
var cost = card.card_data.cost
|
|
var element = card.get_element()
|
|
player.cp_pool.add_cp(element, cost)
|
|
|
|
return true
|
|
|
|
## Get description of the last action (for display)
|
|
func get_last_action_description() -> String:
|
|
if not can_undo():
|
|
return ""
|
|
return last_action.description
|