diff --git a/godot/addons/FreeControl/src/CustomClasses/Carousel/Carousel.gd b/godot/addons/FreeControl/src/CustomClasses/Carousel/Carousel.gd index 512f1ca..32a9f95 100644 --- a/godot/addons/FreeControl/src/CustomClasses/Carousel/Carousel.gd +++ b/godot/addons/FreeControl/src/CustomClasses/Carousel/Carousel.gd @@ -330,6 +330,7 @@ func _get_child_rect(child : Control) -> Rect2: child.position = child_pos return Rect2(child_pos, child_size) + func _get_control_children() -> Array[Control]: var ret : Array[Control] ret.assign(get_children().filter(func(child : Node): return child is Control && child.visible)) diff --git a/godot/addons/iterator/index.gd b/godot/addons/iterator/index.gd index 9d67ce5..6f4969e 100644 --- a/godot/addons/iterator/index.gd +++ b/godot/addons/iterator/index.gd @@ -21,4 +21,6 @@ func clone() -> IndexedIterator: return IndexedIterator.new(_iter.clone()) func next() -> Option: - return _iter.next().map(_add_index) + var next_value = _iter.next().map(_add_index) + _index += 1 + return next_value diff --git a/godot/addons/iterator/iterator.gd b/godot/addons/iterator/iterator.gd index 367604f..c46b164 100644 --- a/godot/addons/iterator/iterator.gd +++ b/godot/addons/iterator/iterator.gd @@ -70,6 +70,10 @@ func last() -> Option: last = Option.some(value) return last +func nth(index: int) -> Option: + advance_by(index - 1) + return self.next() + func map(fn: Callable) -> MapIterator: return MapIterator.new(self, fn) diff --git a/godot/addons/utils/utils.gd b/godot/addons/utils/utils.gd index 7812f49..5bf8c56 100644 --- a/godot/addons/utils/utils.gd +++ b/godot/addons/utils/utils.gd @@ -34,6 +34,24 @@ static func to_str(value: Variant) -> String: return "%s %s" % [name, to_str(props)] _: return str(value) +static func _always_pass(_any: Variant) -> bool: + return true + +static func notify(node: Node, notification: int, up: bool = false): + notify_while(node, notification, _always_pass, up) + +static func notify_while(node: Node, notification: int, predicate: Callable = _always_pass, up: bool = false): + node.notification(notification) + + if up: + var parent = node.get_parent() + if parent != null and predicate.call(parent): + notify_while(parent, notification, predicate, up) + else: + for child in node.get_children(): + if predicate.call(child): + notify_while(child, notification, predicate) + 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) diff --git a/godot/assets/icons/key_icon.tres b/godot/assets/icons/key_icon.tres new file mode 100644 index 0000000..5ed140d --- /dev/null +++ b/godot/assets/icons/key_icon.tres @@ -0,0 +1,8 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dngw0c0dc6u7x"] + +[ext_resource type="Texture2D" uid="uid://d3ergv453flsw" path="res://assets/sprites.png" id="1_gm5ao"] + +[resource] +atlas = ExtResource("1_gm5ao") +region = Rect2(256, 128, 64, 64) +margin = Rect2(-10, -12, -20, -20) diff --git a/godot/assets/icons/pistol_icon.tres b/godot/assets/icons/pistol_icon.tres new file mode 100644 index 0000000..2c293e7 --- /dev/null +++ b/godot/assets/icons/pistol_icon.tres @@ -0,0 +1,8 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dvxrifa0iu8ql"] + +[ext_resource type="Texture2D" uid="uid://d3ergv453flsw" path="res://assets/sprites.png" id="1_y5otb"] + +[resource] +atlas = ExtResource("1_y5otb") +region = Rect2(192, 256, 64, 64) +margin = Rect2(0, -10, 0, -12) diff --git a/godot/assets/pistol_icon.png b/godot/assets/pistol_icon.png new file mode 100644 index 0000000..304dd28 Binary files /dev/null and b/godot/assets/pistol_icon.png differ diff --git a/godot/assets/pistol_icon.png.import b/godot/assets/pistol_icon.png.import new file mode 100644 index 0000000..c6e6091 --- /dev/null +++ b/godot/assets/pistol_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bb35noqd4affs" +path="res://.godot/imported/pistol_icon.png-b7372c1e15b929d59375290c822ef47c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/pistol_icon.png" +dest_files=["res://.godot/imported/pistol_icon.png-b7372c1e15b929d59375290c822ef47c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/godot/assets/sprites.png b/godot/assets/sprites.png new file mode 100644 index 0000000..300aa34 Binary files /dev/null and b/godot/assets/sprites.png differ diff --git a/godot/assets/sprites.png.import b/godot/assets/sprites.png.import new file mode 100644 index 0000000..d6e123b --- /dev/null +++ b/godot/assets/sprites.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d3ergv453flsw" +path="res://.godot/imported/sprites.png-bb36f92a96c2b9ad48a8528dbf01963e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites.png" +dest_files=["res://.godot/imported/sprites.png-bb36f92a96c2b9ad48a8528dbf01963e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/godot/project.godot b/godot/project.godot index 7d34827..9449e31 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -23,6 +23,10 @@ PhantomCameraManager="*res://addons/phantom_camera/scripts/managers/phantom_came settings/addon_root_folder="res://addons/debug_draw_3d/addons/debug_draw_3d" +[display] + +window/stretch/mode="canvas_items" + [editor_plugins] enabled=PackedStringArray("res://addons/FreeControl/plugin.cfg", "res://addons/godot_object_serializer/plugin.cfg", "res://addons/phantom_camera/plugin.cfg") diff --git a/godot/resources/items/key.tres b/godot/resources/items/key.tres index 563d74b..2928796 100644 --- a/godot/resources/items/key.tres +++ b/godot/resources/items/key.tres @@ -1,12 +1,12 @@ [gd_resource type="Resource" script_class="Item" load_steps=3 format=3 uid="uid://cqfnwpmo4fyv4"] [ext_resource type="Script" uid="uid://bqprls343ue6e" path="res://src/item.gd" id="1_7ur50"] -[ext_resource type="Texture2D" uid="uid://djmxd4580q6xs" path="res://icon.svg" id="1_ykwyx"] +[ext_resource type="Texture2D" uid="uid://dngw0c0dc6u7x" path="res://assets/icons/key_icon.tres" id="1_ykwyx"] [resource] script = ExtResource("1_7ur50") -name = "DebugKey" -description = "whatever" +name = "Debug Key" +description = "An unusual key card." max_stack = 1 icon = ExtResource("1_ykwyx") metadata/_custom_type_script = "uid://bqprls343ue6e" diff --git a/godot/resources/items/pistol.tres b/godot/resources/items/pistol.tres index 39aed5e..f471afa 100644 --- a/godot/resources/items/pistol.tres +++ b/godot/resources/items/pistol.tres @@ -1,12 +1,16 @@ -[gd_resource type="Resource" script_class="Equipment" load_steps=3 format=3 uid="uid://crgwey6ibaf2h"] +[gd_resource type="Resource" script_class="EquippableItem" load_steps=5 format=3 uid="uid://crgwey6ibaf2h"] [ext_resource type="PackedScene" uid="uid://isqkayrtr7t8" path="res://scenes/pistol.tscn" id="1_6ttue"] +[ext_resource type="Texture2D" uid="uid://dvxrifa0iu8ql" path="res://assets/icons/pistol_icon.tres" id="1_112eb"] +[ext_resource type="PackedScene" uid="uid://dfljhd4e3l6j2" path="res://scenes/pistol_preview.tscn" id="1_gintf"] [ext_resource type="Script" uid="uid://c710qg683rqbc" path="res://src/equippable_item.gd" id="1_lqglu"] [resource] script = ExtResource("1_lqglu") -scene = ExtResource("1_6ttue") name = "Pistol" -description = "" +description = "A semi-automatic pistol. Fires 10mm ammunition from a 10-round magazine. Easy to use, high rate of fire." max_stack = 1 +icon = ExtResource("1_112eb") +scene = ExtResource("1_6ttue") +preview_scene = ExtResource("1_gintf") metadata/_custom_type_script = "uid://c710qg683rqbc" diff --git a/godot/scenes/box_ui.tres b/godot/scenes/box_ui.tres new file mode 100644 index 0000000..b95462b --- /dev/null +++ b/godot/scenes/box_ui.tres @@ -0,0 +1,45 @@ +[gd_resource type="Theme" load_steps=6 format=3 uid="uid://bb6tvyqikcf3r"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_odwru"] +bg_color = Color(0.6, 0.6, 0.6, 0) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_t6lws"] +bg_color = Color(0.92549, 0.243137, 0.0392157, 1) + +[sub_resource type="SystemFont" id="SystemFont_t6lws"] +font_names = PackedStringArray("Monospace") +font_weight = 600 +keep_rounding_remainders = false +multichannel_signed_distance_field = true + +[sub_resource type="SystemFont" id="SystemFont_odwru"] +font_names = PackedStringArray("monospace") +font_weight = 500 +multichannel_signed_distance_field = true + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4gq11"] +bg_color = Color(0.6, 0.6, 0.6, 0) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.92549, 0.243137, 0.0392157, 1) + +[resource] +BoxContent/base_type = &"Panel" +BoxContent/styles/panel = SubResource("StyleBoxFlat_odwru") +BoxHeader/base_type = &"PanelContainer" +BoxHeader/styles/panel = SubResource("StyleBoxFlat_t6lws") +BoxHeaderLabel/base_type = &"Label" +BoxHeaderLabel/colors/font_color = Color(0, 0, 0, 1) +BoxHeaderLabel/font_sizes/font_size = 8 +BoxHeaderLabel/fonts/font = SubResource("SystemFont_t6lws") +HBoxContainer/constants/separation = 8 +Label/font_sizes/font_size = 12 +Label/fonts/font = SubResource("SystemFont_odwru") +MarginContainer/constants/margin_bottom = 4 +MarginContainer/constants/margin_left = 4 +MarginContainer/constants/margin_right = 4 +MarginContainer/constants/margin_top = 4 +PanelContainer/styles/panel = SubResource("StyleBoxFlat_4gq11") +RichTextLabel/colors/default_color = Color(0.0745098, 0.0745098, 0.0745098, 1) diff --git a/godot/scenes/box_ui.tscn b/godot/scenes/box_ui.tscn new file mode 100644 index 0000000..32ecc42 --- /dev/null +++ b/godot/scenes/box_ui.tscn @@ -0,0 +1,28 @@ +[gd_scene load_steps=2 format=3 uid="uid://cidwsnulug6fl"] + +[ext_resource type="Theme" uid="uid://bb6tvyqikcf3r" path="res://scenes/box_ui.tres" id="1_e1aew"] + +[node name="Box" type="PanelContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = ExtResource("1_e1aew") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="Header" type="PanelContainer" parent="VBoxContainer"] +layout_mode = 2 +theme = ExtResource("1_e1aew") +theme_type_variation = &"BoxHeader" + +[node name="TitleContainer" type="MarginContainer" parent="VBoxContainer/Header"] +layout_mode = 2 + +[node name="Body" type="PanelContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +theme = ExtResource("1_e1aew") +theme_type_variation = &"BoxContent" diff --git a/godot/scenes/game_menu.tres b/godot/scenes/game_menu.tres new file mode 100644 index 0000000..dc95c95 --- /dev/null +++ b/godot/scenes/game_menu.tres @@ -0,0 +1,8 @@ +[gd_resource type="Theme" load_steps=2 format=3 uid="uid://bardurtuo08ox"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_vxpal"] +bg_color = Color(1, 1, 1, 1) + +[resource] +BoxContainer/constants/separation = 4 +PanelContainer/styles/panel = SubResource("StyleBoxFlat_vxpal") diff --git a/godot/scenes/inventory.tscn b/godot/scenes/inventory.tscn index cbf4bc0..fa24b3b 100644 --- a/godot/scenes/inventory.tscn +++ b/godot/scenes/inventory.tscn @@ -1,12 +1,15 @@ -[gd_scene load_steps=12 format=3 uid="uid://cn7tgd4y67wnd"] +[gd_scene load_steps=14 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="Theme" uid="uid://bb6tvyqikcf3r" path="res://scenes/box_ui.tres" id="1_sr8g6"] [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://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"] +[ext_resource type="PackedScene" uid="uid://cidwsnulug6fl" path="res://scenes/box_ui.tscn" id="8_g71ie"] +[ext_resource type="Script" uid="uid://c4gfdpuc14mpq" path="res://src/cancel_button.gd" id="10_p7iul"] [sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_as33y"] size = Vector2(128, 128) @@ -17,9 +20,6 @@ size = Vector2(128, 128) [sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_usnyx"] size = Vector2(128, 64) -[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_sebc8"] -size = Vector2(256, 256) - [node name="Inventory" type="Control"] layout_mode = 3 anchors_preset = 15 @@ -30,6 +30,7 @@ grow_vertical = 2 size_flags_horizontal = 3 size_flags_vertical = 3 focus_mode = 2 +theme = ExtResource("1_sr8g6") script = ExtResource("1_as33y") open_action = &"open_inventory" close_action = &"ui_close_inventory" @@ -43,16 +44,23 @@ grow_horizontal = 2 grow_vertical = 2 color = Color(0.147672, 0.147672, 0.147672, 1) -[node name="Contents" type="VBoxContainer" parent="."] +[node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 + +[node name="Contents" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 alignment = 1 -[node name="InventoryUI" type="Control" parent="Contents" node_paths=PackedStringArray("carousel")] +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Contents"] +layout_mode = 2 + +[node name="InventoryList" type="Control" parent="MarginContainer/Contents/MarginContainer" node_paths=PackedStringArray("carousel")] +custom_minimum_size = Vector2(0, 150) layout_mode = 2 size_flags_vertical = 3 script = ExtResource("1_a0rpf") @@ -61,63 +69,182 @@ item_scene = ExtResource("3_tg4gd") carousel = NodePath("Carousel") metadata/_custom_type_script = "uid://qvoqvonnxwfc" -[node name="Carousel" type="Container" parent="Contents/InventoryUI"] +[node name="Carousel" type="Container" parent="MarginContainer/Contents/MarginContainer/InventoryList"] +custom_minimum_size = Vector2(0, 100) layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +scale = Vector2(1, 1.01) script = ExtResource("5_uae8j") with_drag = true with_clamp = true -display_range = 5 +item_size = Vector2(150, 100) +item_seperation = 64 snap_behavior = 2 paging_requirement = 100 metadata/_custom_type_script = "uid://bpwbaanf6w65h" -[node name="ItemDetails" type="HBoxContainer" parent="Contents" node_paths=PackedStringArray("icon_image", "description_label")] +[node name="Details" type="HBoxContainer" parent="MarginContainer/Contents" node_paths=PackedStringArray("viewport", "description_label", "action_menu")] 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") +viewport = NodePath("ItemDisplay/VBoxContainer/Body/Display/SubViewport") +description_label = NodePath("ItemDescription/VBoxContainer/Body/MarginContainer/Label") +action_menu = NodePath("ItemDescription/VBoxContainer/Body/MarginContainer/Box") -[node name="PlayerInfo" type="VBoxContainer" parent="Contents/ItemDetails"] +[node name="PlayerDetails" parent="MarginContainer/Contents/Details" instance=ExtResource("8_g71ie")] layout_mode = 2 size_flags_horizontal = 3 -[node name="TextureRect" type="TextureRect" parent="Contents/ItemDetails/PlayerInfo"] +[node name="Body" parent="MarginContainer/Contents/Details/PlayerDetails/VBoxContainer" index="1"] +clip_contents = true + +[node name="PlayerInfo" type="VBoxContainer" parent="MarginContainer/Contents/Details/PlayerDetails/VBoxContainer/Body" index="0"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="TextureRect" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/VBoxContainer/Body/PlayerInfo"] layout_mode = 2 size_flags_horizontal = 4 texture = SubResource("PlaceholderTexture2D_as33y") -[node name="TextureRect2" type="TextureRect" parent="Contents/ItemDetails/PlayerInfo"] +[node name="TextureRect2" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/VBoxContainer/Body/PlayerInfo"] layout_mode = 2 size_flags_horizontal = 4 texture = SubResource("PlaceholderTexture2D_tg4gd") -[node name="TextureRect3" type="TextureRect" parent="Contents/ItemDetails/PlayerInfo"] +[node name="TextureRect3" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/VBoxContainer/Body/PlayerInfo"] layout_mode = 2 size_flags_horizontal = 4 texture = SubResource("PlaceholderTexture2D_usnyx") -[node name="Display" type="VBoxContainer" parent="Contents/ItemDetails"] +[node name="ItemDisplay" parent="MarginContainer/Contents/Details" instance=ExtResource("8_g71ie")] layout_mode = 2 size_flags_horizontal = 3 +mouse_filter = 1 -[node name="TextureRect" type="TextureRect" parent="Contents/ItemDetails/Display"] -layout_mode = 2 -size_flags_horizontal = 4 -texture = SubResource("PlaceholderTexture2D_sebc8") - -[node name="Description" type="VBoxContainer" parent="Contents/ItemDetails"] +[node name="Display" type="SubViewportContainer" parent="MarginContainer/Contents/Details/ItemDisplay/VBoxContainer/Body" index="0"] layout_mode = 2 size_flags_horizontal = 3 +stretch = true -[node name="Label" type="Label" parent="Contents/ItemDetails/Description"] +[node name="SubViewport" type="SubViewport" parent="MarginContainer/Contents/Details/ItemDisplay/VBoxContainer/Body/Display"] +own_world_3d = true +transparent_bg = true +handle_input_locally = false +size = Vector2i(374, 464) +render_target_update_mode = 4 + +[node name="Camera3D" type="Camera3D" parent="MarginContainer/Contents/Details/ItemDisplay/VBoxContainer/Body/Display/SubViewport"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2) + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="MarginContainer/Contents/Details/ItemDisplay/VBoxContainer/Body/Display/SubViewport"] +transform = Transform3D(0.71887, 0.431921, -0.544674, -0.0668683, 0.822874, 0.564277, 0.691921, -0.36922, 0.620421, 0, 0, 0) + +[node name="ItemDescription" parent="MarginContainer/Contents/Details" instance=ExtResource("8_g71ie")] layout_mode = 2 -text = "a description" +size_flags_horizontal = 3 +focus_mode = 2 -[connection signal="item_selected" from="Contents/InventoryUI" to="Contents/ItemDetails" method="_on_updated"] +[node name="VBoxContainer" parent="MarginContainer/Contents/Details/ItemDescription" index="0"] +mouse_filter = 2 + +[node name="Header" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer" index="0"] +mouse_filter = 2 + +[node name="TitleContainer" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Header" index="0"] +mouse_filter = 2 + +[node name="Body" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer" index="1"] +mouse_filter = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body" index="0"] +layout_mode = 2 +mouse_filter = 2 + +[node name="Label" type="Label" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer"] +layout_mode = 2 +size_flags_vertical = 1 +autowrap_mode = 3 + +[node name="Box" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer" instance=ExtResource("8_g71ie")] +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 8 +focus_mode = 2 + +[node name="VBoxContainer" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box" index="0"] +mouse_filter = 2 + +[node name="Header" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer" index="0"] +mouse_filter = 2 + +[node name="TitleContainer" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Header" index="0"] +mouse_filter = 2 + +[node name="Body" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer" index="1"] +mouse_filter = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Body" index="0"] +layout_mode = 2 +mouse_filter = 2 + +[node name="UseButton" type="Button" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Body/VBoxContainer"] +layout_mode = 2 +focus_neighbor_left = NodePath(".") +focus_neighbor_top = NodePath(".") +focus_neighbor_right = NodePath(".") +focus_neighbor_bottom = NodePath("../CombineButton") +focus_next = NodePath("../CombineButton") +focus_previous = NodePath(".") +mouse_filter = 1 +mouse_default_cursor_shape = 2 +text = "USE" +alignment = 0 +script = ExtResource("10_p7iul") +metadata/_custom_type_script = "uid://c4gfdpuc14mpq" + +[node name="CombineButton" type="Button" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Body/VBoxContainer"] +layout_mode = 2 +focus_neighbor_left = NodePath(".") +focus_neighbor_top = NodePath("../UseButton") +focus_neighbor_right = NodePath(".") +focus_neighbor_bottom = NodePath("../InspectButton") +focus_next = NodePath("../InspectButton") +focus_previous = NodePath("../UseButton") +mouse_filter = 1 +text = "COMBINE" +alignment = 0 +script = ExtResource("10_p7iul") +metadata/_custom_type_script = "uid://c4gfdpuc14mpq" + +[node name="InspectButton" type="Button" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Body/VBoxContainer"] +layout_mode = 2 +focus_neighbor_left = NodePath(".") +focus_neighbor_top = NodePath("../CombineButton") +focus_neighbor_right = NodePath(".") +focus_neighbor_bottom = NodePath(".") +focus_next = NodePath(".") +focus_previous = NodePath("../CombineButton") +mouse_filter = 1 +text = "INSPECT" +alignment = 0 +script = ExtResource("10_p7iul") +metadata/_custom_type_script = "uid://c4gfdpuc14mpq" + +[connection signal="item_focused" from="MarginContainer/Contents/MarginContainer/InventoryList" to="MarginContainer/Contents/Details" method="_on_updated"] +[connection signal="item_selected" from="MarginContainer/Contents/MarginContainer/InventoryList" to="MarginContainer/Contents/Details" method="_on_selected"] +[connection signal="hidden" from="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box" to="." method="grab_focus"] +[connection signal="visibility_changed" from="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box" to="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Body/VBoxContainer/UseButton" method="grab_focus"] +[connection signal="pressed" from="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Body/VBoxContainer/UseButton" to="MarginContainer/Contents/Details" method="use"] +[connection signal="pressed" from="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Body/VBoxContainer/CombineButton" to="MarginContainer/Contents/Details" method="combine"] +[connection signal="pressed" from="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box/VBoxContainer/Body/VBoxContainer/InspectButton" to="MarginContainer/Contents/Details" method="inspect"] + +[editable path="MarginContainer/Contents/Details/PlayerDetails"] +[editable path="MarginContainer/Contents/Details/ItemDisplay"] +[editable path="MarginContainer/Contents/Details/ItemDescription"] +[editable path="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer/Box"] diff --git a/godot/scenes/inventory_item.tscn b/godot/scenes/inventory_item.tscn index eb105a3..b6d97f8 100644 --- a/godot/scenes/inventory_item.tscn +++ b/godot/scenes/inventory_item.tscn @@ -1,27 +1,23 @@ -[gd_scene load_steps=3 format=3 uid="uid://gn8k2ir47n1m"] +[gd_scene load_steps=4 format=3 uid="uid://gn8k2ir47n1m"] [ext_resource type="Script" uid="uid://dt67n4jti376d" path="res://src/item_ui.gd" id="1_letey"] +[ext_resource type="PackedScene" uid="uid://cidwsnulug6fl" path="res://scenes/box_ui.tscn" id="1_y87vu"] +[ext_resource type="Theme" uid="uid://bb6tvyqikcf3r" path="res://scenes/box_ui.tres" id="3_y87vu"] -[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_u4rwp"] -size = Vector2(128, 128) - -[node name="Item" type="BoxContainer" node_paths=PackedStringArray("name_label", "icon_texture")] -offset_right = 128.0 -offset_bottom = 155.0 -size_flags_horizontal = 3 -size_flags_vertical = 3 -alignment = 1 +[node name="Item" node_paths=PackedStringArray("name_label", "icon_texture") instance=ExtResource("1_y87vu")] script = ExtResource("1_letey") -name_label = NodePath("VBoxContainer/Label") -icon_texture = NodePath("VBoxContainer/Icon") +name_label = NodePath("VBoxContainer/Header/TitleContainer/Label") +icon_texture = NodePath("VBoxContainer/Body/TextureRect") -[node name="VBoxContainer" type="VBoxContainer" parent="."] +[node name="Label" type="Label" parent="VBoxContainer/Header/TitleContainer" index="0"] layout_mode = 2 +theme = ExtResource("3_y87vu") +theme_type_variation = &"BoxHeaderLabel" +text = "pistol" +vertical_alignment = 1 +uppercase = true -[node name="Label" type="Label" parent="VBoxContainer"] +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/Body" index="0"] layout_mode = 2 -text = "Empty" - -[node name="Icon" type="TextureRect" parent="VBoxContainer"] -layout_mode = 2 -texture = SubResource("PlaceholderTexture2D_u4rwp") +expand_mode = 3 +stretch_mode = 5 diff --git a/godot/scenes/pistol_preview.tscn b/godot/scenes/pistol_preview.tscn new file mode 100644 index 0000000..9722d30 --- /dev/null +++ b/godot/scenes/pistol_preview.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://dfljhd4e3l6j2"] + +[ext_resource type="PackedScene" uid="uid://5a023hrws3gx" path="res://assets/Glock 17 Gen 4/Main.glb" id="1_h1roh"] + +[node name="Main" instance=ExtResource("1_h1roh")] +transform = Transform3D(5.96244e-09, 0.866026, -0.5, -1.03272e-08, 0.5, 0.866026, 1, -8.28682e-16, 1.19249e-08, 0, 0, 0) diff --git a/godot/src/cancel_button.gd b/godot/src/cancel_button.gd new file mode 100644 index 0000000..1811b1d --- /dev/null +++ b/godot/src/cancel_button.gd @@ -0,0 +1,9 @@ +class_name CancelButton extends Button + +@export var cancel_action: StringName = &"ui_cancel" + +func _gui_input(event: InputEvent) -> void: + if event.is_action_pressed(cancel_action): + accept_event() + release_focus() + KCUtils.notify(get_parent(), NOTIFICATION_FOCUS_EXIT, true) diff --git a/godot/src/cancel_button.gd.uid b/godot/src/cancel_button.gd.uid new file mode 100644 index 0000000..60e2f7c --- /dev/null +++ b/godot/src/cancel_button.gd.uid @@ -0,0 +1 @@ +uid://c4gfdpuc14mpq diff --git a/godot/src/equipment.gd b/godot/src/equipment.gd index f9b6ae1..0ed6585 100644 --- a/godot/src/equipment.gd +++ b/godot/src/equipment.gd @@ -8,56 +8,83 @@ signal equipped_secondary(equipment: EquippableItem) @export var _primary: EquippableItem var primary: Option: - get: return Option.from(_primary) - set(value): set_primary(value) + get: return Option.from(_primary) + set(value): set_primary(value) func _unequip_primary(): - if _primary != null: - var previous = _primary - _primary = null - unequipped_primary.emit(previous) + if _primary != null: + var previous = _primary + _primary = null + unequipped_primary.emit(previous) func _equip_primary(item: EquippableItem): - if _primary != null: - _unequip_primary() - - if item != null: - _primary = item - equipped_primary.emit(item) + if _primary != null: + _unequip_primary() + + if item != null: + _primary = item + equipped_primary.emit(item) func set_primary(item: Option): - _equip_primary(item.unwrap()) + match item: + var x when x.is_some(): + _equip_primary(x.unwrap()) + _: _unequip_primary() @export var _secondary: EquippableItem var secondary: Option: - get: return Option.from(_secondary) - set(value): set_secondary(value) + get: return Option.from(_secondary) + set(value): set_secondary(value) func _unequip_secondary(): - if _secondary != null: - var previous = _secondary - _secondary = null - unequipped_secondary.emit(previous) + if _secondary != null: + var previous = _secondary + _secondary = null + unequipped_secondary.emit(previous) func _equip_secondary(item: EquippableItem): - if _secondary != null: - _unequip_secondary() - - if item != null: - _secondary = item - equipped_secondary.emit(item) + if _secondary != null: + _unequip_secondary() + + if item != null: + _secondary = item + equipped_secondary.emit(item) func set_secondary(item: Option): - _equip_secondary(item.unwrap()) + match item: + var x when x.is_some(): + _equip_secondary(x.unwrap()) + _: _unequip_secondary() func _init(): - call_deferred("_ready") + call_deferred("_ready") func _ready(): - if _primary != null: - _equip_primary(_primary) + if _primary != null: + _equip_primary(_primary) - if _secondary != null: - _equip_secondary(_secondary) + if _secondary != null: + _equip_secondary(_secondary) +func equip(item: EquippableItem): + match item.type: + EquippableItem.EquipmentType.PRIMARY: primary = Option.some(item) + EquippableItem.EquipmentType.SECONDARY: secondary = Option.some(item) + +func unequip(equip_type: EquippableItem.EquipmentType): + match equip_type: + EquippableItem.EquipmentType.PRIMARY: primary = Option.none + EquippableItem.EquipmentType.SECONDARY:secondary = Option.none + +func unequip_item(item: EquippableItem): + equipped_to(item).inspect(unequip) + +func is_equipped(item: EquippableItem) -> bool: + return equipped_to(item).is_some() + +func equipped_to(item: EquippableItem) -> Option: + match item.type: + EquippableItem.EquipmentType.PRIMARY when item == _primary: return Option.some(EquippableItem.EquipmentType.PRIMARY) + EquippableItem.EquipmentType.SECONDARY when item == _secondary: return Option.some(EquippableItem.EquipmentType.SECONDARY) + return Option.none diff --git a/godot/src/equippable_item.gd b/godot/src/equippable_item.gd index ab52ba0..d60faa4 100644 --- a/godot/src/equippable_item.gd +++ b/godot/src/equippable_item.gd @@ -1,9 +1,14 @@ class_name EquippableItem extends Item -@export var scene: PackedScene +enum EquipmentType { + PRIMARY, + SECONDARY +} -func create() -> Option: - if scene != null and scene.can_instantiate(): - return Option.some(scene.instantiate()) - else: - return Option.none +@export var type: EquipmentType = EquipmentType.PRIMARY + +func is_primary() -> bool: + return type == EquipmentType.PRIMARY + +func is_secondary() -> bool: + return type == EquipmentType.SECONDARY diff --git a/godot/src/index_carousel.gd b/godot/src/index_carousel.gd index 0285807..c36fe5d 100644 --- a/godot/src/index_carousel.gd +++ b/godot/src/index_carousel.gd @@ -15,4 +15,4 @@ 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) + index_changed.emit(next_index) diff --git a/godot/src/inventory_ui.gd b/godot/src/inventory_ui.gd index 0957462..90e9f68 100644 --- a/godot/src/inventory_ui.gd +++ b/godot/src/inventory_ui.gd @@ -1,6 +1,7 @@ class_name InventoryUI extends Control -signal item_selected(item: Option) +signal item_focused(item: Option) +signal item_selected(item: Item) @export var inventory: Inventory @export var item_scene: PackedScene @@ -10,16 +11,14 @@ func _ready() -> void: inventory.updated.connect(_build_carousel) carousel.index_changed.connect(_on_item_changed) -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 +func _items() -> Iterator: + return inventory.iter().map(func(x): return x.value.item) - if not found: - item_selected.emit(Option.none) +func _on_item_changed(index: int) -> void: + match _items().nth(index): + var x when x.is_some(): + item_focused.emit(Option.from(x.unwrap())) + _: item_focused.emit(Option.none) func _build_carousel() -> void: KCUtils.remove_children(carousel) @@ -34,16 +33,6 @@ func _build_carousel() -> void: 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() @@ -56,6 +45,10 @@ func _gui_input(event: InputEvent) -> void: move_right() elif event.is_action_pressed(PlayerInput.UIAction.Left): move_left() + elif event.is_action_pressed(PlayerInput.UIAction.Accept): + var selected = _items().nth(carousel.current_index) + if selected.is_some(): + item_selected.emit(selected.unwrap()) func move_by(delta: int): var next_index = carousel.get_carousel_index() + delta diff --git a/godot/src/item.gd b/godot/src/item.gd index 7ad45f3..68da390 100644 --- a/godot/src/item.gd +++ b/godot/src/item.gd @@ -4,6 +4,31 @@ class_name Item extends Resource @export var description: String @export var max_stack: int @export var icon: Texture2D +@export var scene: PackedScene +@export var preview_scene: PackedScene + +func _to_string() -> String: + var icon_path = _resource_path_name(icon) + var scene_path = _resource_path_name(scene) + var preview_scene_path = _resource_path_name(preview_scene) + + return 'Item { name = "%s", description = "%s", max_stack = %s, icon = "%s", scene = "%s", preview_scene = "%s" }' % [name, description.substr(0, 24), max_stack, icon_path, scene_path, preview_scene_path] + +func _resource_path_name(res: Resource) -> String: + return res.resource_path if res != null else "None" + +func _create(_scene: PackedScene) -> Option: + if _scene != null and _scene.can_instantiate(): + return Option.some(_scene.instantiate()) + else: + return Option.none + +func create() -> Option: + return _create(scene) + +func create_preview() -> Option: + return _create(preview_scene) + func combine(_with: Item) -> bool: return false diff --git a/godot/src/item_details_ui.gd b/godot/src/item_details_ui.gd index 3d99f70..fb431d2 100644 --- a/godot/src/item_details_ui.gd +++ b/godot/src/item_details_ui.gd @@ -1,24 +1,67 @@ class_name ItemDetailsUI extends HBoxContainer @export var equipment: Equipment -@export var icon_image: TextureRect +@export var viewport: SubViewport @export var description_label: Label +@export var action_menu: Control -var _default_icon: Texture2D +var current_item: Option = Option.none + +var _displayed_item: Node3D var _default_description: String func _ready() -> void: - _default_icon = icon_image.texture + action_menu.hide() _default_description = description_label.text func _set_default(): - icon_image.texture = _default_icon + if _displayed_item != null: + viewport.remove_child(_displayed_item) + _displayed_item.queue_free() description_label.text = _default_description func _on_updated(item: Option): + current_item = item if item.is_some(): var _item: Item = item.unwrap() - icon_image.texture = _item.icon + match _item.create_preview(): + var x when x.is_some(): + _displayed_item = x.unwrap() + viewport.add_child(_displayed_item) + _: _set_default() description_label.text = _item.description else: _set_default() + +func _on_selected(_item: Item): + action_menu.show() + +func _notification(what: int) -> void: + if what == NOTIFICATION_FOCUS_EXIT: + action_menu.hide() + +func _is_equip(item: Item) -> bool: + return is_instance_of(item, EquippableItem) + +func _already_equipped(item: Item) -> bool: + return equipment.is_equipped(item) + +func use(): + if current_item.is_some(): + var item = current_item.unwrap() + if _is_equip(item): + if _already_equipped(item): + equipment.unequip_item(item) + else: + equipment.equip(item) + else: + item.use() + action_menu.hide() + +func combine(): + current_item.inspect(func(x): x.combine()) + action_menu.hide() + +func inspect(): + current_item.inspect(func(x): x.inspect()) + action_menu.hide() diff --git a/godot/src/raycast.gd b/godot/src/raycast.gd index 6151ef9..d201906 100644 --- a/godot/src/raycast.gd +++ b/godot/src/raycast.gd @@ -1,36 +1,36 @@ class_name Raycast extends Node3D class RaycastHit extends RefCounted: - var collider: CollisionObject3D - var shape: int - var normal: Vector3 - var position: Vector3 - var face_index: int + var collider: CollisionObject3D + var shape: int + var normal: Vector3 + var position: Vector3 + var face_index: int - @warning_ignore("shadowed_variable") - func _init(collider: CollisionObject3D, shape: int, normal: Vector3, position: Vector3, index: int) -> void: - self.collider = collider - self.shape = shape - self.normal = normal - self.position = position - self.face_index = index + @warning_ignore("shadowed_variable") + func _init(collider: CollisionObject3D, shape: int, normal: Vector3, position: Vector3, index: int) -> void: + self.collider = collider + self.shape = shape + self.normal = normal + self.position = position + self.face_index = index - func get_shape_owner() -> Option: - if typeof(self.collider) == TYPE_NIL or self.shape == 0: return Option.none - var owner_id = self.collider.shape_find_owner(shape) - return Option.some(self.collider.shape_owner_get_owner(owner_id)) + func get_shape_owner() -> Option: + if typeof(self.collider) == TYPE_NIL or self.shape == 0: return Option.none + var owner_id = self.collider.shape_find_owner(shape) + return Option.some(self.collider.shape_owner_get_owner(owner_id)) - static func from_dict(hit: Dictionary) -> Option: - if hit.is_empty(): return Option.none - return Option.some( - RaycastHit.new( - hit['collider'], - hit['shape'], - hit['normal'], - hit['position'], - hit['face_index'] - ) - ) + static func from_dict(hit: Dictionary) -> Option: + if hit.is_empty(): return Option.none + return Option.some( + RaycastHit.new( + hit['collider'], + hit['shape'], + hit['normal'], + hit['position'], + hit['face_index'] + ) + ) @export var enabled: bool = true @export var exclude_parent: bool = true @@ -53,38 +53,40 @@ var _exclusions: Array @export var width: int = 2 var forward: Vector3: - get: return -global_basis.z + get: return -global_basis.z var hit: Option = Option.none func _ready() -> void: - set_physics_process(enabled) - _exclusions = exclusions.map(func(x): return x.get_rid()) - if exclude_parent: - match _find_parent_collider(): - var x when x.is_some(): - _exclusions.append(x.unwrap().get_rid()) + set_physics_process(enabled) + _exclusions = exclusions.map(func(x): return x.get_rid()) + if exclude_parent: + match _find_parent_collider(): + var x when x.is_some(): + _exclusions.append(x.unwrap().get_rid()) func _physics_process(_delta: float) -> void: - force_raycast_update() + force_raycast_update() -func _find_parent_collider(node: Node3D = self) -> Option: - if typeof(node) == TYPE_NIL: return Option.none - if is_instance_of(node, CollisionObject3D): - return Option.some(node) - else: - return _find_parent_collider(node.get_parent()) +func _find_parent_collider(node: Node = self) -> Option: + if typeof(node) == TYPE_NIL: return Option.none + if is_instance_of(node, SubViewport): + return Option.none + if is_instance_of(node, CollisionObject3D): + return Option.some(node) + else: + return _find_parent_collider(node.get_parent()) func force_raycast_update() -> void: - var to = forward * length + global_position - var query = PhysicsRayQueryParameters3D.create(global_position, to, collision_mask, _exclusions) - DebugDraw3D.draw_ray(global_position, forward, length, custom_color, .25) - query.hit_from_inside = hit_from_inside - query.hit_back_faces = hit_backfaces - query.collide_with_areas = areas - query.collide_with_bodies = bodies - var raycast_hit = get_world_3d().direct_space_state.intersect_ray(query) - hit = RaycastHit.from_dict(raycast_hit) + var to = forward * length + global_position + var query = PhysicsRayQueryParameters3D.create(global_position, to, collision_mask, _exclusions) + DebugDraw3D.draw_ray(global_position, forward, length, custom_color, .25) + query.hit_from_inside = hit_from_inside + query.hit_back_faces = hit_backfaces + query.collide_with_areas = areas + query.collide_with_bodies = bodies + var raycast_hit = get_world_3d().direct_space_state.intersect_ray(query) + hit = RaycastHit.from_dict(raycast_hit) func is_colliding() -> bool: - return hit.is_some() + return hit.is_some() diff --git a/godot/src/window_ui.gd b/godot/src/window_ui.gd new file mode 100644 index 0000000..e69de29 diff --git a/godot/src/window_ui.gd.uid b/godot/src/window_ui.gd.uid new file mode 100644 index 0000000..b819dd3 --- /dev/null +++ b/godot/src/window_ui.gd.uid @@ -0,0 +1 @@ +uid://bxd483uvo31jf