188 lines
5 KiB
GDScript3
188 lines
5 KiB
GDScript3
|
|
class_name HotbarSlot
|
|||
|
|
extends Button
|
|||
|
|
|
|||
|
|
signal item_hovered(slot_index: int, item_id: StringName)
|
|||
|
|
signal item_hover_ended(slot_index: int)
|
|||
|
|
signal item_drag_started
|
|||
|
|
signal item_drag_finished
|
|||
|
|
|
|||
|
|
const ItemCatalogType = preload("res://items/item_catalog.gd")
|
|||
|
|
const ItemDataType = preload("res://items/item_data.gd")
|
|||
|
|
const PlayerBagType = preload("res://inventory/player_bag.gd")
|
|||
|
|
const PlayerHotbarType = preload("res://inventory/player_hotbar.gd")
|
|||
|
|
|
|||
|
|
var slot_index: int = 0
|
|||
|
|
var _hotbar: PlayerHotbarType
|
|||
|
|
var _bag: PlayerBagType
|
|||
|
|
var _catalog: ItemCatalogType
|
|||
|
|
var _drag_enabled: bool = false
|
|||
|
|
var _drag_in_progress: bool = false
|
|||
|
|
var _slot_number_label: Label
|
|||
|
|
var _quantity_label: Label
|
|||
|
|
|
|||
|
|
|
|||
|
|
func setup(
|
|||
|
|
index: int,
|
|||
|
|
hotbar: PlayerHotbarType,
|
|||
|
|
bag: PlayerBagType,
|
|||
|
|
catalog: ItemCatalogType,
|
|||
|
|
) -> void:
|
|||
|
|
slot_index = index
|
|||
|
|
_hotbar = hotbar
|
|||
|
|
_bag = bag
|
|||
|
|
_catalog = catalog
|
|||
|
|
custom_minimum_size = Vector2(50, 50)
|
|||
|
|
expand_icon = true
|
|||
|
|
focus_mode = Control.FOCUS_ALL
|
|||
|
|
_slot_number_label = _create_corner_label(str(slot_index + 1))
|
|||
|
|
_quantity_label = _create_corner_label("", true)
|
|||
|
|
pressed.connect(_select_slot)
|
|||
|
|
mouse_entered.connect(_on_mouse_entered)
|
|||
|
|
mouse_exited.connect(_on_mouse_exited)
|
|||
|
|
refresh()
|
|||
|
|
|
|||
|
|
|
|||
|
|
func set_drag_enabled(enabled: bool) -> void:
|
|||
|
|
_drag_enabled = enabled
|
|||
|
|
mouse_filter = (
|
|||
|
|
Control.MOUSE_FILTER_STOP
|
|||
|
|
if enabled
|
|||
|
|
else Control.MOUSE_FILTER_IGNORE
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
func refresh() -> void:
|
|||
|
|
if _hotbar == null:
|
|||
|
|
return
|
|||
|
|
var item_id: StringName = _hotbar.get_item_id(slot_index)
|
|||
|
|
var item: ItemDataType = (
|
|||
|
|
_catalog.get_item_by_id(item_id)
|
|||
|
|
if _catalog != null and not item_id.is_empty()
|
|||
|
|
else null
|
|||
|
|
)
|
|||
|
|
icon = item.icon if item != null else null
|
|||
|
|
var quantity: int = (
|
|||
|
|
_bag.get_quantity(item_id)
|
|||
|
|
if _bag != null and not item_id.is_empty()
|
|||
|
|
else 0
|
|||
|
|
)
|
|||
|
|
var quantity_text: String = (
|
|||
|
|
"×%d" % quantity
|
|||
|
|
if item != null and item.stackable and quantity > 1
|
|||
|
|
else ""
|
|||
|
|
)
|
|||
|
|
text = ""
|
|||
|
|
_quantity_label.text = quantity_text
|
|||
|
|
_quantity_label.visible = not quantity_text.is_empty()
|
|||
|
|
tooltip_text = (
|
|||
|
|
item.display_name if item != null else "Empty hotbar slot"
|
|||
|
|
)
|
|||
|
|
button_pressed = slot_index == _hotbar.get_selected_slot()
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _create_corner_label(
|
|||
|
|
label_text: String,
|
|||
|
|
bottom_right: bool = false,
|
|||
|
|
) -> Label:
|
|||
|
|
var label := Label.new()
|
|||
|
|
label.text = label_text
|
|||
|
|
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|||
|
|
label.add_theme_font_size_override("font_size", 11)
|
|||
|
|
label.add_theme_color_override("font_color", UIPalette.TEXT)
|
|||
|
|
if bottom_right:
|
|||
|
|
label.set_anchors_preset(Control.PRESET_BOTTOM_RIGHT)
|
|||
|
|
label.position = Vector2(-22.0, -20.0)
|
|||
|
|
else:
|
|||
|
|
label.position = Vector2(5.0, 2.0)
|
|||
|
|
add_child(label)
|
|||
|
|
return label
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _gui_input(event: InputEvent) -> void:
|
|||
|
|
if (
|
|||
|
|
_drag_enabled
|
|||
|
|
and event is InputEventMouseButton
|
|||
|
|
and event.button_index == MOUSE_BUTTON_RIGHT
|
|||
|
|
and event.pressed
|
|||
|
|
and _hotbar != null
|
|||
|
|
):
|
|||
|
|
_hotbar.clear_slot(slot_index)
|
|||
|
|
accept_event()
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _get_drag_data(_at_position: Vector2) -> Variant:
|
|||
|
|
if not _drag_enabled or _hotbar == null:
|
|||
|
|
return null
|
|||
|
|
var item_id: StringName = _hotbar.get_item_id(slot_index)
|
|||
|
|
if item_id.is_empty():
|
|||
|
|
return null
|
|||
|
|
var item: ItemDataType = _catalog.get_item_by_id(item_id)
|
|||
|
|
var preview := TextureRect.new()
|
|||
|
|
preview.custom_minimum_size = Vector2(44, 44)
|
|||
|
|
preview.texture = item.icon if item != null else null
|
|||
|
|
preview.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
|||
|
|
preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
|||
|
|
preview.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|||
|
|
set_drag_preview(preview)
|
|||
|
|
_drag_in_progress = true
|
|||
|
|
item_drag_started.emit()
|
|||
|
|
return {
|
|||
|
|
"kind": "hotbar_slot",
|
|||
|
|
"slot_index": slot_index,
|
|||
|
|
"item_id": String(item_id),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _can_drop_data(_at_position: Vector2, data: Variant) -> bool:
|
|||
|
|
if not _drag_enabled or typeof(data) != TYPE_DICTIONARY:
|
|||
|
|
return false
|
|||
|
|
var payload: Dictionary = data
|
|||
|
|
var kind: String = str(payload.get("kind", ""))
|
|||
|
|
if kind == "hotbar_slot":
|
|||
|
|
var source_index: int = int(payload.get("slot_index", -1))
|
|||
|
|
return (
|
|||
|
|
source_index >= 0
|
|||
|
|
and source_index < PlayerHotbarType.SLOT_COUNT
|
|||
|
|
and source_index != slot_index
|
|||
|
|
)
|
|||
|
|
if kind != "bag_item":
|
|||
|
|
return false
|
|||
|
|
var item_id: StringName = StringName(str(payload.get("item_id", "")))
|
|||
|
|
if _bag == null or not _bag.owns_item(item_id) or _catalog == null:
|
|||
|
|
return false
|
|||
|
|
var item: ItemDataType = _catalog.get_item_by_id(item_id)
|
|||
|
|
return item != null and item.is_valid() and item.hotbar_allowed
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _drop_data(_at_position: Vector2, data: Variant) -> void:
|
|||
|
|
if not _can_drop_data(Vector2.ZERO, data) or _hotbar == null:
|
|||
|
|
return
|
|||
|
|
var payload: Dictionary = data
|
|||
|
|
if str(payload.get("kind", "")) == "hotbar_slot":
|
|||
|
|
_hotbar.swap_slots(int(payload["slot_index"]), slot_index)
|
|||
|
|
else:
|
|||
|
|
_hotbar.assign_item(
|
|||
|
|
slot_index,
|
|||
|
|
StringName(str(payload["item_id"]))
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _select_slot() -> void:
|
|||
|
|
if _hotbar != null:
|
|||
|
|
_hotbar.select_slot(slot_index)
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _on_mouse_entered() -> void:
|
|||
|
|
if _hotbar != null:
|
|||
|
|
item_hovered.emit(slot_index, _hotbar.get_item_id(slot_index))
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _on_mouse_exited() -> void:
|
|||
|
|
item_hover_ended.emit(slot_index)
|
|||
|
|
|
|||
|
|
|
|||
|
|
func _notification(what: int) -> void:
|
|||
|
|
if what == NOTIFICATION_DRAG_END and _drag_in_progress:
|
|||
|
|
_drag_in_progress = false
|
|||
|
|
item_drag_finished.emit()
|