Files
dauphincraft/scripts/inventory/InventoryUI.gd
2026-04-19 17:16:13 +02:00

280 lines
8.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends CanvasLayer
const SLOT_SIZE: int = 48
const SLOT_MARGIN: int = 4
var inventory: Inventory = null
var _hotbar_slots: Array = []
var _inv_slots: Array = []
var _inv_window: Control = null
var _recipe_list: VBoxContainer = null
var _is_open: bool = false
func _ready() -> void:
_build_hotbar()
_build_inventory_window()
func setup(inv: Inventory) -> void:
inventory = inv
inventory.inventory_changed.connect(_refresh)
_refresh()
func _build_hotbar() -> void:
var hotbar_root := HBoxContainer.new()
hotbar_root.name = "HotbarRoot"
hotbar_root.add_theme_constant_override("separation", SLOT_MARGIN)
var total_width: int = SLOT_SIZE * 9 + SLOT_MARGIN * 8
var anchor_node := Control.new()
anchor_node.name = "HotbarAnchor"
anchor_node.set_anchors_preset(Control.PRESET_BOTTOM_WIDE)
anchor_node.custom_minimum_size = Vector2(total_width, SLOT_SIZE + 8)
anchor_node.set_offset(SIDE_BOTTOM, -8)
anchor_node.set_offset(SIDE_TOP, -(SLOT_SIZE + 16))
add_child(anchor_node)
hotbar_root.set_anchors_preset(Control.PRESET_CENTER)
hotbar_root.position = Vector2(-total_width / 2.0, 0)
anchor_node.add_child(hotbar_root)
for i: int in range(9):
var slot := _make_slot_panel(i)
hotbar_root.add_child(slot)
_hotbar_slots.append(slot)
func _make_slot_panel(index: int) -> PanelContainer:
var panel := PanelContainer.new()
panel.custom_minimum_size = Vector2(SLOT_SIZE, SLOT_SIZE)
panel.set_meta("slot_index", index)
var style_normal := StyleBoxFlat.new()
style_normal.bg_color = Color(0.05, 0.1, 0.2, 0.85)
style_normal.border_color = Color(0.0, 0.8, 0.8)
style_normal.set_border_width_all(2)
style_normal.set_corner_radius_all(3)
panel.add_theme_stylebox_override("panel", style_normal)
panel.set_meta("style_normal", style_normal)
var style_selected := StyleBoxFlat.new()
style_selected.bg_color = Color(0.05, 0.1, 0.2, 0.85)
style_selected.border_color = Color(1.0, 0.9, 0.1)
style_selected.set_border_width_all(3)
style_selected.set_corner_radius_all(3)
panel.set_meta("style_selected", style_selected)
var vbox := VBoxContainer.new()
vbox.set_anchors_preset(Control.PRESET_FULL_RECT)
panel.add_child(vbox)
var color_rect := ColorRect.new()
color_rect.name = "ColorRect"
color_rect.custom_minimum_size = Vector2(SLOT_SIZE - 8, SLOT_SIZE - 18)
color_rect.color = Color(0, 0, 0, 0)
vbox.add_child(color_rect)
var count_label := Label.new()
count_label.name = "CountLabel"
count_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
count_label.add_theme_font_size_override("font_size", 10)
count_label.text = ""
vbox.add_child(count_label)
return panel
func _build_inventory_window() -> void:
_inv_window = Control.new()
_inv_window.name = "InventoryWindow"
_inv_window.set_anchors_preset(Control.PRESET_FULL_RECT)
_inv_window.visible = false
add_child(_inv_window)
# Dim background
var bg := ColorRect.new()
bg.set_anchors_preset(Control.PRESET_FULL_RECT)
bg.color = Color(0, 0, 0, 0.55)
_inv_window.add_child(bg)
# Main HBox: left = slots, right = craft panel
var hbox := HBoxContainer.new()
hbox.set_anchors_preset(Control.PRESET_CENTER)
hbox.add_theme_constant_override("separation", 16)
_inv_window.add_child(hbox)
# Center it
hbox.set_offset(SIDE_LEFT, -360)
hbox.set_offset(SIDE_RIGHT, 360)
hbox.set_offset(SIDE_TOP, -240)
hbox.set_offset(SIDE_BOTTOM, 240)
# Left panel: inventory grid + hotbar row
var left_vbox := VBoxContainer.new()
left_vbox.add_theme_constant_override("separation", 8)
hbox.add_child(left_vbox)
var inv_label := Label.new()
inv_label.text = "Inventaire"
inv_label.add_theme_font_size_override("font_size", 14)
left_vbox.add_child(inv_label)
# 3 rows × 9 cols = 27 slots (indices 9..35)
var inv_grid := GridContainer.new()
inv_grid.columns = 9
inv_grid.add_theme_constant_override("h_separation", SLOT_MARGIN)
inv_grid.add_theme_constant_override("v_separation", SLOT_MARGIN)
left_vbox.add_child(inv_grid)
for i: int in range(9, 36):
var slot := _make_slot_panel(i)
inv_grid.add_child(slot)
_inv_slots.append(slot)
# Separator
var sep := HSeparator.new()
left_vbox.add_child(sep)
var hbar_label := Label.new()
hbar_label.text = "Hotbar"
hbar_label.add_theme_font_size_override("font_size", 12)
left_vbox.add_child(hbar_label)
# Hotbar row inside inventory (mirror of bottom hotbar)
var hotbar_grid := HBoxContainer.new()
hotbar_grid.add_theme_constant_override("separation", SLOT_MARGIN)
left_vbox.add_child(hotbar_grid)
for i: int in range(9):
var slot := _make_slot_panel(i)
hotbar_grid.add_child(slot)
_inv_slots.append(slot) # also tracked here for refresh
# Right panel: craft
var right_vbox := VBoxContainer.new()
right_vbox.custom_minimum_size = Vector2(200, 0)
right_vbox.add_theme_constant_override("separation", 6)
hbox.add_child(right_vbox)
var craft_label := Label.new()
craft_label.text = "Craft"
craft_label.add_theme_font_size_override("font_size", 14)
right_vbox.add_child(craft_label)
var scroll := ScrollContainer.new()
scroll.custom_minimum_size = Vector2(200, 380)
right_vbox.add_child(scroll)
_recipe_list = VBoxContainer.new()
_recipe_list.add_theme_constant_override("separation", 6)
scroll.add_child(_recipe_list)
func _refresh() -> void:
if inventory == null:
return
_refresh_hotbar_slots()
if _is_open:
_refresh_inv_slots()
_refresh_recipes()
func _refresh_hotbar_slots() -> void:
for i: int in range(_hotbar_slots.size()):
_update_slot_visual(_hotbar_slots[i], i)
func _refresh_inv_slots() -> void:
# _inv_slots contains: 27 inv slots (9..35) + 9 hotbar mirror (0..8)
for i: int in range(27):
_update_slot_visual(_inv_slots[i], i + 9)
for i: int in range(9):
_update_slot_visual(_inv_slots[27 + i], i)
func _update_slot_visual(panel: PanelContainer, slot_index: int) -> void:
var is_selected: bool = (slot_index == inventory.selected_hotbar and slot_index < 9)
if is_selected:
panel.add_theme_stylebox_override("panel", panel.get_meta("style_selected"))
panel.scale = Vector2(1.1, 1.1)
else:
panel.add_theme_stylebox_override("panel", panel.get_meta("style_normal"))
panel.scale = Vector2(1.0, 1.0)
var slot_data: Variant = inventory.slots[slot_index]
var color_rect: ColorRect = panel.get_node("VBoxContainer/ColorRect")
var count_label: Label = panel.get_node("VBoxContainer/CountLabel")
if slot_data == null:
color_rect.color = Color(0, 0, 0, 0)
count_label.text = ""
else:
color_rect.color = ItemDatabase.get_item_color(slot_data["item_id"])
if slot_data["count"] > 1:
count_label.text = str(slot_data["count"])
else:
count_label.text = ""
func _refresh_recipes() -> void:
for child in _recipe_list.get_children():
child.queue_free()
for i: int in range(CraftingRecipes.RECIPES.size()):
var recipe: Dictionary = CraftingRecipes.RECIPES[i]
var can_craft: bool = inventory.has_items(recipe["inputs"])
var recipe_panel := VBoxContainer.new()
recipe_panel.add_theme_constant_override("separation", 2)
_recipe_list.add_child(recipe_panel)
var name_label := Label.new()
name_label.text = recipe["name"]
name_label.add_theme_font_size_override("font_size", 11)
recipe_panel.add_child(name_label)
# Inputs summary
var inputs_text: String = ""
for inp: Dictionary in recipe["inputs"]:
inputs_text += "%s x%d " % [ItemDatabase.get_item_name(inp["item_id"]), inp["count"]]
var inp_label := Label.new()
inp_label.text = inputs_text.strip_edges()
inp_label.add_theme_font_size_override("font_size", 9)
inp_label.modulate = Color(0.7, 0.7, 0.7)
recipe_panel.add_child(inp_label)
var craft_btn := Button.new()
craft_btn.text = "Creer"
craft_btn.disabled = not can_craft
var idx: int = i
craft_btn.pressed.connect(func() -> void: _on_craft_pressed(idx))
recipe_panel.add_child(craft_btn)
var sep := HSeparator.new()
_recipe_list.add_child(sep)
func _on_craft_pressed(recipe_index: int) -> void:
CraftingRecipes.craft(inventory, recipe_index)
func _input(event: InputEvent) -> void:
if event.is_action_pressed("toggle_inventory"):
_toggle_inventory()
get_viewport().set_input_as_handled()
func _toggle_inventory() -> void:
_is_open = not _is_open
_inv_window.visible = _is_open
if _is_open:
get_tree().paused = true
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
_refresh_inv_slots()
_refresh_recipes()
else:
get_tree().paused = false
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED