layout, card, and design camera fixes
This commit is contained in:
@@ -5,6 +5,7 @@ extends CanvasLayer
|
||||
|
||||
signal end_phase_pressed
|
||||
signal pass_priority_pressed
|
||||
signal field_card_action_requested(card: CardInstance, zone_type: Enums.ZoneType, player_index: int, action: String)
|
||||
|
||||
# UI Components
|
||||
var turn_panel: PanelContainer
|
||||
@@ -28,6 +29,19 @@ var detail_power_label: Label
|
||||
var detail_element_label: Label
|
||||
var detail_ability_label: Label
|
||||
|
||||
# Field card selection panel
|
||||
var field_card_panel: Panel
|
||||
var field_card_image_container: Control
|
||||
var field_card_action_menu: VBoxContainer
|
||||
var selected_field_card: CardInstance = null
|
||||
var selected_field_zone: Enums.ZoneType = Enums.ZoneType.HAND
|
||||
var selected_field_player: int = -1
|
||||
|
||||
# Field card panel sizes (match hand selection panel)
|
||||
const FIELD_CARD_WIDTH: float = 405.0
|
||||
const FIELD_CARD_HEIGHT: float = 567.0
|
||||
const FIELD_MENU_WIDTH: float = 180.0
|
||||
|
||||
# Buttons
|
||||
var end_phase_button: Button
|
||||
var pass_button: Button
|
||||
@@ -204,6 +218,9 @@ func _create_ui() -> void:
|
||||
detail_ability_label.custom_minimum_size.x = 180
|
||||
detail_vbox.add_child(detail_ability_label)
|
||||
|
||||
# === FIELD CARD SELECTION PANEL (centered on screen) ===
|
||||
_create_field_card_panel(root)
|
||||
|
||||
# Message timer
|
||||
message_timer = Timer.new()
|
||||
add_child(message_timer)
|
||||
@@ -347,3 +364,233 @@ func hide_card_detail() -> void:
|
||||
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
|
||||
|
||||
## Create field card selection panel
|
||||
func _create_field_card_panel(root: Control) -> void:
|
||||
field_card_panel = Panel.new()
|
||||
field_card_panel.visible = false
|
||||
field_card_panel.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
field_card_panel.z_index = 200
|
||||
|
||||
var style = StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.08, 0.08, 0.12, 0.95)
|
||||
style.border_color = Color(0.5, 0.4, 0.2)
|
||||
style.set_border_width_all(2)
|
||||
style.set_corner_radius_all(6)
|
||||
style.content_margin_left = 15
|
||||
style.content_margin_right = 15
|
||||
style.content_margin_top = 15
|
||||
style.content_margin_bottom = 15
|
||||
field_card_panel.add_theme_stylebox_override("panel", style)
|
||||
|
||||
root.add_child(field_card_panel)
|
||||
|
||||
var hbox = HBoxContainer.new()
|
||||
hbox.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
hbox.add_theme_constant_override("separation", 20)
|
||||
field_card_panel.add_child(hbox)
|
||||
|
||||
# Card image
|
||||
field_card_image_container = Control.new()
|
||||
field_card_image_container.custom_minimum_size = Vector2(FIELD_CARD_WIDTH, FIELD_CARD_HEIGHT)
|
||||
field_card_image_container.clip_contents = false
|
||||
hbox.add_child(field_card_image_container)
|
||||
|
||||
# Action menu
|
||||
field_card_action_menu = VBoxContainer.new()
|
||||
field_card_action_menu.custom_minimum_size = Vector2(FIELD_MENU_WIDTH, FIELD_CARD_HEIGHT)
|
||||
field_card_action_menu.add_theme_constant_override("separation", 10)
|
||||
hbox.add_child(field_card_action_menu)
|
||||
|
||||
var panel_width = 15 + FIELD_CARD_WIDTH + 20 + FIELD_MENU_WIDTH + 15
|
||||
var panel_height = 15 + FIELD_CARD_HEIGHT + 15
|
||||
field_card_panel.custom_minimum_size = Vector2(panel_width, panel_height)
|
||||
field_card_panel.size = Vector2(panel_width, panel_height)
|
||||
|
||||
## Show field card selection panel with context-sensitive actions
|
||||
func show_field_card_selection(card: CardInstance, zone_type: Enums.ZoneType, player_index: int) -> void:
|
||||
if not card or not card.card_data:
|
||||
return
|
||||
|
||||
selected_field_card = card
|
||||
selected_field_zone = zone_type
|
||||
selected_field_player = player_index
|
||||
|
||||
# Clear previous content
|
||||
for child in field_card_image_container.get_children():
|
||||
child.queue_free()
|
||||
for child in field_card_action_menu.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# Card image
|
||||
var texture = CardDatabase.get_card_texture(card.card_data)
|
||||
if texture:
|
||||
var tex_rect = TextureRect.new()
|
||||
tex_rect.texture = texture
|
||||
tex_rect.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
tex_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
tex_rect.stretch_mode = TextureRect.STRETCH_SCALE
|
||||
tex_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
field_card_image_container.add_child(tex_rect)
|
||||
else:
|
||||
var color_rect = ColorRect.new()
|
||||
color_rect.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
color_rect.color = Enums.get_element_color(card.card_data.get_primary_element()).lightened(0.4)
|
||||
field_card_image_container.add_child(color_rect)
|
||||
|
||||
# Context-sensitive action buttons
|
||||
var is_current_player = GameManager.game_state and player_index == GameManager.game_state.turn_manager.current_player_index
|
||||
var phase = GameManager.get_current_phase() if GameManager.game_state else Enums.TurnPhase.ACTIVE
|
||||
|
||||
if is_current_player:
|
||||
match zone_type:
|
||||
Enums.ZoneType.FIELD_BACKUPS:
|
||||
if not card.is_dull() and (phase == Enums.TurnPhase.MAIN_1 or phase == Enums.TurnPhase.MAIN_2):
|
||||
_add_field_action_button("Dull for CP", "dull_cp")
|
||||
|
||||
Enums.ZoneType.FIELD_FORWARDS:
|
||||
if card.can_attack() and phase == Enums.TurnPhase.ATTACK:
|
||||
_add_field_action_button("Attack", "attack")
|
||||
|
||||
# Always show card info
|
||||
_add_field_card_info(card)
|
||||
_add_field_action_button("Close", "cancel")
|
||||
|
||||
# Position same as hand selection panel: centered horizontally, above hand area
|
||||
var viewport = get_viewport()
|
||||
if viewport:
|
||||
var vp_size = viewport.get_visible_rect().size
|
||||
var panel_w = field_card_panel.size.x
|
||||
var panel_h = field_card_panel.size.y
|
||||
|
||||
# Center horizontally on screen
|
||||
var panel_x = (vp_size.x - panel_w) / 2.0
|
||||
|
||||
# Position above the hand area (hand cards are ~373px from bottom)
|
||||
# Match hand panel: bottom of panel sits ~20px above hand cards
|
||||
var hand_top_y = vp_size.y - 100.0 - 273.0 # Same calc as Main._position_hand_display
|
||||
var panel_y = hand_top_y - panel_h - 20.0
|
||||
|
||||
# Clamp to stay on screen (don't go above top bar)
|
||||
if panel_y < 90.0:
|
||||
panel_y = 90.0
|
||||
|
||||
field_card_panel.position = Vector2(panel_x, panel_y)
|
||||
|
||||
# Hide the old detail panel
|
||||
card_detail_panel.visible = false
|
||||
field_card_panel.visible = true
|
||||
|
||||
## Add card info labels to the action menu
|
||||
func _add_field_card_info(card: CardInstance) -> void:
|
||||
var data = card.card_data
|
||||
|
||||
# Card name header
|
||||
var name_label = Label.new()
|
||||
name_label.text = data.name
|
||||
name_label.add_theme_font_size_override("font_size", 16)
|
||||
name_label.add_theme_color_override("font_color", Color(0.9, 0.85, 0.7))
|
||||
field_card_action_menu.add_child(name_label)
|
||||
|
||||
# Type / Element / Cost
|
||||
var info_label = Label.new()
|
||||
var type_str = Enums.card_type_to_string(data.type)
|
||||
var elem_strs = []
|
||||
for elem in data.elements:
|
||||
elem_strs.append(Enums.element_to_string(elem))
|
||||
info_label.text = type_str + " | " + "/".join(elem_strs) + " | Cost: " + str(data.cost)
|
||||
info_label.add_theme_font_size_override("font_size", 12)
|
||||
info_label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
field_card_action_menu.add_child(info_label)
|
||||
|
||||
# Power (if applicable)
|
||||
if data.type == Enums.CardType.FORWARD or data.power > 0:
|
||||
var power_label = Label.new()
|
||||
power_label.text = "Power: " + str(card.get_power())
|
||||
power_label.add_theme_font_size_override("font_size", 12)
|
||||
field_card_action_menu.add_child(power_label)
|
||||
|
||||
# State
|
||||
var state_label = Label.new()
|
||||
state_label.text = "Status: " + ("Dull" if card.is_dull() else "Active")
|
||||
state_label.add_theme_font_size_override("font_size", 12)
|
||||
field_card_action_menu.add_child(state_label)
|
||||
|
||||
# Separator before abilities
|
||||
var sep = HSeparator.new()
|
||||
field_card_action_menu.add_child(sep)
|
||||
|
||||
# Abilities
|
||||
if data.abilities.size() > 0:
|
||||
for ability in data.abilities:
|
||||
var ability_label = Label.new()
|
||||
var type_prefix = ""
|
||||
match ability.type:
|
||||
Enums.AbilityType.FIELD: type_prefix = "[Field] "
|
||||
Enums.AbilityType.AUTO: type_prefix = "[Auto] "
|
||||
Enums.AbilityType.ACTION: type_prefix = "[Action] "
|
||||
Enums.AbilityType.SPECIAL: type_prefix = "[Special] "
|
||||
ability_label.text = type_prefix + ability.effect
|
||||
ability_label.add_theme_font_size_override("font_size", 11)
|
||||
ability_label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
ability_label.custom_minimum_size.x = FIELD_MENU_WIDTH - 10
|
||||
field_card_action_menu.add_child(ability_label)
|
||||
else:
|
||||
var no_ability = Label.new()
|
||||
no_ability.text = "No abilities"
|
||||
no_ability.add_theme_font_size_override("font_size", 11)
|
||||
field_card_action_menu.add_child(no_ability)
|
||||
|
||||
var sep2 = HSeparator.new()
|
||||
field_card_action_menu.add_child(sep2)
|
||||
|
||||
## Add a styled action button to the field card panel
|
||||
func _add_field_action_button(text: String, action: String) -> void:
|
||||
var button = Button.new()
|
||||
button.text = text
|
||||
button.custom_minimum_size = Vector2(FIELD_MENU_WIDTH - 10, 40)
|
||||
|
||||
var style_normal = StyleBoxFlat.new()
|
||||
style_normal.bg_color = Color(0.25, 0.25, 0.3)
|
||||
style_normal.border_color = Color(0.5, 0.5, 0.6)
|
||||
style_normal.set_border_width_all(1)
|
||||
style_normal.set_corner_radius_all(5)
|
||||
style_normal.content_margin_top = 8
|
||||
style_normal.content_margin_bottom = 8
|
||||
button.add_theme_stylebox_override("normal", style_normal)
|
||||
|
||||
var style_hover = StyleBoxFlat.new()
|
||||
style_hover.bg_color = Color(0.35, 0.35, 0.45)
|
||||
style_hover.border_color = Color(0.7, 0.6, 0.3)
|
||||
style_hover.set_border_width_all(2)
|
||||
style_hover.set_corner_radius_all(5)
|
||||
style_hover.content_margin_top = 8
|
||||
style_hover.content_margin_bottom = 8
|
||||
button.add_theme_stylebox_override("hover", style_hover)
|
||||
|
||||
var style_pressed = StyleBoxFlat.new()
|
||||
style_pressed.bg_color = Color(0.2, 0.2, 0.25)
|
||||
style_pressed.border_color = Color(0.7, 0.6, 0.3)
|
||||
style_pressed.set_border_width_all(2)
|
||||
style_pressed.set_corner_radius_all(5)
|
||||
style_pressed.content_margin_top = 8
|
||||
style_pressed.content_margin_bottom = 8
|
||||
button.add_theme_stylebox_override("pressed", style_pressed)
|
||||
|
||||
button.add_theme_font_size_override("font_size", 14)
|
||||
button.pressed.connect(_on_field_action_pressed.bind(action))
|
||||
field_card_action_menu.add_child(button)
|
||||
|
||||
func _on_field_action_pressed(action: String) -> void:
|
||||
if action == "cancel":
|
||||
hide_field_card_selection()
|
||||
return
|
||||
|
||||
if selected_field_card:
|
||||
field_card_action_requested.emit(selected_field_card, selected_field_zone, selected_field_player, action)
|
||||
hide_field_card_selection()
|
||||
|
||||
## Hide field card selection panel
|
||||
func hide_field_card_selection() -> void:
|
||||
field_card_panel.visible = false
|
||||
selected_field_card = null
|
||||
|
||||
Reference in New Issue
Block a user