Files
settled-reach/client/ui/inventory_grid.gd
T
jpmschweitzerandClaude Opus 4.6 4eb54a6f7a fix(client): resolve all gdlint warnings — zero warnings policy
Fix 354 gdlint warnings across 65 files: 194 class-definitions-order
(reorder declarations), 138 max-line-length (split long lines),
22 code issues (unused args, no-else-return, naming). Update .gdlintrc
to exclude addons/ and raise max-public-methods for test files.
No logic changes — declaration order, whitespace, and naming only.

Ticket: #783

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 09:59:56 +02:00

141 lines
3.7 KiB
GDScript

extends Control
## D-065: Inventory grid — 3x3 slots, bottom-right, 40x40px icons.
## No empty slots displayed — icons appear only when items are carried.
## 1-9 hotkeys for direct slot access. Reads from GameState.player_inventory.
## Lives on UILayer (z-layer 7).
signal item_selected(slot: int, item_id: int)
const SLOT_SIZE := 40
const SLOT_GAP := 4
const GRID_COLS := 3
const GRID_ROWS := 3
const MAX_SLOTS := 9
const SLOT_BG := Color(0.1, 0.1, 0.14, 0.6)
const SLOT_BORDER := Color(0.3, 0.3, 0.38, 0.8)
const SLOT_ACTIVE := Color("#c8d0e0")
const SLOT_TEXT := Color("#c8d0e0")
const SLOT_TEXT_DIM := Color("#8b8ba0")
const HOTKEY_SIZE := 10
var _slots: Array = [] # [{item_id, name, slot}] from GameState
var _slot_nodes: Array[Control] = []
var _selected_slot: int = -1
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
_build_grid()
visible = false
func _build_grid() -> void:
for node in _slot_nodes:
if is_instance_valid(node):
node.queue_free()
_slot_nodes.clear()
var grid_w: float = GRID_COLS * SLOT_SIZE + (GRID_COLS - 1) * SLOT_GAP
var grid_h: float = GRID_ROWS * SLOT_SIZE + (GRID_ROWS - 1) * SLOT_GAP
# Position grid at bottom-right with margin
custom_minimum_size = Vector2(grid_w, grid_h)
size = Vector2(grid_w, grid_h)
func update_from_state() -> void:
_slots = GameState.player_inventory.duplicate()
if _slots.is_empty():
visible = false
return
visible = true
queue_redraw()
func _draw() -> void:
if _slots.is_empty():
return
for item in _slots:
var slot_idx: int = item.get("slot", 0)
if slot_idx < 0 or slot_idx >= MAX_SLOTS:
continue
var col: int = slot_idx % GRID_COLS
var row: int = slot_idx / GRID_COLS
var pos := Vector2(
col * (SLOT_SIZE + SLOT_GAP),
row * (SLOT_SIZE + SLOT_GAP)
)
var rect := Rect2(pos, Vector2(SLOT_SIZE, SLOT_SIZE))
# Slot background
draw_rect(rect, SLOT_BG)
# Border
draw_rect(rect, SLOT_BORDER, false, 1.0)
# Selected highlight
if slot_idx == _selected_slot:
draw_rect(rect, SLOT_ACTIVE, false, 2.0)
# Item name (truncated, centered)
var item_name: String = item.get("name", "?")
if item_name.length() > 5:
item_name = item_name.substr(0, 4) + "."
var font := ThemeDB.fallback_font
var font_size := 11
var text_size := font.get_string_size(item_name, HORIZONTAL_ALIGNMENT_CENTER, -1, font_size)
var text_pos := pos + Vector2((SLOT_SIZE - text_size.x) / 2.0, SLOT_SIZE / 2.0 + text_size.y / 4.0)
draw_string(font, text_pos, item_name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, SLOT_TEXT)
# Hotkey number (top-left corner)
var hotkey := str(slot_idx + 1)
draw_string(font, pos + Vector2(3, HOTKEY_SIZE + 2), hotkey,
HORIZONTAL_ALIGNMENT_LEFT, -1, HOTKEY_SIZE, SLOT_TEXT_DIM)
func _unhandled_input(event: InputEvent) -> void:
if not visible:
return
if event is InputEventKey and event.pressed and not event.echo:
var key: int = event.physical_keycode
# 1-9 hotkeys (Key_1 = 49, Key_9 = 57)
if key >= KEY_1 and key <= KEY_9:
var slot_idx: int = key - KEY_1
_select_slot(slot_idx)
get_viewport().set_input_as_handled()
func _select_slot(slot_idx: int) -> void:
# Find item in this slot
for item in _slots:
if item.get("slot", -1) == slot_idx:
_selected_slot = slot_idx
item_selected.emit(slot_idx, item.get("item_id", -1))
queue_redraw()
return
# No item in slot — deselect
_selected_slot = -1
queue_redraw()
# -- Public API ---------------------------------------------------------------
func get_slot_count() -> int:
return _slots.size()
func get_selected_slot() -> int:
return _selected_slot
func get_item_at_slot(slot_idx: int) -> Dictionary:
for item in _slots:
if item.get("slot", -1) == slot_idx:
return item
return {}