@tool extends PanelContainer # Displays all weapons from the ItemsDatabase in a grid format # Shows sprite and name, with tooltip showing resource path # Clicking opens the weapon resource in the inspector signal weapon_selected(weapon_resource_path: String) var _editor_interface: EditorInterface var _grid_container: HFlowContainer var _items_database_path := "res://Resources/ItemsDatabase.tres" func setup(editor_interface: EditorInterface) -> void: _editor_interface = editor_interface func _ready() -> void: _build_ui() refresh_weapons() func _build_ui() -> void: # Main margin container var margin = MarginContainer.new() margin.add_theme_constant_override("margin_left", 8) margin.add_theme_constant_override("margin_top", 8) margin.add_theme_constant_override("margin_right", 8) margin.add_theme_constant_override("margin_bottom", 8) add_child(margin) # Main vbox var vbox = VBoxContainer.new() vbox.add_theme_constant_override("separation", 8) margin.add_child(vbox) # Header with title and refresh button var header_hbox = HBoxContainer.new() vbox.add_child(header_hbox) var title = Label.new() title.text = "Weapons" title.size_flags_horizontal = Control.SIZE_EXPAND_FILL header_hbox.add_child(title) var refresh_button = Button.new() refresh_button.text = "Refresh" refresh_button.pressed.connect(refresh_weapons) header_hbox.add_child(refresh_button) vbox.add_child(HSeparator.new()) # Scroll container for grid var scroll = ScrollContainer.new() scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED vbox.add_child(scroll) # Flow container for responsive wrapping _grid_container = HFlowContainer.new() _grid_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL _grid_container.add_theme_constant_override("h_separation", 8) _grid_container.add_theme_constant_override("v_separation", 8) scroll.add_child(_grid_container) func refresh_weapons() -> void: if not _grid_container: return # Clear existing items for child in _grid_container.get_children(): child.queue_free() # Load ItemsDatabase if not ResourceLoader.exists(_items_database_path): _add_error_label("ItemsDatabase not found at: " + _items_database_path) return var items_database = load(_items_database_path) if items_database == null: _add_error_label("Failed to load ItemsDatabase") return var loot_items = items_database.get("LootItems") if loot_items == null: _add_error_label("No LootItems found in database") return # Filter for weapons only (items with WeaponData3D) var weapon_count = 0 for loot_item in loot_items: var weapon_data = loot_item.get("WeaponData3D") if weapon_data != null: _create_weapon_tile(loot_item, weapon_data) weapon_count += 1 if weapon_count == 0: _add_error_label("No weapons found in database") func _create_weapon_tile(loot_item: Resource, weapon_data: Resource) -> void: var button = Button.new() button.custom_minimum_size = Vector2(100, 110) button.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN button.size_flags_vertical = Control.SIZE_SHRINK_BEGIN var vbox = VBoxContainer.new() vbox.add_theme_constant_override("separation", 2) vbox.mouse_filter = Control.MOUSE_FILTER_IGNORE var sprite: Texture2D = loot_item.get("InventorySprite") var texture_rect = TextureRect.new() texture_rect.custom_minimum_size = Vector2(64, 64) texture_rect.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED texture_rect.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST texture_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE if sprite: texture_rect.texture = sprite vbox.add_child(texture_rect) else: var placeholder_label = Label.new() placeholder_label.text = "No Icon" placeholder_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER placeholder_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER placeholder_label.custom_minimum_size = Vector2(64, 64) placeholder_label.mouse_filter = Control.MOUSE_FILTER_IGNORE placeholder_label.add_theme_font_size_override("font_size", 10) vbox.add_child(placeholder_label) var name_label = Label.new() var item_name: String = loot_item.get("ItemName") name_label.text = item_name if item_name else "Unknown" name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER name_label.vertical_alignment = VERTICAL_ALIGNMENT_TOP name_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART name_label.custom_minimum_size = Vector2(90, 0) name_label.size_flags_vertical = Control.SIZE_EXPAND_FILL name_label.clip_text = true name_label.max_lines_visible = 2 name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE name_label.add_theme_font_size_override("font_size", 11) name_label.add_theme_constant_override("line_spacing", -2) vbox.add_child(name_label) button.add_child(vbox) vbox.set_anchors_preset(Control.PRESET_FULL_RECT) vbox.add_theme_constant_override("margin_left", 4) vbox.add_theme_constant_override("margin_top", 4) vbox.add_theme_constant_override("margin_right", 4) vbox.add_theme_constant_override("margin_bottom", 4) var weapon_path = weapon_data.resource_path if weapon_path: button.tooltip_text = weapon_path else: button.tooltip_text = "Built-in resource (no file path)" button.pressed.connect(_on_weapon_clicked.bind(weapon_data, weapon_path)) _grid_container.add_child(button) func _on_weapon_clicked(weapon_data: Resource, weapon_path: String) -> void: if not _editor_interface: push_error("Editor interface not available") return # Select the weapon resource in the inspector if weapon_data: _editor_interface.edit_resource(weapon_data) _editor_interface.get_inspector().set_current_tab(0) weapon_selected.emit(weapon_path) func _add_error_label(error_message: String) -> void: var label = Label.new() label.text = error_message label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER label.modulate = Color.ORANGE_RED _grid_container.add_child(label)