started working on fog darkness
This commit is contained in:
@@ -7,36 +7,41 @@ extends CanvasLayer
|
||||
|
||||
var is_open: bool = false
|
||||
var local_player: Node = null
|
||||
var is_updating_ui: bool = false # Prevent recursive UI updates
|
||||
|
||||
# Selection tracking
|
||||
var selected_item: Item = null # Selected inventory item
|
||||
var selected_slot: String = "" # Selected equipment slot name
|
||||
var selected_type: String = "" # "item" or "equipment"
|
||||
var selected_item: Item = null # Selected inventory item
|
||||
var selected_slot: String = "" # Selected equipment slot name
|
||||
var selected_type: String = "" # "item" or "equipment"
|
||||
var is_first_open: bool = true # Track if this is the first time opening
|
||||
|
||||
# Navigation tracking (for keyboard navigation)
|
||||
var inventory_selection_row: int = 0 # Current inventory row (0-based)
|
||||
var inventory_selection_col: int = 0 # Current inventory column (0-based)
|
||||
var equipment_selection_index: int = 0 # Current equipment slot index (0-5: mainhand, offhand, headgear, armour, boots, accessory)
|
||||
var inventory_selection_row: int = 0 # Current inventory row (0-based)
|
||||
var inventory_selection_col: int = 0 # Current inventory column (0-based)
|
||||
var equipment_selection_index: int = 0 # Current equipment slot index (0-5: mainhand, offhand, headgear, armour, boots, accessory)
|
||||
|
||||
# UI Nodes (from scene)
|
||||
@onready var container: Control = $InventoryContainer
|
||||
@onready var stats_panel: Control = $InventoryContainer/MarginContainer/VBoxContainer/HBox/StatsPanel
|
||||
@onready var equipment_panel: GridContainer = $InventoryContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/EquipmentPanel
|
||||
@onready var scroll_container: ScrollContainer = $InventoryContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/InventoryScroll
|
||||
@onready var inventory_grid: VBoxContainer = $InventoryContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/InventoryScroll/InventoryVBox
|
||||
@onready var selection_rectangle: Panel = $InventoryContainer/MarginContainer/VBoxContainer/SelectionRectangle
|
||||
@onready var info_panel: Control = $InventoryContainer/MarginContainer/VBoxContainer/InfoPanel
|
||||
@onready var info_label: Label = $InventoryContainer/MarginContainer/VBoxContainer/InfoPanel/InfoLabel
|
||||
@onready var label_base_stats: Label = $InventoryContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelBaseStats
|
||||
@onready var label_base_stats_value: Label = $InventoryContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelBaseStatsValue
|
||||
@onready var label_derived_stats: Label = $InventoryContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelDerivedStats
|
||||
@onready var label_derived_stats_value: Label = $InventoryContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelDerivedStatsValue
|
||||
@onready var stats_panel: Control = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel
|
||||
@onready var equipment_panel: GridContainer = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/EquipmentPanel
|
||||
@onready var scroll_container: ScrollContainer = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/InventoryScroll
|
||||
@onready var inventory_grid: VBoxContainer = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/InventoryScroll/InventoryVBox
|
||||
@onready var selection_rectangle: Panel = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/SelectionRectangle
|
||||
@onready var info_panel: Control = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/InfoPanel
|
||||
@onready var info_label: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/InfoPanel/InfoLabel
|
||||
@onready var label_base_stats: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelBaseStats
|
||||
@onready var label_base_stats_value: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelBaseStatsValue
|
||||
@onready var label_derived_stats: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelDerivedStats
|
||||
@onready var label_derived_stats_value: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelDerivedStatsValue
|
||||
@onready var sfx_potion: AudioStreamPlayer2D = $SfxPotion
|
||||
@onready var sfx_food: AudioStreamPlayer2D = $SfxFood
|
||||
@onready var sfx_armour: AudioStreamPlayer2D = $SfxArmour
|
||||
|
||||
# Store button/item mappings for selection highlighting
|
||||
var inventory_buttons: Dictionary = {} # item -> button
|
||||
var equipment_buttons: Dictionary = {} # slot_name -> button
|
||||
var inventory_items_list: Array = [] # Flat list of items for navigation
|
||||
var inventory_rows_list: Array = [] # List of HBoxContainers (rows)
|
||||
var inventory_buttons: Dictionary = {} # item -> button
|
||||
var equipment_buttons: Dictionary = {} # slot_name -> button
|
||||
var inventory_items_list: Array = [] # Flat list of items for navigation
|
||||
var inventory_rows_list: Array = [] # List of HBoxContainers (rows)
|
||||
|
||||
# Equipment slot buttons
|
||||
var equipment_slots: Dictionary = {
|
||||
@@ -47,7 +52,7 @@ var equipment_slots: Dictionary = {
|
||||
"boots": null,
|
||||
"accessory": null
|
||||
}
|
||||
var equipment_slots_list: Array = ["mainhand", "offhand", "headgear", "armour", "boots", "accessory"] # Order for navigation
|
||||
var equipment_slots_list: Array = ["mainhand", "offhand", "headgear", "armour", "boots", "accessory"] # Order for navigation
|
||||
|
||||
# StyleBoxes for inventory slots (like inspiration system)
|
||||
var style_box_hover: StyleBox = null
|
||||
@@ -65,10 +70,7 @@ func _ready():
|
||||
|
||||
# Load styleboxes for inventory slots (like inspiration system)
|
||||
_setup_styleboxes()
|
||||
|
||||
# Setup fonts for labels
|
||||
_setup_fonts()
|
||||
|
||||
|
||||
# Create equipment slot buttons (dynamically)
|
||||
_create_equipment_slots()
|
||||
|
||||
@@ -79,23 +81,40 @@ func _ready():
|
||||
call_deferred("_find_local_player")
|
||||
|
||||
func _setup_styleboxes():
|
||||
# Create styleboxes similar to inspiration inventory system
|
||||
var slot_texture = preload("res://assets/gfx/ui/inventory_slot_kenny_white.png")
|
||||
if not slot_texture:
|
||||
# Fallback if texture doesn't exist
|
||||
slot_texture = null
|
||||
# Create styleboxes exactly like inspiration inventory system
|
||||
var selected_tex = preload("res://assets/gfx/ui/inventory_slot_kenny_white.png")
|
||||
|
||||
style_box_empty = StyleBoxEmpty.new()
|
||||
|
||||
if slot_texture:
|
||||
if selected_tex:
|
||||
# Scale factor for the slot background (1.5x to match larger item sprites)
|
||||
# Since StyleBoxTexture doesn't support texture_scale, we use expand_margin
|
||||
# to make the texture fill more space
|
||||
# For 1.5x scale on a 36px button (which was 24px originally), we need to expand
|
||||
# The button is now 36px, so to make a 24px texture appear 1.5x (36px), we use negative margins
|
||||
# Actually, let's use smaller positive margins to avoid clipping
|
||||
var margin_scale = 3.0 # Smaller margin to avoid clipping in upper left corner
|
||||
|
||||
style_box_hover = StyleBoxTexture.new()
|
||||
style_box_hover.texture = slot_texture
|
||||
style_box_hover.texture = selected_tex
|
||||
style_box_hover.expand_margin_left = margin_scale
|
||||
style_box_hover.expand_margin_top = margin_scale
|
||||
style_box_hover.expand_margin_right = margin_scale
|
||||
style_box_hover.expand_margin_bottom = margin_scale
|
||||
|
||||
style_box_focused = StyleBoxTexture.new()
|
||||
style_box_focused.texture = slot_texture
|
||||
style_box_focused.texture = selected_tex
|
||||
style_box_focused.expand_margin_left = margin_scale
|
||||
style_box_focused.expand_margin_top = margin_scale
|
||||
style_box_focused.expand_margin_right = margin_scale
|
||||
style_box_focused.expand_margin_bottom = margin_scale
|
||||
|
||||
style_box_pressed = StyleBoxTexture.new()
|
||||
style_box_pressed.texture = slot_texture
|
||||
style_box_pressed.texture = selected_tex
|
||||
style_box_pressed.expand_margin_left = margin_scale
|
||||
style_box_pressed.expand_margin_top = margin_scale
|
||||
style_box_pressed.expand_margin_right = margin_scale
|
||||
style_box_pressed.expand_margin_bottom = margin_scale
|
||||
else:
|
||||
# Fallback to empty styleboxes if texture not found
|
||||
style_box_hover = StyleBoxEmpty.new()
|
||||
@@ -106,41 +125,17 @@ func _setup_styleboxes():
|
||||
if ResourceLoader.exists("res://assets/fonts/dmg_numbers.png"):
|
||||
quantity_font = load("res://assets/fonts/dmg_numbers.png")
|
||||
|
||||
func _setup_fonts():
|
||||
# Setup fonts for labels (standard_font.png)
|
||||
var standard_font_resource = null
|
||||
if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
|
||||
standard_font_resource = load("res://assets/fonts/standard_font.png")
|
||||
if standard_font_resource:
|
||||
# Stats panel labels
|
||||
if label_base_stats:
|
||||
label_base_stats.add_theme_font_override("font", standard_font_resource)
|
||||
if label_base_stats_value:
|
||||
label_base_stats_value.add_theme_font_override("font", standard_font_resource)
|
||||
if label_derived_stats:
|
||||
label_derived_stats.add_theme_font_override("font", standard_font_resource)
|
||||
if label_derived_stats_value:
|
||||
label_derived_stats_value.add_theme_font_override("font", standard_font_resource)
|
||||
|
||||
# Info label
|
||||
if info_label:
|
||||
info_label.add_theme_font_override("font", standard_font_resource)
|
||||
|
||||
# Equipment and Inventory labels
|
||||
var eq_label = container.get_node_or_null("MarginContainer/VBoxContainer/HBox/InventoryPanel/EquipmentLabel")
|
||||
if eq_label:
|
||||
eq_label.add_theme_font_override("font", standard_font_resource)
|
||||
var inv_label = container.get_node_or_null("MarginContainer/VBoxContainer/HBox/InventoryPanel/InventoryLabel")
|
||||
if inv_label:
|
||||
inv_label.add_theme_font_override("font", standard_font_resource)
|
||||
var stats_label = container.get_node_or_null("MarginContainer/VBoxContainer/HBox/StatsPanel/StatsLabel")
|
||||
if stats_label:
|
||||
stats_label.add_theme_font_override("font", standard_font_resource)
|
||||
|
||||
func _setup_selection_rectangle():
|
||||
# Selection rectangle is already in scene, just ensure it's configured correctly
|
||||
if selection_rectangle:
|
||||
selection_rectangle.visible = false
|
||||
# Ensure it's on top and visible
|
||||
selection_rectangle.z_index = 100
|
||||
selection_rectangle.z_as_relative = false
|
||||
selection_rectangle.mouse_filter = Control.MOUSE_FILTER_IGNORE # Don't block mouse input
|
||||
# Ensure it's on top
|
||||
selection_rectangle.z_index = 100
|
||||
selection_rectangle.z_as_relative = false
|
||||
|
||||
func _find_local_player():
|
||||
# Find the local player
|
||||
@@ -207,7 +202,6 @@ func _create_equipment_slots():
|
||||
label.text = slot_label
|
||||
label.add_theme_font_size_override("font_size", 10)
|
||||
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
var standard_font_resource = null
|
||||
if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
|
||||
var font_resource = load("res://assets/fonts/standard_font.png")
|
||||
if font_resource:
|
||||
@@ -217,8 +211,9 @@ func _create_equipment_slots():
|
||||
# Button (use styleboxes like inspiration system)
|
||||
var button = Button.new()
|
||||
button.name = slot_name + "_btn"
|
||||
button.custom_minimum_size = Vector2(24, 24) # Smaller like inspiration (24x24 instead of 60x60)
|
||||
button.size = Vector2(24, 24)
|
||||
# Button size increased to accommodate 1.5x scaled texture (24 * 1.5 = 36)
|
||||
button.custom_minimum_size = Vector2(36, 36) # Increased to fit 1.5x scaled texture
|
||||
button.size = Vector2(36, 36)
|
||||
if style_box_empty:
|
||||
button.add_theme_stylebox_override("normal", style_box_empty)
|
||||
if style_box_hover:
|
||||
@@ -227,8 +222,16 @@ func _create_equipment_slots():
|
||||
button.add_theme_stylebox_override("focus", style_box_focused)
|
||||
if style_box_pressed:
|
||||
button.add_theme_stylebox_override("pressed", style_box_pressed)
|
||||
button.flat = false # Use styleboxes instead of flat
|
||||
button.flat = false # Use styleboxes instead of flat
|
||||
button.focus_mode = Control.FOCUS_ALL # Allow button to receive focus
|
||||
button.size_flags_horizontal = 0
|
||||
button.size_flags_vertical = 0
|
||||
button.connect("pressed", _on_equipment_slot_pressed.bind(slot_name))
|
||||
# Connect focus_entered like inspiration system (for keyboard navigation)
|
||||
if local_player and local_player.character_stats:
|
||||
var equipped_item = local_player.character_stats.equipment[slot_name]
|
||||
if equipped_item:
|
||||
button.connect("focus_entered", _on_equipment_slot_pressed.bind(slot_name))
|
||||
slot_container.add_child(button)
|
||||
|
||||
equipment_slots[slot_name] = button
|
||||
@@ -259,6 +262,10 @@ func _on_equipment_slot_pressed(slot_name: String):
|
||||
if not local_player or not local_player.character_stats:
|
||||
return
|
||||
|
||||
# Prevent updates during UI refresh (prevents infinite loops from focus_entered)
|
||||
if is_updating_ui:
|
||||
return
|
||||
|
||||
# Only select if there's an item equipped
|
||||
if not _has_equipment_in_slot(slot_name):
|
||||
return
|
||||
@@ -276,85 +283,110 @@ func _on_equipment_slot_pressed(slot_name: String):
|
||||
_update_selection_rectangle()
|
||||
|
||||
func _update_selection_highlight():
|
||||
# Reset all button styles
|
||||
for button in equipment_buttons.values():
|
||||
if button:
|
||||
var highlight = button.get_node_or_null("Highlight")
|
||||
if highlight:
|
||||
highlight.queue_free()
|
||||
|
||||
for button in inventory_buttons.values():
|
||||
if button:
|
||||
var highlight = button.get_node_or_null("Highlight")
|
||||
if highlight:
|
||||
highlight.queue_free()
|
||||
# This function is kept for compatibility but now uses _update_selection_rectangle()
|
||||
_update_selection_rectangle()
|
||||
|
||||
# Removed _clear_button_highlight and _apply_button_highlight - using focus system instead
|
||||
|
||||
func _update_selection_rectangle():
|
||||
# Update visual selection rectangle position and visibility
|
||||
if not selection_rectangle:
|
||||
return
|
||||
|
||||
var target_button: Button = null
|
||||
var target_position: Vector2 = Vector2.ZERO
|
||||
var should_show: bool = false
|
||||
|
||||
# Get the parent of selection_rectangle (VBoxContainer) to calculate relative positions
|
||||
var selection_parent = selection_rectangle.get_parent()
|
||||
if not selection_parent:
|
||||
# Update visual selection indicator - use button focus like inspiration system
|
||||
# Hide the old selection rectangle
|
||||
if selection_rectangle:
|
||||
selection_rectangle.visible = false
|
||||
return
|
||||
|
||||
# Find and focus the selected button (like inspiration system uses grab_focus())
|
||||
var target_button: Button = null
|
||||
|
||||
if selected_type == "equipment" and selected_slot != "":
|
||||
# Show rectangle on equipment slot (only if it has an item)
|
||||
# Focus equipment slot (only if it has an item)
|
||||
if _has_equipment_in_slot(selected_slot):
|
||||
target_button = equipment_buttons.get(selected_slot)
|
||||
if target_button and target_button.is_inside_tree():
|
||||
# Get button position relative to selection_rectangle's parent (VBoxContainer)
|
||||
var button_global_pos = target_button.global_position
|
||||
var parent_global_pos = selection_parent.global_position
|
||||
target_position = button_global_pos - parent_global_pos
|
||||
should_show = true
|
||||
elif selected_type == "item" and inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||
# Show rectangle on inventory item
|
||||
# Focus inventory item
|
||||
var row = inventory_rows_list[inventory_selection_row]
|
||||
if row and inventory_selection_col >= 0 and inventory_selection_col < row.get_child_count():
|
||||
target_button = row.get_child(inventory_selection_col) as Button
|
||||
if target_button and target_button.is_inside_tree():
|
||||
# Get button position relative to selection_rectangle's parent (VBoxContainer)
|
||||
var button_global_pos = target_button.global_position
|
||||
var parent_global_pos = selection_parent.global_position
|
||||
target_position = button_global_pos - parent_global_pos
|
||||
should_show = true
|
||||
|
||||
# Only show and position if we have a valid target
|
||||
if should_show and target_button:
|
||||
selection_rectangle.visible = true
|
||||
selection_rectangle.position = target_position
|
||||
selection_rectangle.size = Vector2(38, 38)
|
||||
# Grab focus on selected button (this will automatically show the focus stylebox)
|
||||
if target_button:
|
||||
if target_button.is_inside_tree():
|
||||
# Don't grab focus if button already has focus (prevents infinite loops)
|
||||
if target_button.has_focus():
|
||||
return
|
||||
|
||||
# Ensure button is visible and ready
|
||||
if not target_button.visible:
|
||||
target_button.visible = true
|
||||
# Wait a frame to ensure button is fully ready for focus
|
||||
await get_tree().process_frame
|
||||
# Check again if already focused (might have changed during await)
|
||||
if target_button.has_focus():
|
||||
return
|
||||
# Ensure button can receive focus
|
||||
if target_button.focus_mode == Control.FOCUS_NONE:
|
||||
target_button.focus_mode = Control.FOCUS_ALL
|
||||
# Try direct grab_focus (only if not already focused)
|
||||
if not target_button.has_focus():
|
||||
target_button.grab_focus()
|
||||
# Also use call_deferred as backup to ensure it's set
|
||||
target_button.call_deferred("grab_focus")
|
||||
print("InventoryUI: Focus grabbed on button - has_focus: ", target_button.has_focus())
|
||||
else:
|
||||
# If not in tree yet, wait a frame and try again
|
||||
await get_tree().process_frame
|
||||
if target_button.is_inside_tree():
|
||||
target_button.grab_focus()
|
||||
target_button.call_deferred("grab_focus")
|
||||
print("InventoryUI: Focus grabbed on button (after wait)")
|
||||
else:
|
||||
print("InventoryUI: Button still not in tree after wait")
|
||||
else:
|
||||
selection_rectangle.visible = false
|
||||
print("InventoryUI: No button to focus - selected_type: ", selected_type)
|
||||
|
||||
func _process(delta):
|
||||
if is_open and selection_rectangle and selection_rectangle.visible:
|
||||
# Animate selection rectangle border color
|
||||
selection_animation_time += delta * 2.0 # Speed of animation
|
||||
if is_open:
|
||||
# Animate selection highlight border color on selected button
|
||||
selection_animation_time += delta * 2.0 # Speed of animation
|
||||
# Animate between yellow and orange
|
||||
var color1 = Color.YELLOW
|
||||
var color2 = Color(1.0, 0.7, 0.0) # Orange-yellow
|
||||
var t = (sin(selection_animation_time) + 1.0) / 2.0 # 0 to 1
|
||||
var color2 = Color(1.0, 0.7, 0.0) # Orange-yellow
|
||||
var t = (sin(selection_animation_time) + 1.0) / 2.0 # 0 to 1
|
||||
var animated_color = color1.lerp(color2, t)
|
||||
|
||||
# Update border color
|
||||
var stylebox = selection_rectangle.get_theme_stylebox("panel") as StyleBoxFlat
|
||||
if stylebox:
|
||||
stylebox.border_color = animated_color
|
||||
# Find the selected button and update its highlight color
|
||||
var selected_button: Button = null
|
||||
if selected_type == "equipment" and selected_slot != "":
|
||||
if _has_equipment_in_slot(selected_slot):
|
||||
selected_button = equipment_buttons.get(selected_slot)
|
||||
elif selected_type == "item" and inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||
var row = inventory_rows_list[inventory_selection_row]
|
||||
if row and inventory_selection_col >= 0 and inventory_selection_col < row.get_child_count():
|
||||
selected_button = row.get_child(inventory_selection_col) as Button
|
||||
|
||||
if selected_button and selected_button.has_meta("highlight_stylebox"):
|
||||
var stylebox = selected_button.get_meta("highlight_stylebox") as StyleBoxFlat
|
||||
if stylebox:
|
||||
stylebox.border_color = animated_color
|
||||
|
||||
func _update_ui():
|
||||
if not local_player or not local_player.character_stats:
|
||||
return
|
||||
|
||||
# Prevent recursive updates
|
||||
if is_updating_ui:
|
||||
return
|
||||
is_updating_ui = true
|
||||
|
||||
var char_stats = local_player.character_stats
|
||||
|
||||
# Ensure containers don't clip their children (allows expand_margin to show properly)
|
||||
if scroll_container:
|
||||
scroll_container.clip_contents = false # Allow buttons to extend beyond scroll bounds
|
||||
if inventory_grid:
|
||||
inventory_grid.clip_contents = false # Allow buttons to extend beyond grid bounds
|
||||
if equipment_panel:
|
||||
equipment_panel.clip_contents = false # Allow buttons to extend beyond grid bounds
|
||||
|
||||
# Debug: Print inventory contents
|
||||
print("InventoryUI: Updating UI - inventory size: ", char_stats.inventory.size())
|
||||
for i in range(char_stats.inventory.size()):
|
||||
@@ -366,6 +398,9 @@ func _update_ui():
|
||||
inventory_items_list.clear()
|
||||
inventory_rows_list.clear()
|
||||
|
||||
# Wait for old buttons to be fully freed before creating new ones
|
||||
await get_tree().process_frame
|
||||
|
||||
# Update equipment slots
|
||||
for slot_name in equipment_slots.keys():
|
||||
var button = equipment_slots[slot_name]
|
||||
@@ -389,33 +424,53 @@ func _update_ui():
|
||||
sprite.hframes = equipped_item.spriteFrames.x if equipped_item.spriteFrames.x > 0 else 20
|
||||
sprite.vframes = equipped_item.spriteFrames.y if equipped_item.spriteFrames.y > 0 else 14
|
||||
sprite.frame = equipped_item.spriteFrame
|
||||
sprite.centered = false # Like inspiration system
|
||||
sprite.position = Vector2(4, 4) # Like inspiration system
|
||||
sprite.scale = Vector2(2.0, 2.0) # 2x size as requested
|
||||
sprite.centered = false # Like inspiration system
|
||||
sprite.position = Vector2(4, 4) # Like inspiration system
|
||||
sprite.scale = Vector2(2.0, 2.0) # 2x size as requested
|
||||
button.add_child(sprite)
|
||||
|
||||
# Add quantity label if item can have multiple (like arrows)
|
||||
if equipped_item.can_have_multiple_of and equipped_item.quantity > 1:
|
||||
var quantity_label = Label.new()
|
||||
quantity_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
quantity_label.size = Vector2(24, 24)
|
||||
quantity_label.custom_minimum_size = Vector2(0, 0)
|
||||
quantity_label.position = Vector2(10, 2)
|
||||
quantity_label.text = str(equipped_item.quantity)
|
||||
if quantity_font:
|
||||
quantity_label.add_theme_font_override("font", quantity_font)
|
||||
quantity_label.add_theme_font_size_override("font_size", 8)
|
||||
quantity_label.scale = Vector2(0.5, 0.5)
|
||||
button.add_child(quantity_label)
|
||||
|
||||
# Update inventory grid - clear existing HBoxContainers
|
||||
for child in inventory_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# Wait for old buttons to be fully freed before creating new ones
|
||||
await get_tree().process_frame
|
||||
|
||||
# Add inventory items using HBoxContainers (like inspiration system)
|
||||
var current_hbox: HBoxContainer = null
|
||||
var items_per_row = 10 # Items per row (like inspiration system - they use 10 per HBox)
|
||||
var items_per_row = 8 # Items per row (3 rows = 24 total items max)
|
||||
var items_in_current_row = 0
|
||||
|
||||
for item in char_stats.inventory:
|
||||
# Create new HBoxContainer if needed
|
||||
if current_hbox == null or items_in_current_row >= items_per_row:
|
||||
current_hbox = HBoxContainer.new()
|
||||
current_hbox.add_theme_constant_override("separation", 0) # No separation like inspiration
|
||||
current_hbox.add_theme_constant_override("separation", 0) # No separation like inspiration
|
||||
# Ensure HBoxContainer doesn't clip child buttons
|
||||
current_hbox.clip_contents = false
|
||||
inventory_grid.add_child(current_hbox)
|
||||
inventory_rows_list.append(current_hbox)
|
||||
items_in_current_row = 0
|
||||
|
||||
# Create button with styleboxes (like inspiration system)
|
||||
var button = Button.new()
|
||||
button.custom_minimum_size = Vector2(24, 24) # Smaller like inspiration (24x24)
|
||||
button.size = Vector2(24, 24)
|
||||
# Button size increased to accommodate 1.5x scaled texture (24 * 1.5 = 36)
|
||||
button.custom_minimum_size = Vector2(36, 36) # Increased to fit 1.5x scaled texture
|
||||
button.size = Vector2(36, 36)
|
||||
if style_box_empty:
|
||||
button.add_theme_stylebox_override("normal", style_box_empty)
|
||||
if style_box_hover:
|
||||
@@ -424,8 +479,13 @@ func _update_ui():
|
||||
button.add_theme_stylebox_override("focus", style_box_focused)
|
||||
if style_box_pressed:
|
||||
button.add_theme_stylebox_override("pressed", style_box_pressed)
|
||||
button.flat = false # Use styleboxes
|
||||
button.flat = false # Use styleboxes
|
||||
button.focus_mode = Control.FOCUS_ALL # Allow button to receive focus
|
||||
button.connect("pressed", _on_inventory_item_pressed.bind(item))
|
||||
# Connect focus_entered like inspiration system (for keyboard navigation)
|
||||
# Note: focus_entered will trigger when we call grab_focus(), but _on_inventory_item_pressed
|
||||
# just updates selection state, so it should be safe
|
||||
button.connect("focus_entered", _on_inventory_item_pressed.bind(item))
|
||||
current_hbox.add_child(button)
|
||||
|
||||
# Add item sprite (like inspiration system - positioned at 4,4 with centered=false)
|
||||
@@ -437,23 +497,28 @@ func _update_ui():
|
||||
sprite.hframes = item.spriteFrames.x if item.spriteFrames.x > 0 else 20
|
||||
sprite.vframes = item.spriteFrames.y if item.spriteFrames.y > 0 else 14
|
||||
sprite.frame = item.spriteFrame
|
||||
sprite.centered = false # Like inspiration system
|
||||
sprite.position = Vector2(4, 4) # Like inspiration system
|
||||
sprite.scale = Vector2(2.0, 2.0) # 2x size as requested
|
||||
sprite.centered = false # Like inspiration system
|
||||
sprite.position = Vector2(4, 4) # Like inspiration system
|
||||
sprite.scale = Vector2(2.0, 2.0) # 2x size as requested
|
||||
button.add_child(sprite)
|
||||
|
||||
# Add quantity label if item can have multiple (like inspiration system)
|
||||
if item.can_have_multiple_of and item.quantity > 1:
|
||||
# Add quantity label if item quantity > 1 (show for all stacked items)
|
||||
if item.quantity > 1:
|
||||
var quantity_label = Label.new()
|
||||
quantity_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
quantity_label.size = Vector2(24, 24)
|
||||
quantity_label.custom_minimum_size = Vector2(0, 0)
|
||||
quantity_label.position = Vector2(10, 2)
|
||||
quantity_label.vertical_alignment = VERTICAL_ALIGNMENT_TOP
|
||||
quantity_label.size = Vector2(36, 36)
|
||||
quantity_label.custom_minimum_size = Vector2(36, 36)
|
||||
quantity_label.position = Vector2(0, 0)
|
||||
quantity_label.text = str(item.quantity)
|
||||
if quantity_font:
|
||||
quantity_label.add_theme_font_override("font", quantity_font)
|
||||
quantity_label.add_theme_font_size_override("font_size", 8)
|
||||
quantity_label.scale = Vector2(0.5, 0.5)
|
||||
# Use dmg_numbers.png font (same as damage_number.gd)
|
||||
var dmg_font_resource = load("res://assets/fonts/dmg_numbers.png")
|
||||
if dmg_font_resource:
|
||||
var font_file = FontFile.new()
|
||||
font_file.font_data = dmg_font_resource
|
||||
quantity_label.add_theme_font_override("font", font_file)
|
||||
quantity_label.add_theme_font_size_override("font_size", 16)
|
||||
quantity_label.z_index = 100 # High z-index to show above item sprite
|
||||
button.add_child(quantity_label)
|
||||
|
||||
inventory_buttons[item] = button
|
||||
@@ -468,19 +533,74 @@ func _update_ui():
|
||||
if inventory_selection_col >= row.get_child_count():
|
||||
inventory_selection_col = max(0, row.get_child_count() - 1)
|
||||
|
||||
# Update selection
|
||||
_update_selection_from_navigation()
|
||||
_update_selection_rectangle()
|
||||
_update_info_panel()
|
||||
# Update selection only if selected_type is already set (don't auto-update during initialization)
|
||||
if selected_type != "":
|
||||
_update_selection_from_navigation()
|
||||
_update_selection_rectangle()
|
||||
_update_info_panel()
|
||||
|
||||
_set_selection()
|
||||
|
||||
# Reset update flag
|
||||
is_updating_ui = false
|
||||
|
||||
func _set_selection():
|
||||
# NOW check for items AFTER UI is updated
|
||||
# Initialize selection - prefer inventory, but if empty, check equipment
|
||||
# Check if we have inventory items
|
||||
if inventory_rows_list.size() > 0 and inventory_items_list.size() > 0:
|
||||
selected_type = "item"
|
||||
inventory_selection_row = 0
|
||||
inventory_selection_col = 0
|
||||
# Ensure selection is set correctly
|
||||
_update_selection_from_navigation()
|
||||
# Debug: Print selection state
|
||||
print("InventoryUI: Initial selection - type: ", selected_type, " row: ", inventory_selection_row, " col: ", inventory_selection_col, " item: ", selected_item)
|
||||
# Now set focus - buttons should be ready
|
||||
await _update_selection_rectangle() # Await to ensure focus is set
|
||||
_update_info_panel()
|
||||
else:
|
||||
# No inventory items, try equipment
|
||||
var first_filled_slot = _find_next_filled_equipment_slot(-1, 1)
|
||||
if first_filled_slot >= 0:
|
||||
selected_type = "equipment"
|
||||
equipment_selection_index = first_filled_slot
|
||||
selected_slot = equipment_slots_list[first_filled_slot]
|
||||
# Ensure selection is set correctly
|
||||
_update_selection_from_navigation()
|
||||
# Debug: Print selection state
|
||||
print("InventoryUI: Initial selection - type: ", selected_type, " slot: ", selected_slot, " item: ", selected_item)
|
||||
# Now set focus - buttons should be ready
|
||||
await _update_selection_rectangle() # Await to ensure focus is set
|
||||
_update_info_panel()
|
||||
else:
|
||||
# Nothing to select (only print this AFTER UI is updated)
|
||||
selected_type = ""
|
||||
if selection_rectangle:
|
||||
selection_rectangle.visible = false
|
||||
if info_label:
|
||||
info_label.text = ""
|
||||
print("InventoryUI: No items to select")
|
||||
pass
|
||||
|
||||
func _update_selection_from_navigation():
|
||||
# Update selected_item/selected_slot based on navigation position
|
||||
# Early return if selected_type is not set yet (prevents errors during initialization)
|
||||
if selected_type == "":
|
||||
print("InventoryUI: _update_selection_from_navigation() - selected_type is empty, skipping")
|
||||
return
|
||||
|
||||
print("InventoryUI: _update_selection_from_navigation() - selected_type: ", selected_type, " inventory_rows_list.size(): ", inventory_rows_list.size(), " inventory_items_list.size(): ", inventory_items_list.size())
|
||||
|
||||
if selected_type == "equipment" and equipment_selection_index >= 0 and equipment_selection_index < equipment_slots_list.size():
|
||||
var slot_name = equipment_slots_list[equipment_selection_index]
|
||||
if _has_equipment_in_slot(slot_name):
|
||||
selected_slot = slot_name
|
||||
if local_player and local_player.character_stats:
|
||||
selected_item = local_player.character_stats.equipment[slot_name]
|
||||
else:
|
||||
selected_item = null
|
||||
print("InventoryUI: Selected equipment slot: ", slot_name, " item: ", selected_item)
|
||||
else:
|
||||
# Empty slot - switch to inventory
|
||||
selected_type = "item"
|
||||
@@ -492,21 +612,35 @@ func _update_selection_from_navigation():
|
||||
_update_selection_from_navigation()
|
||||
elif selected_type == "item" and inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||
var row = inventory_rows_list[inventory_selection_row]
|
||||
if inventory_selection_col >= 0 and inventory_selection_col < row.get_child_count():
|
||||
print("InventoryUI: Checking item selection - row: ", inventory_selection_row, " col: ", inventory_selection_col, " row exists: ", row != null, " row child count: ", row.get_child_count() if row else 0)
|
||||
if row and inventory_selection_col >= 0 and inventory_selection_col < row.get_child_count():
|
||||
var item_index = inventory_selection_row * 10 + inventory_selection_col
|
||||
print("InventoryUI: Calculated item_index: ", item_index, " inventory_items_list.size(): ", inventory_items_list.size())
|
||||
if item_index >= 0 and item_index < inventory_items_list.size():
|
||||
selected_item = inventory_items_list[item_index]
|
||||
selected_slot = ""
|
||||
print("InventoryUI: Selected inventory item: ", selected_item.item_name if selected_item else "null")
|
||||
else:
|
||||
selected_item = null
|
||||
selected_slot = ""
|
||||
print("InventoryUI: item_index out of range!")
|
||||
else:
|
||||
selected_item = null
|
||||
selected_slot = ""
|
||||
print("InventoryUI: Row or column invalid!")
|
||||
else:
|
||||
print("InventoryUI: selected_type invalid or row out of range!")
|
||||
|
||||
func _format_item_info(item: Item) -> String:
|
||||
# Format item description, stats modifiers, and controls
|
||||
var text = ""
|
||||
|
||||
# Item name (always show)
|
||||
text += item.item_name
|
||||
|
||||
# Description
|
||||
if item.description != "":
|
||||
text += item.description
|
||||
else:
|
||||
text += item.item_name
|
||||
text += "\n" + item.description
|
||||
|
||||
text += "\n\n"
|
||||
|
||||
@@ -538,7 +672,7 @@ func _format_item_info(item: Item) -> String:
|
||||
stat_lines.append("MAXMP: +%d" % item.modifiers["maxmp"])
|
||||
|
||||
if stat_lines.size() > 0:
|
||||
text += "\n".join(stat_lines)
|
||||
text += ", ".join(stat_lines)
|
||||
text += "\n\n"
|
||||
|
||||
# Controls
|
||||
@@ -550,25 +684,28 @@ func _format_item_info(item: Item) -> String:
|
||||
elif item.item_type == Item.ItemType.Restoration:
|
||||
text += "Press F to consume"
|
||||
|
||||
# Only show "Press E to drop" for inventory items, not equipment
|
||||
if selected_type == "item":
|
||||
text += "\nPress E to drop"
|
||||
text += ", Press E to drop"
|
||||
|
||||
return text
|
||||
|
||||
func _update_info_panel():
|
||||
# Update info panel based on selected item
|
||||
if not info_label:
|
||||
print("InventoryUI: _update_info_panel() - info_label is null!")
|
||||
return
|
||||
|
||||
print("InventoryUI: _update_info_panel() - selected_item: ", selected_item, " selected_type: ", selected_type)
|
||||
if selected_item:
|
||||
info_label.text = _format_item_info(selected_item)
|
||||
print("InventoryUI: Info panel text set: ", info_label.text.substr(0, 50) if info_label.text.length() > 50 else info_label.text)
|
||||
else:
|
||||
info_label.text = ""
|
||||
print("InventoryUI: Info panel text cleared (no selected_item)")
|
||||
|
||||
func _navigate_inventory(direction: String):
|
||||
# Handle navigation within inventory
|
||||
var items_per_row = 10
|
||||
|
||||
match direction:
|
||||
"left":
|
||||
if inventory_selection_col > 0:
|
||||
@@ -598,7 +735,7 @@ func _navigate_inventory(direction: String):
|
||||
inventory_selection_col = row.get_child_count() - 1
|
||||
else:
|
||||
# Move to equipment slots (only if there are filled slots)
|
||||
var next_equip_index = _find_next_filled_equipment_slot(-1, 1) # Start from end, go forward
|
||||
var next_equip_index = _find_next_filled_equipment_slot(-1, 1) # Start from end, go forward
|
||||
if next_equip_index >= 0:
|
||||
selected_type = "equipment"
|
||||
equipment_selection_index = next_equip_index
|
||||
@@ -625,7 +762,6 @@ func _navigate_equipment(direction: String):
|
||||
# Equipment layout: 3 columns, 2 rows
|
||||
# Row 1: mainhand(0), offhand(1), headgear(2)
|
||||
# Row 2: armour(3), boots(4), accessory(5)
|
||||
|
||||
match direction:
|
||||
"left":
|
||||
var next_index = _find_next_filled_equipment_slot(equipment_selection_index, -1)
|
||||
@@ -637,7 +773,7 @@ func _navigate_equipment(direction: String):
|
||||
equipment_selection_index = next_index
|
||||
"up":
|
||||
# Find next filled slot in row above (same column)
|
||||
var current_row = int(equipment_selection_index / 3)
|
||||
var current_row: int = floor(equipment_selection_index / 3.0)
|
||||
var current_col = equipment_selection_index % 3
|
||||
if current_row > 0:
|
||||
var target_index = (current_row - 1) * 3 + current_col
|
||||
@@ -647,12 +783,12 @@ func _navigate_equipment(direction: String):
|
||||
else:
|
||||
# Skip to next filled slot in that row
|
||||
var next_index = _find_next_filled_equipment_slot(target_index - 1, 1)
|
||||
if next_index >= 0 and next_index < 3: # Make sure it's in row 0
|
||||
if next_index >= 0 and next_index < 3: # Make sure it's in row 0
|
||||
equipment_selection_index = next_index
|
||||
# Can't go up from equipment (already at top)
|
||||
"down":
|
||||
# Find next filled slot in row below (same column), or move to inventory
|
||||
var current_row = int(equipment_selection_index / 3)
|
||||
var current_row: int = floor(equipment_selection_index / 3.0)
|
||||
var current_col = equipment_selection_index % 3
|
||||
if current_row < 1:
|
||||
var target_index = (current_row + 1) * 3 + current_col
|
||||
@@ -660,37 +796,35 @@ func _navigate_equipment(direction: String):
|
||||
if _has_equipment_in_slot(target_slot):
|
||||
equipment_selection_index = target_index
|
||||
else:
|
||||
# No filled slot below, move to inventory
|
||||
# No filled slot below, move to inventory (only if inventory has items)
|
||||
if inventory_rows_list.size() > 0 and inventory_items_list.size() > 0:
|
||||
selected_type = "item"
|
||||
inventory_selection_row = 0
|
||||
inventory_selection_col = current_col
|
||||
# Clamp to valid range
|
||||
var inv_row = inventory_rows_list[0]
|
||||
if inventory_selection_col >= inv_row.get_child_count():
|
||||
inventory_selection_col = inv_row.get_child_count() - 1
|
||||
_update_selection_from_navigation()
|
||||
_update_selection_rectangle()
|
||||
_update_info_panel()
|
||||
return
|
||||
# No inventory items, stay on equipment
|
||||
else:
|
||||
# Already at bottom row, move to inventory (only if inventory has items)
|
||||
if inventory_rows_list.size() > 0 and inventory_items_list.size() > 0:
|
||||
selected_type = "item"
|
||||
inventory_selection_row = 0
|
||||
inventory_selection_col = current_col
|
||||
# Clamp to valid range
|
||||
if inventory_rows_list.size() > 0:
|
||||
var inv_row = inventory_rows_list[0]
|
||||
if inventory_selection_col >= inv_row.get_child_count():
|
||||
inventory_selection_col = inv_row.get_child_count() - 1
|
||||
else:
|
||||
inventory_selection_col = 0
|
||||
var inv_row = inventory_rows_list[0]
|
||||
if inventory_selection_col >= inv_row.get_child_count():
|
||||
inventory_selection_col = inv_row.get_child_count() - 1
|
||||
_update_selection_from_navigation()
|
||||
_update_selection_rectangle()
|
||||
_update_info_panel()
|
||||
return
|
||||
else:
|
||||
# Already at bottom row, move to inventory
|
||||
selected_type = "item"
|
||||
inventory_selection_row = 0
|
||||
inventory_selection_col = current_col
|
||||
# Clamp to valid range
|
||||
if inventory_rows_list.size() > 0:
|
||||
var inv_row = inventory_rows_list[0]
|
||||
if inventory_selection_col >= inv_row.get_child_count():
|
||||
inventory_selection_col = inv_row.get_child_count() - 1
|
||||
else:
|
||||
inventory_selection_col = 0
|
||||
_update_selection_from_navigation()
|
||||
_update_selection_rectangle()
|
||||
_update_info_panel()
|
||||
return
|
||||
# No inventory items, stay on equipment
|
||||
|
||||
_update_selection_from_navigation()
|
||||
_update_selection_rectangle()
|
||||
@@ -700,6 +834,10 @@ func _on_inventory_item_pressed(item: Item):
|
||||
if not local_player or not local_player.character_stats:
|
||||
return
|
||||
|
||||
# Prevent updates during UI refresh (prevents infinite loops from focus_entered)
|
||||
if is_updating_ui:
|
||||
return
|
||||
|
||||
selected_item = item
|
||||
selected_slot = ""
|
||||
selected_type = "item"
|
||||
@@ -707,16 +845,25 @@ func _on_inventory_item_pressed(item: Item):
|
||||
# Update navigation position
|
||||
var item_index = inventory_items_list.find(item)
|
||||
if item_index >= 0:
|
||||
var items_per_row = 10
|
||||
inventory_selection_row = int(item_index / items_per_row)
|
||||
var items_per_row: int = 8
|
||||
inventory_selection_row = floor(item_index / float(items_per_row))
|
||||
inventory_selection_col = item_index % items_per_row
|
||||
|
||||
_update_selection_highlight()
|
||||
_update_selection_rectangle()
|
||||
|
||||
func _on_character_changed(_char: CharacterStats):
|
||||
_update_ui()
|
||||
# Always update stats when character changes (even if inventory is closed)
|
||||
# Equipment changes affect max HP/MP which should be reflected everywhere
|
||||
_update_stats()
|
||||
|
||||
# Only update UI if inventory is open (prevents unnecessary updates)
|
||||
if not is_open:
|
||||
return
|
||||
# Prevent recursive updates
|
||||
if is_updating_ui:
|
||||
return
|
||||
_update_ui()
|
||||
|
||||
func _input(event):
|
||||
# Toggle with Tab key
|
||||
@@ -773,6 +920,9 @@ func _handle_f_key():
|
||||
var equipped_item = char_stats.equipment[selected_slot]
|
||||
if equipped_item:
|
||||
char_stats.unequip_item(equipped_item)
|
||||
# Play armour sound when unequipping
|
||||
if sfx_armour:
|
||||
sfx_armour.play()
|
||||
# After unequipping, if all equipment is empty, go to inventory
|
||||
var has_any_equipment = false
|
||||
for slot in equipment_slots_list:
|
||||
@@ -832,6 +982,10 @@ func _handle_f_key():
|
||||
|
||||
char_stats.equip_item(selected_item)
|
||||
|
||||
# Play armour sound when equipping
|
||||
if sfx_armour:
|
||||
sfx_armour.play()
|
||||
|
||||
# If this was the last item, set selection state BEFORE _update_ui()
|
||||
# so that _update_selection_from_navigation() works correctly
|
||||
if was_last_item and target_slot_name != "":
|
||||
@@ -856,6 +1010,18 @@ func _use_consumable_item(item: Item):
|
||||
|
||||
var char_stats = local_player.character_stats
|
||||
|
||||
# Determine if it's a potion or food based on item name
|
||||
var is_potion = "potion" in item.item_name.to_lower()
|
||||
|
||||
# Play appropriate sound
|
||||
if is_potion:
|
||||
if sfx_potion:
|
||||
sfx_potion.play()
|
||||
else:
|
||||
# Food item
|
||||
if sfx_food:
|
||||
sfx_food.play()
|
||||
|
||||
if item.modifiers.has("hp"):
|
||||
var hp_heal = item.modifiers["hp"]
|
||||
if local_player.has_method("heal"):
|
||||
@@ -880,6 +1046,11 @@ func _handle_e_key():
|
||||
|
||||
var char_stats = local_player.character_stats
|
||||
|
||||
# Play armour sound when dropping equipment
|
||||
if selected_item.item_type == Item.ItemType.Equippable:
|
||||
if sfx_armour:
|
||||
sfx_armour.play()
|
||||
|
||||
if not selected_item in char_stats.inventory:
|
||||
return
|
||||
|
||||
@@ -893,10 +1064,24 @@ func _handle_e_key():
|
||||
if game_world:
|
||||
entities_node = game_world.get_node_or_null("Entities")
|
||||
|
||||
if entities_node:
|
||||
var loot = ItemLootHelper.spawn_item_loot(selected_item, drop_position, entities_node, game_world)
|
||||
if loot:
|
||||
if local_player.has_method("get_multiplayer_authority"):
|
||||
# In multiplayer, clients need to request server to spawn loot
|
||||
if multiplayer.has_multiplayer_peer() and not multiplayer.is_server():
|
||||
# Client: send drop request to server
|
||||
if game_world and game_world.has_method("_request_item_drop"):
|
||||
game_world._request_item_drop.rpc_id(1, selected_item.save(), drop_position, local_player.get_multiplayer_authority())
|
||||
else:
|
||||
# Fallback: try to spawn locally (won't sync)
|
||||
if entities_node:
|
||||
var loot = ItemLootHelper.spawn_item_loot(selected_item, drop_position, entities_node, game_world)
|
||||
if loot and local_player.has_method("get_multiplayer_authority"):
|
||||
var player_peer_id = local_player.get_multiplayer_authority()
|
||||
loot.set_meta("dropped_by_peer_id", player_peer_id)
|
||||
loot.set_meta("drop_time", Time.get_ticks_msec())
|
||||
else:
|
||||
# Server or single-player: spawn directly
|
||||
if entities_node:
|
||||
var loot = ItemLootHelper.spawn_item_loot(selected_item, drop_position, entities_node, game_world)
|
||||
if loot and local_player.has_method("get_multiplayer_authority"):
|
||||
var player_peer_id = local_player.get_multiplayer_authority()
|
||||
loot.set_meta("dropped_by_peer_id", player_peer_id)
|
||||
loot.set_meta("drop_time", Time.get_ticks_msec())
|
||||
@@ -913,38 +1098,34 @@ func _open_inventory():
|
||||
if is_open:
|
||||
return
|
||||
|
||||
# Workaround: On first open, immediately close and reopen to ensure proper initialization
|
||||
if is_first_open:
|
||||
is_first_open = false
|
||||
is_open = true
|
||||
if container:
|
||||
container.visible = true
|
||||
_lock_player_controls(true)
|
||||
_update_ui()
|
||||
# Wait a frame
|
||||
await get_tree().process_frame
|
||||
# Close immediately
|
||||
_close_inventory()
|
||||
# Wait a frame
|
||||
await get_tree().process_frame
|
||||
# Now reopen properly (will continue with normal flow below)
|
||||
|
||||
is_open = true
|
||||
if container:
|
||||
container.visible = true
|
||||
|
||||
_lock_player_controls(true)
|
||||
_update_ui()
|
||||
|
||||
# Initialize selection - prefer inventory, but if empty, check equipment
|
||||
if inventory_rows_list.size() > 0:
|
||||
selected_type = "item"
|
||||
inventory_selection_row = 0
|
||||
inventory_selection_col = 0
|
||||
_update_selection_from_navigation()
|
||||
_update_selection_rectangle()
|
||||
_update_info_panel()
|
||||
else:
|
||||
# No inventory items, try equipment
|
||||
var first_filled_slot = _find_next_filled_equipment_slot(-1, 1)
|
||||
if first_filled_slot >= 0:
|
||||
selected_type = "equipment"
|
||||
equipment_selection_index = first_filled_slot
|
||||
selected_slot = equipment_slots_list[first_filled_slot]
|
||||
_update_selection_from_navigation()
|
||||
_update_selection_rectangle()
|
||||
_update_info_panel()
|
||||
else:
|
||||
# Nothing to select
|
||||
selected_type = ""
|
||||
if selection_rectangle:
|
||||
selection_rectangle.visible = false
|
||||
if info_label:
|
||||
info_label.text = ""
|
||||
# Reset selection state BEFORE updating UI (so _update_ui doesn't try to update selection)
|
||||
selected_type = ""
|
||||
selected_item = null
|
||||
selected_slot = ""
|
||||
|
||||
_update_ui()
|
||||
|
||||
if not local_player:
|
||||
_find_local_player()
|
||||
|
||||
Reference in New Issue
Block a user