337 lines
9.5 KiB
GDScript
337 lines
9.5 KiB
GDScript
class_name GameUI
|
|
extends CanvasLayer
|
|
|
|
## GameUI - Main UI overlay for game information and controls
|
|
|
|
signal end_phase_pressed
|
|
signal pass_priority_pressed
|
|
|
|
# UI Components
|
|
var turn_panel: PanelContainer
|
|
var phase_panel: PanelContainer
|
|
var cp_panel: PanelContainer
|
|
var message_panel: PanelContainer
|
|
var card_detail_panel: PanelContainer
|
|
var action_buttons: HBoxContainer
|
|
|
|
# Labels
|
|
var turn_label: Label
|
|
var phase_label: Label
|
|
var cp_label: Label
|
|
var message_label: Label
|
|
|
|
# Card detail labels
|
|
var detail_name_label: Label
|
|
var detail_type_label: Label
|
|
var detail_cost_label: Label
|
|
var detail_power_label: Label
|
|
var detail_element_label: Label
|
|
var detail_ability_label: Label
|
|
|
|
# Buttons
|
|
var end_phase_button: Button
|
|
var pass_button: Button
|
|
|
|
# Message queue
|
|
var message_queue: Array[String] = []
|
|
var message_timer: Timer
|
|
const MESSAGE_DISPLAY_TIME: float = 3.0
|
|
|
|
func _ready() -> void:
|
|
_create_ui()
|
|
_connect_signals()
|
|
|
|
func _create_ui() -> void:
|
|
# Root control that fills the screen
|
|
var root = Control.new()
|
|
add_child(root)
|
|
root.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
root.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
# === TOP BAR ===
|
|
var top_bar = HBoxContainer.new()
|
|
root.add_child(top_bar)
|
|
top_bar.set_anchors_preset(Control.PRESET_TOP_WIDE)
|
|
top_bar.offset_left = 10
|
|
top_bar.offset_right = -10
|
|
top_bar.offset_top = 10
|
|
top_bar.offset_bottom = 70
|
|
top_bar.add_theme_constant_override("separation", 20)
|
|
|
|
# Turn panel (top left)
|
|
turn_panel = _create_panel()
|
|
top_bar.add_child(turn_panel)
|
|
var turn_vbox = VBoxContainer.new()
|
|
turn_panel.add_child(turn_vbox)
|
|
|
|
var turn_header = Label.new()
|
|
turn_header.text = "Turn"
|
|
turn_header.add_theme_font_size_override("font_size", 12)
|
|
turn_vbox.add_child(turn_header)
|
|
|
|
turn_label = Label.new()
|
|
turn_label.text = "Player 1 - Turn 1"
|
|
turn_label.add_theme_font_size_override("font_size", 16)
|
|
turn_vbox.add_child(turn_label)
|
|
|
|
# Phase panel (top center-left)
|
|
phase_panel = _create_panel()
|
|
top_bar.add_child(phase_panel)
|
|
var phase_vbox = VBoxContainer.new()
|
|
phase_panel.add_child(phase_vbox)
|
|
|
|
var phase_header = Label.new()
|
|
phase_header.text = "Phase"
|
|
phase_header.add_theme_font_size_override("font_size", 12)
|
|
phase_vbox.add_child(phase_header)
|
|
|
|
phase_label = Label.new()
|
|
phase_label.text = "Active Phase"
|
|
phase_label.add_theme_font_size_override("font_size", 16)
|
|
phase_vbox.add_child(phase_label)
|
|
|
|
# CP panel
|
|
cp_panel = _create_panel()
|
|
top_bar.add_child(cp_panel)
|
|
var cp_vbox = VBoxContainer.new()
|
|
cp_panel.add_child(cp_vbox)
|
|
|
|
var cp_header = Label.new()
|
|
cp_header.text = "CP Pool"
|
|
cp_header.add_theme_font_size_override("font_size", 12)
|
|
cp_vbox.add_child(cp_header)
|
|
|
|
cp_label = Label.new()
|
|
cp_label.text = "0 CP"
|
|
cp_label.add_theme_font_size_override("font_size", 16)
|
|
cp_vbox.add_child(cp_label)
|
|
|
|
# Spacer to push buttons to the right
|
|
var spacer = Control.new()
|
|
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
top_bar.add_child(spacer)
|
|
|
|
# Action buttons in top bar (right side)
|
|
action_buttons = HBoxContainer.new()
|
|
top_bar.add_child(action_buttons)
|
|
action_buttons.add_theme_constant_override("separation", 10)
|
|
|
|
pass_button = Button.new()
|
|
pass_button.text = "Pass"
|
|
pass_button.custom_minimum_size = Vector2(80, 40)
|
|
action_buttons.add_child(pass_button)
|
|
|
|
end_phase_button = Button.new()
|
|
end_phase_button.text = "End Phase"
|
|
end_phase_button.custom_minimum_size = Vector2(100, 40)
|
|
action_buttons.add_child(end_phase_button)
|
|
|
|
# === MESSAGE PANEL (center, above hand) ===
|
|
message_panel = _create_panel()
|
|
root.add_child(message_panel)
|
|
message_panel.set_anchors_preset(Control.PRESET_CENTER)
|
|
message_panel.position = Vector2(-100, 200)
|
|
message_panel.custom_minimum_size = Vector2(200, 40)
|
|
|
|
message_label = Label.new()
|
|
message_label.text = ""
|
|
message_label.add_theme_font_size_override("font_size", 16)
|
|
message_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
message_panel.add_child(message_label)
|
|
message_panel.visible = false
|
|
|
|
# === CARD DETAIL PANEL (right side) ===
|
|
card_detail_panel = _create_panel()
|
|
root.add_child(card_detail_panel)
|
|
card_detail_panel.set_anchors_preset(Control.PRESET_CENTER_RIGHT)
|
|
card_detail_panel.offset_left = -220
|
|
card_detail_panel.offset_right = -10
|
|
card_detail_panel.offset_top = -150
|
|
card_detail_panel.offset_bottom = 150
|
|
card_detail_panel.visible = false
|
|
|
|
var detail_vbox = VBoxContainer.new()
|
|
card_detail_panel.add_child(detail_vbox)
|
|
detail_vbox.add_theme_constant_override("separation", 5)
|
|
|
|
detail_name_label = Label.new()
|
|
detail_name_label.text = "Card Name"
|
|
detail_name_label.add_theme_font_size_override("font_size", 18)
|
|
detail_vbox.add_child(detail_name_label)
|
|
|
|
var separator = HSeparator.new()
|
|
detail_vbox.add_child(separator)
|
|
|
|
detail_type_label = Label.new()
|
|
detail_type_label.text = "Type: Forward"
|
|
detail_vbox.add_child(detail_type_label)
|
|
|
|
detail_element_label = Label.new()
|
|
detail_element_label.text = "Element: Fire"
|
|
detail_vbox.add_child(detail_element_label)
|
|
|
|
detail_cost_label = Label.new()
|
|
detail_cost_label.text = "Cost: 3"
|
|
detail_vbox.add_child(detail_cost_label)
|
|
|
|
detail_power_label = Label.new()
|
|
detail_power_label.text = "Power: 7000"
|
|
detail_vbox.add_child(detail_power_label)
|
|
|
|
var separator2 = HSeparator.new()
|
|
detail_vbox.add_child(separator2)
|
|
|
|
var ability_header = Label.new()
|
|
ability_header.text = "Abilities:"
|
|
ability_header.add_theme_font_size_override("font_size", 12)
|
|
detail_vbox.add_child(ability_header)
|
|
|
|
detail_ability_label = Label.new()
|
|
detail_ability_label.text = ""
|
|
detail_ability_label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
|
detail_ability_label.custom_minimum_size.x = 180
|
|
detail_vbox.add_child(detail_ability_label)
|
|
|
|
# Message timer
|
|
message_timer = Timer.new()
|
|
add_child(message_timer)
|
|
message_timer.one_shot = true
|
|
message_timer.timeout.connect(_on_message_timer_timeout)
|
|
|
|
func _create_panel() -> PanelContainer:
|
|
var panel = PanelContainer.new()
|
|
|
|
# Create stylebox
|
|
var style = StyleBoxFlat.new()
|
|
style.bg_color = Color(0.1, 0.1, 0.15, 0.9)
|
|
style.border_color = Color(0.3, 0.3, 0.4)
|
|
style.set_border_width_all(2)
|
|
style.set_corner_radius_all(5)
|
|
style.set_content_margin_all(8)
|
|
|
|
panel.add_theme_stylebox_override("panel", style)
|
|
return panel
|
|
|
|
func _connect_signals() -> void:
|
|
end_phase_button.pressed.connect(_on_end_phase_pressed)
|
|
pass_button.pressed.connect(_on_pass_priority_pressed)
|
|
|
|
# Connect to GameManager signals
|
|
if GameManager:
|
|
GameManager.turn_changed.connect(_on_turn_changed)
|
|
GameManager.phase_changed.connect(_on_phase_changed)
|
|
GameManager.message.connect(show_message)
|
|
|
|
func _on_end_phase_pressed() -> void:
|
|
end_phase_pressed.emit()
|
|
if GameManager:
|
|
GameManager.pass_priority()
|
|
|
|
func _on_pass_priority_pressed() -> void:
|
|
pass_priority_pressed.emit()
|
|
if GameManager:
|
|
GameManager.pass_priority()
|
|
|
|
func _on_turn_changed(player_name: String, turn_number: int) -> void:
|
|
turn_label.text = player_name + " - Turn " + str(turn_number)
|
|
|
|
func _on_phase_changed(phase_name: String) -> void:
|
|
phase_label.text = phase_name
|
|
|
|
## Update CP display
|
|
func update_cp_display(cp_pool: CPPool) -> void:
|
|
if not cp_pool:
|
|
cp_label.text = "0 CP"
|
|
return
|
|
|
|
var total = cp_pool.get_total_cp()
|
|
var text = str(total) + " CP"
|
|
|
|
# Show element breakdown if any specific element CP
|
|
var elements_text = []
|
|
for element in Enums.Element.values():
|
|
var amount = cp_pool.get_cp(element)
|
|
if amount > 0:
|
|
var elem_name = Enums.element_to_string(element)
|
|
elements_text.append(elem_name + ":" + str(amount))
|
|
|
|
if elements_text.size() > 0:
|
|
text += "\n" + ", ".join(elements_text)
|
|
|
|
cp_label.text = text
|
|
|
|
## Show a message
|
|
func show_message(text: String) -> void:
|
|
message_queue.append(text)
|
|
if not message_timer.is_stopped():
|
|
return
|
|
_show_next_message()
|
|
|
|
func _show_next_message() -> void:
|
|
if message_queue.is_empty():
|
|
message_panel.visible = false
|
|
return
|
|
|
|
var text = message_queue.pop_front()
|
|
message_label.text = text
|
|
message_panel.visible = true
|
|
message_timer.start(MESSAGE_DISPLAY_TIME)
|
|
|
|
func _on_message_timer_timeout() -> void:
|
|
_show_next_message()
|
|
|
|
## Show card detail panel
|
|
func show_card_detail(card: CardInstance) -> void:
|
|
if not card or not card.card_data:
|
|
card_detail_panel.visible = false
|
|
return
|
|
|
|
var data = card.card_data
|
|
detail_name_label.text = data.name
|
|
detail_type_label.text = "Type: " + Enums.card_type_to_string(data.type)
|
|
detail_cost_label.text = "Cost: " + str(data.cost)
|
|
|
|
# Element
|
|
var element_strs = []
|
|
for elem in data.elements:
|
|
element_strs.append(Enums.element_to_string(elem))
|
|
detail_element_label.text = "Element: " + "/".join(element_strs)
|
|
|
|
# Power
|
|
if data.type == Enums.CardType.FORWARD or data.power > 0:
|
|
detail_power_label.text = "Power: " + str(card.get_power())
|
|
detail_power_label.visible = true
|
|
else:
|
|
detail_power_label.visible = false
|
|
|
|
# Abilities
|
|
var ability_text = ""
|
|
for ability in data.abilities:
|
|
if ability_text != "":
|
|
ability_text += "\n\n"
|
|
|
|
var type_str = ""
|
|
match ability.type:
|
|
Enums.AbilityType.FIELD: type_str = "[Field]"
|
|
Enums.AbilityType.AUTO: type_str = "[Auto]"
|
|
Enums.AbilityType.ACTION: type_str = "[Action]"
|
|
Enums.AbilityType.SPECIAL: type_str = "[Special]"
|
|
|
|
ability_text += type_str
|
|
if ability.name != "":
|
|
ability_text += " " + ability.name
|
|
ability_text += "\n" + ability.effect
|
|
|
|
detail_ability_label.text = ability_text if ability_text != "" else "No abilities"
|
|
|
|
card_detail_panel.visible = true
|
|
|
|
## Hide card detail panel
|
|
func hide_card_detail() -> void:
|
|
card_detail_panel.visible = false
|
|
|
|
## Update button states based on game phase
|
|
func update_button_states(can_end_phase: bool, can_pass: bool) -> void:
|
|
end_phase_button.disabled = not can_end_phase
|
|
pass_button.disabled = not can_pass
|