forked from woofmeow/straywild
159 lines
4.6 KiB
GDScript
159 lines
4.6 KiB
GDScript
class_name GeneralInventoryGrid
|
|
extends Control
|
|
|
|
signal entry_selected(kind: int, identity: StringName)
|
|
signal slot_activated(slot: GeneralInventorySlot)
|
|
signal context_requested(slot: GeneralInventorySlot)
|
|
signal context_changed(slot: GeneralInventorySlot, text: String, active: bool)
|
|
|
|
const DEFAULT_SLOT_SIZE := Vector2(52.0, 52.0)
|
|
const DEFAULT_SLOT_SEPARATION: int = 5
|
|
const COLUMNS: int = PlayerInventoryLayout.INVENTORY_COLUMNS
|
|
|
|
var _layout: PlayerInventoryLayout
|
|
var _bag: PlayerBag
|
|
var _fish_inventory: FishInventory
|
|
var _hotbar: PlayerHotbar
|
|
var _item_catalog: ItemCatalog
|
|
var _container: int = PlayerInventoryLayout.InventoryContainer.INVENTORY
|
|
var _grid: GridContainer
|
|
var _slots: Array[GeneralInventorySlot] = []
|
|
var _slot_size: Vector2 = DEFAULT_SLOT_SIZE
|
|
var _slot_separation: int = DEFAULT_SLOT_SEPARATION
|
|
|
|
|
|
func _ready() -> void:
|
|
_grid = GridContainer.new()
|
|
_grid.columns = COLUMNS
|
|
_apply_grid_separation()
|
|
add_child(_grid)
|
|
|
|
|
|
func set_slot_presentation(slot_size: Vector2, separation: int) -> void:
|
|
_slot_size = Vector2(maxf(1.0, slot_size.x), maxf(1.0, slot_size.y))
|
|
_slot_separation = maxi(0, separation)
|
|
if _grid != null:
|
|
_apply_grid_separation()
|
|
if is_node_ready() and _layout != null:
|
|
var active_capacity := (
|
|
_layout.get_inventory_capacity()
|
|
if _container == PlayerInventoryLayout.InventoryContainer.INVENTORY
|
|
else _layout.get_storage_capacity()
|
|
)
|
|
_rebuild(
|
|
PlayerInventoryLayout.MAX_INVENTORY_SLOT_COUNT
|
|
if _container == PlayerInventoryLayout.InventoryContainer.INVENTORY
|
|
else PlayerInventoryLayout.MAX_STORAGE_SLOT_COUNT,
|
|
active_capacity,
|
|
)
|
|
|
|
|
|
func setup(
|
|
layout: PlayerInventoryLayout,
|
|
bag: PlayerBag,
|
|
fish_inventory: FishInventory,
|
|
hotbar: PlayerHotbar,
|
|
item_catalog: ItemCatalog,
|
|
container: int,
|
|
) -> void:
|
|
_layout = layout
|
|
_bag = bag
|
|
_fish_inventory = fish_inventory
|
|
_hotbar = hotbar
|
|
_item_catalog = item_catalog
|
|
_container = container
|
|
if _layout != null and not _layout.layout_changed.is_connected(refresh):
|
|
_layout.layout_changed.connect(refresh)
|
|
refresh()
|
|
|
|
|
|
func refresh() -> void:
|
|
if not is_node_ready() or _layout == null:
|
|
return
|
|
var active_capacity := (
|
|
_layout.get_inventory_capacity()
|
|
if _container == PlayerInventoryLayout.InventoryContainer.INVENTORY
|
|
else _layout.get_storage_capacity()
|
|
)
|
|
var visible_capacity := (
|
|
PlayerInventoryLayout.MAX_INVENTORY_SLOT_COUNT
|
|
if _container == PlayerInventoryLayout.InventoryContainer.INVENTORY
|
|
else PlayerInventoryLayout.MAX_STORAGE_SLOT_COUNT
|
|
)
|
|
if _slots.size() != visible_capacity:
|
|
_rebuild(visible_capacity, active_capacity)
|
|
else:
|
|
for index: int in _slots.size():
|
|
_slots[index].set_locked(index >= active_capacity)
|
|
for slot: GeneralInventorySlot in _slots:
|
|
slot.refresh()
|
|
|
|
|
|
func get_slots() -> Array[GeneralInventorySlot]:
|
|
var active: Array[GeneralInventorySlot] = []
|
|
for slot: GeneralInventorySlot in _slots:
|
|
if not slot.disabled:
|
|
active.append(slot)
|
|
return active
|
|
|
|
|
|
func get_first_occupied_slot() -> GeneralInventorySlot:
|
|
for slot: GeneralInventorySlot in _slots:
|
|
if not slot.entry_identity.is_empty():
|
|
return slot
|
|
return _slots.front() if not _slots.is_empty() else null
|
|
|
|
|
|
func _rebuild(visible_capacity: int, active_capacity: int) -> void:
|
|
for child: Node in _grid.get_children():
|
|
child.queue_free()
|
|
_slots.clear()
|
|
for slot_index: int in visible_capacity:
|
|
var slot := GeneralInventorySlot.new()
|
|
slot.custom_minimum_size = _slot_size
|
|
slot.entry_selected.connect(
|
|
func(kind: int, identity: StringName) -> void:
|
|
entry_selected.emit(kind, identity)
|
|
)
|
|
slot.pressed.connect(func() -> void: slot_activated.emit(slot))
|
|
slot.context_requested.connect(
|
|
func(source: GeneralInventorySlot) -> void:
|
|
context_requested.emit(source)
|
|
)
|
|
slot.context_changed.connect(
|
|
func(
|
|
source: GeneralInventorySlot,
|
|
text: String,
|
|
active: bool,
|
|
) -> void:
|
|
context_changed.emit(source, text, active)
|
|
)
|
|
_grid.add_child(slot)
|
|
slot.set_presentation_size(_slot_size)
|
|
slot.configure(
|
|
slot_index,
|
|
_container,
|
|
slot_index >= active_capacity,
|
|
_layout,
|
|
_bag,
|
|
_fish_inventory,
|
|
_hotbar,
|
|
_item_catalog,
|
|
)
|
|
_slots.append(slot)
|
|
custom_minimum_size = Vector2(
|
|
float(COLUMNS) * _slot_size.x
|
|
+ float(COLUMNS - 1) * _slot_separation,
|
|
ceilf(float(visible_capacity) / float(COLUMNS)) * _slot_size.y
|
|
+ maxf(
|
|
0.0,
|
|
ceilf(float(visible_capacity) / float(COLUMNS)) - 1.0,
|
|
) * _slot_separation,
|
|
)
|
|
size = custom_minimum_size
|
|
ControllerFocusNavigation.configure_spatial_neighbors(_slots)
|
|
|
|
|
|
func _apply_grid_separation() -> void:
|
|
_grid.add_theme_constant_override("h_separation", _slot_separation)
|
|
_grid.add_theme_constant_override("v_separation", _slot_separation)
|