diff --git a/godot/addons/collections/int_range.gd b/godot/addons/collections/int_range.gd index 021d90e..462aeb0 100644 --- a/godot/addons/collections/int_range.gd +++ b/godot/addons/collections/int_range.gd @@ -18,13 +18,22 @@ func _init(start: int, end: int, inclusive: bool = false) -> void: minmax = PackedInt32Array([start, end]) self.inclusive = inclusive +static func from_sized(value: Variant) -> Result: + match KCUtils.get_size(value): + var len when len.is_ok(): + return Result.ok(IntRange.new(0, len.unwrap())) + var e: return e + func _to_string() -> String: var ch = "]" if inclusive else ")" return "IntRange [%s, %s%s" % [min, max, ch] -func length() -> int: +func size() -> int: return absi(max - min) +func length() -> int: + return size() + func is_zero() -> bool: return min == 0 and max == 0 diff --git a/godot/addons/collections/tuple.gd b/godot/addons/collections/tuple.gd new file mode 100644 index 0000000..c08420f --- /dev/null +++ b/godot/addons/collections/tuple.gd @@ -0,0 +1,15 @@ +class_name Tuple extends RefCounted + +var _items: Array + +func _init(items: Array) -> void: + _items = items + +static func from_iter(iter: Iterator): + Tuple.new(iter.collect()) + +func iter() -> Iterator: + return ListIterator.from_array(_items) + +func _get(property) -> Variant: + return _items[property] diff --git a/godot/addons/collections/tuple.gd.uid b/godot/addons/collections/tuple.gd.uid new file mode 100644 index 0000000..d60c0dd --- /dev/null +++ b/godot/addons/collections/tuple.gd.uid @@ -0,0 +1 @@ +uid://crc57r28p8aem diff --git a/godot/addons/iterator/dict.gd b/godot/addons/iterator/dict.gd new file mode 100644 index 0000000..8e7560a --- /dev/null +++ b/godot/addons/iterator/dict.gd @@ -0,0 +1,23 @@ +class_name DictionaryIterator extends Iterator + +class Entry extends RefCounted: + var key + var value + + func _init(key: Variant, value: Variant) -> void: + self.key = key + self.value = value + +var dict: Dictionary +var keys: Iterator + +func _init(dict: Dictionary) -> void: + self.dict = dict + self.keys = ListIterator.from_array(dict.keys()) + +func next() -> Option: + match keys.next(): + var _key when _key.is_some(): + var key = _key.unwrap() + return Option.some(Entry.new(key, dict[key])) + return Option.none diff --git a/godot/addons/iterator/dict.gd.uid b/godot/addons/iterator/dict.gd.uid new file mode 100644 index 0000000..4065621 --- /dev/null +++ b/godot/addons/iterator/dict.gd.uid @@ -0,0 +1 @@ +uid://bvt4ktq7etavr diff --git a/godot/addons/iterator/empty.gd b/godot/addons/iterator/empty.gd new file mode 100644 index 0000000..59658dd --- /dev/null +++ b/godot/addons/iterator/empty.gd @@ -0,0 +1,4 @@ +class_name EmptyIterator extends Iterator + +func next() -> Option: + return Option.none diff --git a/godot/addons/iterator/empty.gd.uid b/godot/addons/iterator/empty.gd.uid new file mode 100644 index 0000000..2a54f9e --- /dev/null +++ b/godot/addons/iterator/empty.gd.uid @@ -0,0 +1 @@ +uid://dqbfj2kctxnwp diff --git a/godot/addons/iterator/filter.gd b/godot/addons/iterator/filter.gd new file mode 100644 index 0000000..b2afe39 --- /dev/null +++ b/godot/addons/iterator/filter.gd @@ -0,0 +1,14 @@ +class_name FilterIterator extends Iterator + +var iterator: Iterator +var predicate: Callable + +func _init(iterator: Iterator, predicate: Callable) -> void: + self.iterator = iterator + self.predicate = predicate + +func next() -> Option: + var value = iterator.next() + while value.is_some() and not predicate.call(value.unwrap()): + value = iterator.next() + return value diff --git a/godot/addons/iterator/filter.gd.uid b/godot/addons/iterator/filter.gd.uid new file mode 100644 index 0000000..66cae43 --- /dev/null +++ b/godot/addons/iterator/filter.gd.uid @@ -0,0 +1 @@ +uid://bmt0rqpkd5ugi diff --git a/godot/addons/iterator/inspect.gd b/godot/addons/iterator/inspect.gd new file mode 100644 index 0000000..89decdc --- /dev/null +++ b/godot/addons/iterator/inspect.gd @@ -0,0 +1,15 @@ +class_name InspectIterator extends Iterator + +var iterator: Iterator +var fn: Callable + +func _init(iterator: Iterator, fn: Callable) -> void: + self.iterator = iterator + self.fn = fn + +func next() -> Option: + match iterator.next(): + var x when x.is_some(): + fn.call(x.unwrap()) + return x + var x: return x diff --git a/godot/addons/iterator/inspect.gd.uid b/godot/addons/iterator/inspect.gd.uid new file mode 100644 index 0000000..9978772 --- /dev/null +++ b/godot/addons/iterator/inspect.gd.uid @@ -0,0 +1 @@ +uid://bvnn2llh6fmo0 diff --git a/godot/addons/iterator/iterator.gd b/godot/addons/iterator/iterator.gd index f2bc24f..367604f 100644 --- a/godot/addons/iterator/iterator.gd +++ b/godot/addons/iterator/iterator.gd @@ -1,33 +1,114 @@ class_name Iterator extends RefCounted +static func repeat(value: Variant) -> RepeatIterator: + return RepeatIterator.new(value) + func _to_string() -> String: - return "Iterator" + return "Iterator" func clone() -> Iterator: - assert(false, "can't clone a abstract base class") - return null + assert(false, "can't clone a abstract base class") + return null func next() -> Option: - return Option.none + return Option.none + +static func empty() -> Iterator: + return EmptyIterator.new() + +func advance_by(amount: int) -> Iterator: + for _i in range(amount): + if self.next().is_none(): + return empty() + return self + +func all(predicate: Callable) -> bool: + for value in self: + if not predicate.call(value): + return false + return true + +func any(predicate: Callable) -> bool: + for value in self: + if predicate.call(value): + return true + return false func collect() -> Array: - var result = [] - for item in self: - result.append(item) - return result + var result = [] + for item in self: + result.append(item) + return result -func into_peekable() -> PeekableIter: - return PeekableIter.new(self) +func count() -> int: + var length = 0 + for _value in self: + length += 1 + return length -func into_indexed() -> IndexedIterator: - return IndexedIterator.new(self) +func enumerate() -> IndexedIterator: + return IndexedIterator.new(self) + +func filter(predicate: Callable) -> FilterIterator: + return FilterIterator.new(self, predicate) + +func find(predicate: Callable) -> Option: + for value in self: + if predicate.call(value): + return Option.some(value) + return Option.none + +func fuse(other: Iterator) -> FusedIterator: + return FusedIterator.new([self, other]) + +func inspect(fn: Callable) -> Iterator: + return InspectIterator.new(self, fn) + +func last() -> Option: + var last = Option.none + for value in self: + last = Option.some(value) + return last + +func map(fn: Callable) -> MapIterator: + return MapIterator.new(self, fn) + +func peekable() -> PeekableIter: + return PeekableIter.new(self) + +func position(predicate: Callable) -> Option: + for indexed_value in self.enumerate(): + if predicate.call(indexed_value.value): + return Option.some(indexed_value.index) + return Option.none + +func reduce(reducer: Callable, initial_value: Variant) -> Option: + return scan(reducer, initial_value).last() + +func scan(reducer: Callable, initial_value: Variant) -> ReduceIterator: + return ReduceIterator.new(self, reducer, initial_value) + +func skip(amount: int) -> SkipIterator: + return SkipIterator.new(self, amount) + +func skip_while(predicate: Callable) -> SkipWhileIterator: + return SkipWhileIterator.new(self, predicate) + +func take(limit: int) -> TakeIterator: + return TakeIterator.new(self, limit) + +func take_while(predicate: Callable) -> TakeWhileIter: + return TakeWhileIter.new(self, predicate) + +func zip(a: Iterator, b: Iterator) -> ZipIterator: + return ZipIterator.new(a, b) func _iter_init(iter: Array) -> bool: - return _iter_next(iter) + return _iter_next(iter) func _iter_next(iter: Array) -> bool: - iter[0] = next() - return iter[0].is_some() + iter[0] = next() + return iter[0].is_some() func _iter_get(iter: Variant) -> Variant: - return iter.unwrap() + return iter.unwrap() diff --git a/godot/addons/iterator/list.gd b/godot/addons/iterator/list.gd index 4274338..b366540 100644 --- a/godot/addons/iterator/list.gd +++ b/godot/addons/iterator/list.gd @@ -7,6 +7,9 @@ func _init(value: Variant, iter: RangeIterator) -> void: _value = value _iter = iter +static func from_array(array: Array) -> ListIterator: + return ListIterator.new(array, RangeIterator.from_array(array)) + func _at(index: int) -> Variant: return _value[index] diff --git a/godot/addons/iterator/map.gd b/godot/addons/iterator/map.gd new file mode 100644 index 0000000..d846c9c --- /dev/null +++ b/godot/addons/iterator/map.gd @@ -0,0 +1,14 @@ +class_name MapIterator extends Iterator + +var iterator: Iterator +var morphism: Callable + +func _init(iterator: Iterator, fn: Callable) -> void: + self.iterator = iterator + self.morphism = fn + +func next() -> Option: + match iterator.next(): + var x when x.is_some(): + return Option.some(morphism.call(x.unwrap())) + _: return Option.none diff --git a/godot/addons/iterator/map.gd.uid b/godot/addons/iterator/map.gd.uid new file mode 100644 index 0000000..1d0a85c --- /dev/null +++ b/godot/addons/iterator/map.gd.uid @@ -0,0 +1 @@ +uid://y6345wflhmr1 diff --git a/godot/addons/iterator/range.gd b/godot/addons/iterator/range.gd index 5effb90..8ba3e23 100644 --- a/godot/addons/iterator/range.gd +++ b/godot/addons/iterator/range.gd @@ -17,6 +17,18 @@ func _init(range: IntRange, start_index: int = range.min, step: int = 1) -> void func from_values(from: int, to: int, start_index: int = range.min, step: int = 1) -> RangeIterator: return RangeIterator.new(IntRange.new(from, to), start_index, step) +static func from_sized(value: Variant) -> Result: + match IntRange.from_sized(value): + var range when range.is_ok(): + return Result.ok(RangeIterator.new(range.unwrap())) + var e: return e + +static func from_array(array: Array) -> RangeIterator: + return RangeIterator.from_sized(array).unwrap() + +func size() -> int: + return range.size() + func length() -> int: return range.length() diff --git a/godot/addons/iterator/reduce.gd b/godot/addons/iterator/reduce.gd new file mode 100644 index 0000000..70a7251 --- /dev/null +++ b/godot/addons/iterator/reduce.gd @@ -0,0 +1,21 @@ +class_name ReduceIterator extends Iterator + +var iterator: Iterator +var reducer: Callable +var accumulator: Variant + +func _init(iterator: Iterator, reducer: Callable, initial_value: Variant) -> void: + self.iterator = iterator + self.reducer = reducer + accumulator = initial_value + +func next() -> Option: + var value = iterator.next() + if value.is_none(): return value + + if accumulator == null: + accumulator = value + else: + accumulator = reducer.call(accumulator, value) + + return Option.some(accumulator) diff --git a/godot/addons/iterator/reduce.gd.uid b/godot/addons/iterator/reduce.gd.uid new file mode 100644 index 0000000..bf28f7d --- /dev/null +++ b/godot/addons/iterator/reduce.gd.uid @@ -0,0 +1 @@ +uid://d1nuo4gmvw6gb diff --git a/godot/addons/iterator/repeat.gd b/godot/addons/iterator/repeat.gd new file mode 100644 index 0000000..5d20fe1 --- /dev/null +++ b/godot/addons/iterator/repeat.gd @@ -0,0 +1,9 @@ +class_name RepeatIterator extends Iterator + +var value: Variant + +func _init(value: Variant) -> void: + self.value = value + +func next() -> Option: + return Option.some(value) diff --git a/godot/addons/iterator/repeat.gd.uid b/godot/addons/iterator/repeat.gd.uid new file mode 100644 index 0000000..859aa64 --- /dev/null +++ b/godot/addons/iterator/repeat.gd.uid @@ -0,0 +1 @@ +uid://bmfuvpufiq7fl diff --git a/godot/addons/iterator/skip.gd b/godot/addons/iterator/skip.gd new file mode 100644 index 0000000..bcc6d39 --- /dev/null +++ b/godot/addons/iterator/skip.gd @@ -0,0 +1,15 @@ +class_name SkipIterator extends Iterator + +var iterator: Iterator +var amount: int +var _skipped: bool = false + +func _init(iterator: Iterator, amount: int) -> void: + self.iterator = iterator + self.amount = amount + +func next() -> Option: + if not _skipped: + iterator.advance_by(amount) + _skipped = true + return iterator.next() diff --git a/godot/addons/iterator/skip.gd.uid b/godot/addons/iterator/skip.gd.uid new file mode 100644 index 0000000..fd70a4e --- /dev/null +++ b/godot/addons/iterator/skip.gd.uid @@ -0,0 +1 @@ +uid://mg6bs321701m diff --git a/godot/addons/iterator/skip_while.gd b/godot/addons/iterator/skip_while.gd new file mode 100644 index 0000000..24a25ec --- /dev/null +++ b/godot/addons/iterator/skip_while.gd @@ -0,0 +1,18 @@ +class_name SkipWhileIterator extends Iterator + +var iterator: Iterator +var predicate: Callable +var _skipped: bool = false + +func _init(iterator: Iterator, predicate: Callable) -> void: + self.iterator = iterator + self.predicate = predicate + +func next() -> Option: + if not _skipped: + var value = iterator.next() + while value.is_some() and predicate.call(value): + value = iterator.next() + _skipped = true + return value + return iterator.next() diff --git a/godot/addons/iterator/skip_while.gd.uid b/godot/addons/iterator/skip_while.gd.uid new file mode 100644 index 0000000..cd97781 --- /dev/null +++ b/godot/addons/iterator/skip_while.gd.uid @@ -0,0 +1 @@ +uid://i2jri31g6mam diff --git a/godot/addons/iterator/take.gd b/godot/addons/iterator/take.gd new file mode 100644 index 0000000..994255a --- /dev/null +++ b/godot/addons/iterator/take.gd @@ -0,0 +1,15 @@ +class_name TakeIterator extends Iterator + +var iter: Iterator +var limit: int + +func _init(iter: Iterator, limit: int) -> void: + self.iter = iter + self.limit = limit + +func next() -> Option: + if limit < 0: + return Option.none + + limit -= 1 + return iter.next() diff --git a/godot/addons/iterator/take.gd.uid b/godot/addons/iterator/take.gd.uid new file mode 100644 index 0000000..313c5fd --- /dev/null +++ b/godot/addons/iterator/take.gd.uid @@ -0,0 +1 @@ +uid://dnxnj6qn8fqrq diff --git a/godot/addons/iterator/zip.gd b/godot/addons/iterator/zip.gd new file mode 100644 index 0000000..2787dac --- /dev/null +++ b/godot/addons/iterator/zip.gd @@ -0,0 +1,14 @@ +class_name ZipIterator extends Iterator + +var iter1: Iterator +var iter2: Iterator + +func _init(a: Iterator, b: Iterator) -> void: + iter1 = a + iter2 = b + +func next() -> Option: + match [iter1.next(), iter2.next()]: + [var a, var b] when a.is_some() and b.is_some(): + return Option.some(Tuple.new([a.unwrap(), b.unwrap()])) + _: return Option.none diff --git a/godot/addons/iterator/zip.gd.uid b/godot/addons/iterator/zip.gd.uid new file mode 100644 index 0000000..722e76f --- /dev/null +++ b/godot/addons/iterator/zip.gd.uid @@ -0,0 +1 @@ +uid://bu2orcurqmml1 diff --git a/godot/addons/utils/utils.gd b/godot/addons/utils/utils.gd index 0c20827..7812f49 100644 --- a/godot/addons/utils/utils.gd +++ b/godot/addons/utils/utils.gd @@ -1,49 +1,63 @@ class_name KCUtils -static func remove_children(node: Node): - for i in range(node.get_child_count()): - node.remove_child(node.get_child(i)) +static func remove_children(node: Node, delete: bool = true): + for i in range(node.get_child_count() - 1, -1, -1): + var child = node.get_child(i) + node.remove_child(child) + if delete: + child.queue_free() static func get_class_name(value: Object) -> String: - match value.get_script(): - var script when script != null: - match script.get_global_name(): - var name when name != null: return name - _: return script.get_instance_base_type() - _: return value.get_class() + match value.get_script(): + var script when script != null: + match script.get_global_name(): + var name when name != null: return name + _: return script.get_instance_base_type() + _: return value.get_class() static func is_string_like(value: Variant) -> bool: - match typeof(value): - TYPE_STRING: return true - TYPE_STRING_NAME: return true - TYPE_NODE_PATH: return true - _: return false + match typeof(value): + TYPE_STRING: return true + TYPE_STRING_NAME: return true + TYPE_NODE_PATH: return true + _: return false static func to_str(value: Variant) -> String: - match typeof(value): - TYPE_OBJECT: - if value.has_method('_to_string'): - return value.to_string() - else: - var name = get_class_name(value) - value = value as Object - var props: Dictionary = inst_to_dict(value) - return "%s %s" % [name, to_str(props)] - _: return str(value) + match typeof(value): + TYPE_OBJECT: + if value.has_method('_to_string'): + return value.to_string() + else: + var name = get_class_name(value) + value = value as Object + var props: Dictionary = inst_to_dict(value) + return "%s %s" % [name, to_str(props)] + _: return str(value) static func propagate(node: Node, fn: StringName, args: Array, call_on_self: bool = true): - if call_on_self and node.has_method(fn): - node.callv(fn, args) + if call_on_self and node.has_method(fn): + node.callv(fn, args) - for child in node.get_children(): - propagate(child, fn, args) + for child in node.get_children(): + propagate(child, fn, args) static func propagate_input_event(node: Node, fn: StringName, event: InputEvent, call_on_self: bool = true): - if node.get_viewport().is_input_handled() or event.is_canceled(): - return + if node.get_viewport().is_input_handled() or event.is_canceled(): + return - if call_on_self and node.has_method(fn): - node.callv(fn, [event]) + if call_on_self and node.has_method(fn): + node.callv(fn, [event]) - for child in node.get_children(): - propagate_input_event(child, fn, event) + for child in node.get_children(): + propagate_input_event(child, fn, event) + +static func get_size(value: Variant) -> Result: + match typeof(value): + TYPE_STRING | TYPE_VECTOR2 | TYPE_VECTOR2I | TYPE_VECTOR3 | TYPE_VECTOR3I | TYPE_VECTOR4 | TYPE_VECTOR4I | TYPE_QUATERNION: + return Result.ok(value.length()) + var x when x >= 27 and x <= 38: + return Result.ok(value.size()) + _: return Result.err(Error.NotImplemented.new('"length" or "size"')) + +static func len(value: Variant) -> int: + return get_size(value).unwrap() diff --git a/godot/resources/player_equipment.tres b/godot/resources/player_equipment.tres index e544b57..bc9ef06 100644 --- a/godot/resources/player_equipment.tres +++ b/godot/resources/player_equipment.tres @@ -1,9 +1,7 @@ -[gd_resource type="Resource" script_class="Equipment" load_steps=3 format=3 uid="uid://cxm3s081hnw8l"] +[gd_resource type="Resource" script_class="Equipment" load_steps=2 format=3 uid="uid://cxm3s081hnw8l"] [ext_resource type="Script" uid="uid://bff1tgf3sn855" path="res://src/equipment.gd" id="1_ajqsy"] -[ext_resource type="Resource" uid="uid://crgwey6ibaf2h" path="res://resources/items/pistol.tres" id="1_hds1i"] [resource] script = ExtResource("1_ajqsy") -_primary = ExtResource("1_hds1i") metadata/_custom_type_script = "uid://bff1tgf3sn855" diff --git a/godot/scenes/inventory.tscn b/godot/scenes/inventory.tscn index d68bd9c..cbf4bc0 100644 --- a/godot/scenes/inventory.tscn +++ b/godot/scenes/inventory.tscn @@ -1,10 +1,12 @@ -[gd_scene load_steps=10 format=3 uid="uid://cn7tgd4y67wnd"] +[gd_scene load_steps=12 format=3 uid="uid://cn7tgd4y67wnd"] [ext_resource type="Script" uid="uid://qvoqvonnxwfc" path="res://src/inventory_ui.gd" id="1_a0rpf"] [ext_resource type="Script" uid="uid://bx4wxlm5mv268" path="res://src/root_control.gd" id="1_as33y"] [ext_resource type="Resource" uid="uid://bllq6ri54q3ne" path="res://resources/player_inventory.tres" id="2_as33y"] [ext_resource type="PackedScene" uid="uid://gn8k2ir47n1m" path="res://scenes/inventory_item.tscn" id="3_tg4gd"] -[ext_resource type="Script" uid="uid://13lxe4c4fmrp" path="res://addons/FreeControl/src/CustomClasses/Carousel/Carousel.gd" id="4_usnyx"] +[ext_resource type="Script" uid="uid://bpwbaanf6w65h" path="res://src/index_carousel.gd" id="5_uae8j"] +[ext_resource type="Script" uid="uid://c8m7eq6a3tpgu" path="res://src/item_details_ui.gd" id="6_s887n"] +[ext_resource type="Resource" uid="uid://cxm3s081hnw8l" path="res://resources/player_equipment.tres" id="7_s887n"] [sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_as33y"] size = Vector2(128, 128) @@ -66,14 +68,21 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -script = ExtResource("4_usnyx") +script = ExtResource("5_uae8j") +with_drag = true +with_clamp = true display_range = 5 snap_behavior = 2 paging_requirement = 100 +metadata/_custom_type_script = "uid://bpwbaanf6w65h" -[node name="ItemDetails" type="HBoxContainer" parent="Contents"] +[node name="ItemDetails" type="HBoxContainer" parent="Contents" node_paths=PackedStringArray("icon_image", "description_label")] layout_mode = 2 size_flags_vertical = 3 +script = ExtResource("6_s887n") +equipment = ExtResource("7_s887n") +icon_image = NodePath("Display/TextureRect") +description_label = NodePath("Description/Label") [node name="PlayerInfo" type="VBoxContainer" parent="Contents/ItemDetails"] layout_mode = 2 @@ -110,3 +119,5 @@ size_flags_horizontal = 3 [node name="Label" type="Label" parent="Contents/ItemDetails/Description"] layout_mode = 2 text = "a description" + +[connection signal="item_selected" from="Contents/InventoryUI" to="Contents/ItemDetails" method="_on_updated"] diff --git a/godot/src/index_carousel.gd b/godot/src/index_carousel.gd new file mode 100644 index 0000000..0285807 --- /dev/null +++ b/godot/src/index_carousel.gd @@ -0,0 +1,18 @@ +@tool +class_name IndexCarousel extends Carousel + +signal index_changed(index: int) + +@export var with_drag: bool = false +@export var with_clamp: bool = false + +var current_index: int = 0 + +func _ready() -> void: + current_index = get_carousel_index(with_drag, with_clamp) + +func _on_progress(_scroll: int) -> void: + var next_index = get_carousel_index(with_drag, with_clamp) + if current_index != next_index: + current_index = next_index + index_changed.emit(current_index) diff --git a/godot/src/index_carousel.gd.uid b/godot/src/index_carousel.gd.uid new file mode 100644 index 0000000..4b85fb9 --- /dev/null +++ b/godot/src/index_carousel.gd.uid @@ -0,0 +1 @@ +uid://bpwbaanf6w65h diff --git a/godot/src/inventory.gd b/godot/src/inventory.gd index 584dd0d..def725a 100644 --- a/godot/src/inventory.gd +++ b/godot/src/inventory.gd @@ -1,75 +1,60 @@ class_name Inventory extends Resource -class InventoryIterator extends Iterator: - var values: Array[ItemInstance] - var size: int - var index: int = 0 - - @warning_ignore("shadowed_variable") - func _init(values: Array[ItemInstance], size: int = values.size()) -> void: - self.values = values - self.size = size - - func next() -> Option: - if index < size: - var value = Option.some(values[index]) - index += 1 - return value - else: - return Option.none - -@export var initial_items: Array[ItemInstance] -@export var max_capacity: int = 6 - -var items: Dictionary[int, ItemInstance] -var size: int: - get: return items.size() - signal item_added(item: Item, quantity: int) signal item_removed(item: Item, remaining: int) signal updated +@export var initial_items: Array[ItemInstance] +@export var max_capacity: int = 6 + +var items: Dictionary[int, ItemInstance] +var empty_slots: int: + get: return max_capacity - size() + func _init(): - call_deferred("_ready") + call_deferred("_ready") func _ready(): - for item in initial_items: - items[_get_id(item.item)] = item - updated.emit() + for item in initial_items: + items[_get_id(item.item)] = item + updated.emit() + +func size() -> int: + return items.size() func _get_id(item: Item) -> int: - return item.get_instance_id() + return item.get_instance_id() func _item_eq(a: Item, b: ItemInstance) -> bool: - return a.item == b + return a.item == b func has_item(item: Item) -> bool: - return items.has(_get_id(item)) + return items.has(_get_id(item)) func find(item: Item) -> Option: - match items.get(_get_id(item)): - null: return Option.none - var found: return Option.some(found) + match items.get(_get_id(item)): + null: return Option.none + var found: return Option.some(found) func add_item(item: Item, quantity: int = 1): - var id = _get_id(item) - var updated_quantity = quantity - if items.has(id): - items[id].quantity += quantity - updated_quantity = items[id].quantity - else: - items[id] = ItemInstance.new(item, quantity) + var id = _get_id(item) + var updated_quantity = quantity + if items.has(id): + items[id].quantity += quantity + updated_quantity = items[id].quantity + else: + items[id] = ItemInstance.new(item, quantity) - item_added.emit(item, updated_quantity) - updated.emit() + item_added.emit(item, updated_quantity) + updated.emit() func remove_item(item: Item, quantity: int = 1): - if find(item): - item.quantity -= quantity - if item.quantity <= 0: - items.erase(_get_id(item)) - item_removed.emit(item, item.quantity) - updated.emit() + if find(item): + item.quantity -= quantity + if item.quantity <= 0: + items.erase(_get_id(item)) + item_removed.emit(item, item.quantity) + updated.emit() -func iter() -> InventoryIterator: - return InventoryIterator.new(items.values(), max_capacity) +func iter() -> Iterator: + return DictionaryIterator.new(items) diff --git a/godot/src/inventory_ui.gd b/godot/src/inventory_ui.gd index 9e7bea5..0957462 100644 --- a/godot/src/inventory_ui.gd +++ b/godot/src/inventory_ui.gd @@ -1,44 +1,68 @@ class_name InventoryUI extends Control +signal item_selected(item: Option) + @export var inventory: Inventory @export var item_scene: PackedScene -@export var carousel: Carousel +@export var carousel: IndexCarousel func _ready() -> void: - inventory.updated.connect(_build_carousel) + inventory.updated.connect(_build_carousel) + carousel.index_changed.connect(_on_item_changed) -func _build_carousel(): - KCUtils.remove_children(carousel) +func _on_item_changed(index: int) -> void: + var found: bool = false + for indexed_value in IndexedIterator.new(inventory.iter()): + if indexed_value.index == index: + found = true + item_selected.emit(Option.from(indexed_value.value.value.item)) + break - var items = inventory.items.values() - var count = items.size() - for i in range(inventory.max_capacity): - var scene = create_item() - var value = Option.none - if i < count: - value = Option.some(items[i].item) - bind_item(scene, value) - carousel.add_child(scene) + if not found: + item_selected.emit(Option.none) + +func _build_carousel() -> void: + KCUtils.remove_children(carousel) + + var empty_iter = Iterator.repeat(null).take(inventory.empty_slots) + var item_iter = ListIterator.from_array(inventory.items.values().map(func(x): return x.item)) + var items = FusedIterator.new([item_iter, empty_iter]) + + for item in items: + var scene = create_item() + var option = Option.from(item) + bind_item(scene, option) + carousel.add_child(scene) + + #var items = inventory.items.values() + #var count = items.size() + #for i in range(inventory.max_capacity): + # var scene = create_item() + # var value = Option.none + # if i < count: + # value = Option.some(items[i].item) + # bind_item(scene, value) + # carousel.add_child(scene) func create_item() -> Node: - return item_scene.instantiate() + return item_scene.instantiate() -func bind_item(node: Node, item: Option): - if node.has_method('bind'): - node.bind(item) +func bind_item(node: Node, item: Option) -> void: + if node.has_method('bind'): + node.bind(item) func _gui_input(event: InputEvent) -> void: - if event.is_action_pressed(PlayerInput.UIAction.Right): - move_right() - elif event.is_action_pressed(PlayerInput.UIAction.Left): - move_left() + if event.is_action_pressed(PlayerInput.UIAction.Right): + move_right() + elif event.is_action_pressed(PlayerInput.UIAction.Left): + move_left() func move_by(delta: int): - var next_index = carousel.get_carousel_index() + delta - carousel.go_to_index(next_index) + var next_index = carousel.get_carousel_index() + delta + carousel.go_to_index(next_index) func move_right(): - move_by(1) + move_by(1) func move_left(): - move_by(-1) + move_by(-1) diff --git a/godot/src/item_container.gd b/godot/src/item_container.gd index 1d231d4..3fa2e05 100644 --- a/godot/src/item_container.gd +++ b/godot/src/item_container.gd @@ -14,5 +14,5 @@ func add_item(item: Item, quantity: int = 1): func remove_item(item: Item, quantity: int = 1): return inventory.remove_item(item, quantity) -func iter() -> Inventory.InventoryIterator: +func iter() -> Iterator: return inventory.iter() diff --git a/godot/src/item_details_ui.gd b/godot/src/item_details_ui.gd index 1c077c8..3d99f70 100644 --- a/godot/src/item_details_ui.gd +++ b/godot/src/item_details_ui.gd @@ -1,5 +1,6 @@ class_name ItemDetailsUI extends HBoxContainer +@export var equipment: Equipment @export var icon_image: TextureRect @export var description_label: Label @@ -14,10 +15,10 @@ func _set_default(): icon_image.texture = _default_icon description_label.text = _default_description -func _on_updated(_item: Option): - if _item.is_some(): - var item: Item = _item.unwrap() - icon_image.texture = item.icon - description_label.text = item.description +func _on_updated(item: Option): + if item.is_some(): + var _item: Item = item.unwrap() + icon_image.texture = _item.icon + description_label.text = _item.description else: _set_default() diff --git a/godot/src/item_details_ui.gd.uid b/godot/src/item_details_ui.gd.uid index 2314589..fe6aab5 100644 --- a/godot/src/item_details_ui.gd.uid +++ b/godot/src/item_details_ui.gd.uid @@ -1 +1 @@ -uid://dfvvqpgu8r5v6 +uid://c8m7eq6a3tpgu