organize scripts; wip ui overhaul

This commit is contained in:
Rowan 2025-07-04 07:29:07 -04:00
parent 89bcba0ff2
commit ed1a2ca7e3
97 changed files with 717 additions and 397 deletions

View file

@ -2,3 +2,11 @@ root = true
[*]
charset = utf-8
[*.gd]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

View file

@ -19,7 +19,7 @@ func _init(start: int, end: int, inclusive: bool = false) -> void:
self.inclusive = inclusive
static func from_sized(value: Variant) -> Result:
match KCUtils.get_size(value):
match K.get_size(value):
var len when len.is_ok():
return Result.ok(IntRange.new(0, len.unwrap()))
var e: return e

View file

@ -1,4 +1,4 @@
class_name KCUtils
class_name K
static func remove_children(node: Node, delete: bool = true):
for i in range(node.get_child_count() - 1, -1, -1):
@ -15,6 +15,10 @@ static func get_class_name(value: Object) -> String:
_: return script.get_instance_base_type()
_: return value.get_class()
static func is_array_like(value: Variant) -> bool:
var type = typeof(value)
return type >= 28 and type <= 38 or type == TYPE_STRING or type == TYPE_STRING_NAME
static func is_string_like(value: Variant) -> bool:
match typeof(value):
TYPE_STRING: return true
@ -79,3 +83,9 @@ static func get_size(value: Variant) -> Result:
static func len(value: Variant) -> int:
return get_size(value).unwrap()
static func iter(value: Variant) -> Iterator:
if is_array_like(value): return ListIterator.from_array(value)
if typeof(value) == TYPE_OBJECT: return VariantIterator.new(value)
if typeof(value) == TYPE_DICTIONARY: return DictionaryIterator.new(value)
return SingletonIterator.new(value)

View file

@ -0,0 +1,7 @@
[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://csnm0disev20f"]
[ext_resource type="Texture2D" uid="uid://d3ergv453flsw" path="res://assets/sprites.png" id="1_nybgi"]
[resource]
atlas = ExtResource("1_nybgi")
region = Rect2(72, 272, 48, 32)

View file

@ -4,5 +4,4 @@
[resource]
atlas = ExtResource("1_gm5ao")
region = Rect2(256, 128, 64, 64)
margin = Rect2(-10, -12, -20, -20)
region = Rect2(275, 142, 25, 39)

View file

@ -4,5 +4,4 @@
[resource]
atlas = ExtResource("1_y5otb")
region = Rect2(192, 256, 64, 64)
margin = Rect2(0, -10, 0, -12)
region = Rect2(193, 272, 62, 40)

View file

@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="Item" load_steps=3 format=3 uid="uid://ud2qc6eul8lt"]
[ext_resource type="Script" uid="uid://d1imxjix6ljul" path="res://src/attributes/attribute.gd" id="1_gkq1r"]
[ext_resource type="Script" uid="uid://bqprls343ue6e" path="res://src/items/item.gd" id="2_4ckx0"]
[resource]
script = ExtResource("2_4ckx0")
name = "9mm Ammo"
description = ""
max_stack = 99
attributes = Array[ExtResource("1_gkq1r")]([])
metadata/_custom_type_script = "uid://bqprls343ue6e"

View file

@ -1,12 +1,14 @@
[gd_resource type="Resource" script_class="Item" load_steps=3 format=3 uid="uid://cqfnwpmo4fyv4"]
[gd_resource type="Resource" script_class="Item" load_steps=4 format=3 uid="uid://cqfnwpmo4fyv4"]
[ext_resource type="Script" uid="uid://bqprls343ue6e" path="res://src/item.gd" id="1_7ur50"]
[ext_resource type="Script" uid="uid://d1imxjix6ljul" path="res://src/attributes/attribute.gd" id="1_nv3up"]
[ext_resource type="Texture2D" uid="uid://dngw0c0dc6u7x" path="res://assets/icons/key_icon.tres" id="1_ykwyx"]
[ext_resource type="Script" uid="uid://bqprls343ue6e" path="res://src/items/item.gd" id="3_4rdgs"]
[resource]
script = ExtResource("1_7ur50")
script = ExtResource("3_4rdgs")
name = "Debug Key"
description = "An unusual key card."
max_stack = 1
icon = ExtResource("1_ykwyx")
attributes = Array[ExtResource("1_nv3up")]([])
metadata/_custom_type_script = "uid://bqprls343ue6e"

View file

@ -1,16 +1,32 @@
[gd_resource type="Resource" script_class="EquippableItem" load_steps=5 format=3 uid="uid://crgwey6ibaf2h"]
[gd_resource type="Resource" script_class="EquippableItem" load_steps=10 format=3 uid="uid://crgwey6ibaf2h"]
[ext_resource type="PackedScene" uid="uid://isqkayrtr7t8" path="res://scenes/pistol.tscn" id="1_6ttue"]
[ext_resource type="Script" uid="uid://d1imxjix6ljul" path="res://src/attributes/attribute.gd" id="1_7dru5"]
[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"]
[ext_resource type="Script" uid="uid://c710qg683rqbc" path="res://src/items/equippable_item.gd" id="1_lqglu"]
[ext_resource type="Script" uid="uid://bbigpwchxitb5" path="res://src/attributes/ammo_attribute.gd" id="2_j7ges"]
[ext_resource type="Script" uid="uid://c1y3loxtmkeg3" path="res://src/attributes/equippable_attribute.gd" id="3_fcfbw"]
[sub_resource type="Resource" id="Resource_6opap"]
script = ExtResource("2_j7ges")
max_capacity = 10
metadata/_custom_type_script = "uid://bbigpwchxitb5"
[sub_resource type="Resource" id="Resource_moakd"]
script = ExtResource("3_fcfbw")
type = 0
metadata/_custom_type_script = "uid://c1y3loxtmkeg3"
[resource]
script = ExtResource("1_lqglu")
type = 0
ammo_capacity = 0
name = "Pistol"
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")
attributes = Array[ExtResource("1_7dru5")]([SubResource("Resource_6opap"), SubResource("Resource_moakd")])
metadata/_custom_type_script = "uid://c710qg683rqbc"

View file

@ -1,7 +1,7 @@
[gd_resource type="Resource" script_class="Inventory" load_steps=5 format=3 uid="uid://bllq6ri54q3ne"]
[ext_resource type="Script" uid="uid://1rjq1ttxq4nd" path="res://src/item_instance.gd" id="1_uptie"]
[ext_resource type="Script" uid="uid://dh4ytedxidq0x" path="res://src/inventory.gd" id="2_1njko"]
[ext_resource type="Script" uid="uid://1rjq1ttxq4nd" path="res://src/items/item_instance.gd" id="1_uptie"]
[ext_resource type="Script" uid="uid://dh4ytedxidq0x" path="res://src/items/inventory.gd" id="2_1njko"]
[ext_resource type="Resource" uid="uid://cqfnwpmo4fyv4" path="res://resources/items/key.tres" id="2_85a8j"]
[sub_resource type="Resource" id="Resource_hfe8y"]

View file

@ -1,23 +1,9 @@
[gd_resource type="Theme" load_steps=6 format=3 uid="uid://bb6tvyqikcf3r"]
[gd_resource type="Theme" load_steps=3 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"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nj55m"]
bg_color = Color(0.6, 0.6, 0.6, 0)
border_width_left = 1
border_width_top = 1
@ -26,20 +12,8 @@ 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)
BoxTitle/base_type = &"PanelContainer"
BoxTitle/styles/panel = SubResource("StyleBoxFlat_odwru")
BoxTitleText/base_type = &"Label"
BoxTitleText/colors/font_color = Color(0.0745098, 0.0745098, 0.0745098, 1)
PanelContainer/styles/panel = SubResource("StyleBoxFlat_nj55m")

View file

@ -1,27 +1,35 @@
[gd_scene load_steps=2 format=3 uid="uid://cidwsnulug6fl"]
[gd_scene load_steps=3 format=3 uid="uid://cidwsnulug6fl"]
[ext_resource type="Theme" uid="uid://bb6tvyqikcf3r" path="res://scenes/box_ui.tres" id="1_e1aew"]
[ext_resource type="Script" uid="uid://bnumwlio6adb8" path="res://src/ui/box.gd" id="2_jp73w"]
[node name="Box" type="PanelContainer"]
[node name="Box" type="PanelContainer" node_paths=PackedStringArray("title_label", "body_container")]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_e1aew")
script = ExtResource("2_jp73w")
title_label = NodePath("Container/Header/TitleContainer/Label")
body_container = NodePath("Container/Content")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
[node name="Container" type="VBoxContainer" parent="."]
layout_mode = 2
[node name="Header" type="PanelContainer" parent="VBoxContainer"]
[node name="Header" type="PanelContainer" parent="Container"]
layout_mode = 2
theme = ExtResource("1_e1aew")
theme_type_variation = &"BoxHeader"
theme_type_variation = &"BoxTitle"
[node name="TitleContainer" type="MarginContainer" parent="VBoxContainer/Header"]
[node name="TitleContainer" type="MarginContainer" parent="Container/Header"]
layout_mode = 2
[node name="Body" type="PanelContainer" parent="VBoxContainer"]
[node name="Label" type="Label" parent="Container/Header/TitleContainer"]
layout_mode = 2
theme_type_variation = &"BoxTitleText"
[node name="Content" type="PanelContainer" parent="Container"]
layout_mode = 2
size_flags_vertical = 3
theme = ExtResource("1_e1aew")

View file

@ -0,0 +1,9 @@
[gd_scene format=3 uid="uid://bgn32l1f007w2"]
[node name="ContextMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

View file

@ -1,15 +1,13 @@
[gd_scene load_steps=14 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="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="Script" uid="uid://b7j7weoa8tikm" path="res://src/ui/inventory_screen.gd" id="2_g71ie"]
[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="Script" uid="uid://c8m7eq6a3tpgu" path="res://src/ui/item_detail_ui.gd" id="4_yyk2a"]
[ext_resource type="Script" uid="uid://bpwbaanf6w65h" path="res://src/ui/index_carousel.gd" id="5_uae8j"]
[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)
@ -20,20 +18,25 @@ size = Vector2(128, 128)
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_usnyx"]
size = Vector2(128, 64)
[node name="Inventory" type="Control"]
[node name="Inventory" type="Control" node_paths=PackedStringArray("carousel", "item_details")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 2.0
offset_right = 2.0
grow_horizontal = 2
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"
script = ExtResource("2_g71ie")
inventory = ExtResource("2_as33y")
equipment = ExtResource("7_s887n")
inventory_item_scene = ExtResource("3_tg4gd")
carousel = NodePath("MarginContainer/Contents/MarginContainer/Carousel")
item_details = NodePath("MarginContainer/Contents/Details")
[node name="ColorRect" type="ColorRect" parent="."]
layout_mode = 1
@ -59,25 +62,9 @@ alignment = 1
[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")
inventory = ExtResource("2_as33y")
item_scene = ExtResource("3_tg4gd")
carousel = NodePath("Carousel")
metadata/_custom_type_script = "uid://qvoqvonnxwfc"
[node name="Carousel" type="Container" parent="MarginContainer/Contents/MarginContainer/InventoryList"]
[node name="Carousel" type="Container" parent="MarginContainer/Contents/MarginContainer"]
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)
layout_mode = 2
script = ExtResource("5_uae8j")
with_drag = true
with_clamp = true
@ -85,39 +72,39 @@ item_size = Vector2(150, 100)
item_seperation = 64
snap_behavior = 2
paging_requirement = 100
manual_carousel_duration = 0.2
metadata/_custom_type_script = "uid://bpwbaanf6w65h"
[node name="Details" type="HBoxContainer" parent="MarginContainer/Contents" node_paths=PackedStringArray("viewport", "description_label", "action_menu")]
[node name="Details" type="HBoxContainer" parent="MarginContainer/Contents" node_paths=PackedStringArray("viewport", "description_label")]
layout_mode = 2
size_flags_vertical = 3
script = ExtResource("6_s887n")
equipment = ExtResource("7_s887n")
viewport = NodePath("ItemDisplay/VBoxContainer/Body/Display/SubViewport")
description_label = NodePath("ItemDescription/VBoxContainer/Body/MarginContainer/Label")
action_menu = NodePath("ItemDescription/VBoxContainer/Body/MarginContainer/Box")
script = ExtResource("4_yyk2a")
viewport = NodePath("ItemDisplay/Container/Content/SubViewport")
description_label = NodePath("ItemDescription/Container/Header/TitleContainer/Label")
[node name="PlayerDetails" parent="MarginContainer/Contents/Details" instance=ExtResource("8_g71ie")]
layout_mode = 2
size_flags_horizontal = 3
[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"]
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Contents/Details/PlayerDetails/Container/Content" index="0"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/margin_left = 24
theme_override_constants/margin_right = 24
[node name="TextureRect" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/VBoxContainer/Body/PlayerInfo"]
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Contents/Details/PlayerDetails/Container/Content/MarginContainer"]
layout_mode = 2
alignment = 1
[node name="TextureRect" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/Container/Content/MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 4
texture = SubResource("PlaceholderTexture2D_as33y")
[node name="TextureRect2" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/VBoxContainer/Body/PlayerInfo"]
[node name="TextureRect2" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/Container/Content/MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 4
texture = SubResource("PlaceholderTexture2D_tg4gd")
[node name="TextureRect3" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/VBoxContainer/Body/PlayerInfo"]
[node name="TextureRect3" type="TextureRect" parent="MarginContainer/Contents/Details/PlayerDetails/Container/Content/MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 4
texture = SubResource("PlaceholderTexture2D_usnyx")
@ -127,124 +114,44 @@ layout_mode = 2
size_flags_horizontal = 3
mouse_filter = 1
[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="Camera3D" type="Camera3D" parent="MarginContainer/Contents/Details/ItemDisplay/Container/Content" index="0"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2)
[node name="SubViewport" type="SubViewport" parent="MarginContainer/Contents/Details/ItemDisplay/VBoxContainer/Body/Display"]
[node name="SubViewport" type="SubViewport" parent="MarginContainer/Contents/Details/ItemDisplay/Container/Content" index="1"]
own_world_3d = true
transparent_bg = true
handle_input_locally = false
size = Vector2i(374, 464)
size = Vector2i(374, 514)
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="DirectionalLight3D" type="DirectionalLight3D" parent="MarginContainer/Contents/Details/ItemDisplay/Container/Content" index="2"]
transform = Transform3D(0.71887, 0.431921, -0.544675, -0.0668683, 0.822874, 0.564276, 0.691921, -0.36922, 0.620421, 0, 0, 0)
[node name="ItemDescription" parent="MarginContainer/Contents/Details" instance=ExtResource("8_g71ie")]
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 2
[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"]
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Contents/Details/ItemDescription/Container/Content" index="0"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 8
[node name="Label" type="Label" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer"]
[node name="Label" type="Label" parent="MarginContainer/Contents/Details/ItemDescription/Container/Content/MarginContainer"]
layout_mode = 2
size_flags_vertical = 1
size_flags_vertical = 3
autowrap_mode = 3
[node name="Box" parent="MarginContainer/Contents/Details/ItemDescription/VBoxContainer/Body/MarginContainer" instance=ExtResource("8_g71ie")]
[node name="ContextMenu" parent="MarginContainer/Contents/Details/ItemDescription/Container/Content/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"]
[node name="Label" type="Label" parent="MarginContainer/Contents/Details/ItemDescription/Container/Content/MarginContainer/ContextMenu/Container/Content" 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"]
[editable path="MarginContainer/Contents/Details/ItemDescription/Container/Content/MarginContainer/ContextMenu"]

View file

@ -1,23 +1,14 @@
[gd_scene load_steps=4 format=3 uid="uid://gn8k2ir47n1m"]
[gd_scene load_steps=3 format=3 uid="uid://gn8k2ir47n1m"]
[ext_resource type="Script" uid="uid://dt67n4jti376d" path="res://src/item_ui.gd" id="1_letey"]
[ext_resource type="Script" uid="uid://c2yaayl4msnf1" path="res://src/ui/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"]
[node name="Item" node_paths=PackedStringArray("name_label", "icon_texture") instance=ExtResource("1_y87vu")]
[node name="Item" node_paths=PackedStringArray("_title_label", "_icon_texture") instance=ExtResource("1_y87vu")]
script = ExtResource("1_letey")
name_label = NodePath("VBoxContainer/Header/TitleContainer/Label")
icon_texture = NodePath("VBoxContainer/Body/TextureRect")
_title_label = NodePath("Container/Header/TitleContainer/Label")
_icon_texture = NodePath("Container/Content/TextureRect")
[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="TextureRect" type="TextureRect" parent="VBoxContainer/Body" index="0"]
[node name="TextureRect" type="TextureRect" parent="Container/Content" index="0"]
layout_mode = 2
expand_mode = 3
stretch_mode = 5

View file

@ -1,14 +1,16 @@
[gd_scene load_steps=17 format=3 uid="uid://dttyp3682enn7"]
[gd_scene load_steps=19 format=3 uid="uid://dttyp3682enn7"]
[ext_resource type="PackedScene" uid="uid://crbrniwi6kd3p" path="res://scenes/player.tscn" id="1_2q6dc"]
[ext_resource type="Script" uid="uid://csjccrhj5wnx7" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd" id="2_klq6b"]
[ext_resource type="Script" uid="uid://ds8lef4lc6xuj" path="res://src/door.gd" id="2_w8frs"]
[ext_resource type="Script" uid="uid://ds8lef4lc6xuj" path="res://src/world/door.gd" id="2_w8frs"]
[ext_resource type="Script" uid="uid://8umksf8e80fw" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="3_b121j"]
[ext_resource type="Script" uid="uid://dyghf5fq7s72x" path="res://src/interactable.gd" id="3_w8frs"]
[ext_resource type="Script" uid="uid://dyghf5fq7s72x" path="res://src/world/interactable.gd" id="3_w8frs"]
[ext_resource type="Script" uid="uid://bd046eokvcnu2" path="res://addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd" id="4_8c41q"]
[ext_resource type="Script" uid="uid://pdpejp2xor23" path="res://src/persistence.gd" id="4_mx8sn"]
[ext_resource type="Resource" uid="uid://cqfnwpmo4fyv4" path="res://resources/items/key.tres" id="7_8c41q"]
[ext_resource type="Script" uid="uid://35hnuxagjlo2" path="res://src/ui/ui_manager.gd" id="8_8iemx"]
[ext_resource type="PackedScene" uid="uid://cn7tgd4y67wnd" path="res://scenes/inventory.tscn" id="8_b121j"]
[ext_resource type="Script" uid="uid://ct5na682hxc6g" path="res://src/ui/input_listener.gd" id="9_64w2a"]
[ext_resource type="PackedScene" uid="uid://c0cf6jkxasplk" path="res://scenes/enemy.tscn" id="10_olg7q"]
[ext_resource type="PackedScene" uid="uid://iwn3rk6leull" path="res://scenes/pistol_pickup.tscn" id="11_t1rx8"]
@ -89,34 +91,68 @@ shape = SubResource("BoxShape3D_mx8sn")
[node name="Interactable" type="Node3D" parent="Door"]
script = ExtResource("3_w8frs")
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="GameUI" type="CanvasLayer" parent="."]
follow_viewport_enabled = true
[node name="Control" type="Control" parent="CanvasLayer"]
[node name="UIManager" type="Control" parent="GameUI" node_paths=PackedStringArray("inventory_menu", "context_menu")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("8_8iemx")
inventory_menu = NodePath("Inventory")
context_menu = NodePath("Inventory/MarginContainer/Contents/Details/ItemDescription/Container/Content/MarginContainer/ContextMenu")
metadata/_custom_type_script = "uid://35hnuxagjlo2"
[node name="Control" type="Control" parent="GameUI/UIManager"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="Persistence" type="Node" parent="CanvasLayer/Control"]
[node name="Persistence" type="Node" parent="GameUI/UIManager/Control"]
script = ExtResource("4_mx8sn")
[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/Control"]
[node name="HBoxContainer" type="HBoxContainer" parent="GameUI/UIManager/Control"]
layout_mode = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="SaveButton" type="Button" parent="CanvasLayer/Control/HBoxContainer"]
[node name="SaveButton" type="Button" parent="GameUI/UIManager/Control/HBoxContainer"]
layout_mode = 2
text = "Save"
[node name="LoadButton" type="Button" parent="CanvasLayer/Control/HBoxContainer"]
[node name="LoadButton" type="Button" parent="GameUI/UIManager/Control/HBoxContainer"]
layout_mode = 2
text = "Load
"
[node name="Inventory" parent="CanvasLayer" instance=ExtResource("8_b121j")]
[node name="Inventory" parent="GameUI/UIManager" instance=ExtResource("8_b121j")]
visible = false
layout_mode = 1
[node name="InventoryListeners" type="Node" parent="GameUI"]
[node name="OpenInventory" type="Control" parent="GameUI/InventoryListeners"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("9_64w2a")
action = &"open_inventory"
method = 2
metadata/_custom_type_script = "uid://ct5na682hxc6g"
[node name="CloseInventory" type="Control" parent="GameUI/InventoryListeners"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("9_64w2a")
action = &"ui_close_inventory"
metadata/_custom_type_script = "uid://ct5na682hxc6g"
[node name="Enemy" parent="." instance=ExtResource("10_olg7q")]
transform = Transform3D(1.75, 0, 0, 0, 1.75, 0, 0, 0, 1.75, 6, 0, 0)
@ -126,5 +162,12 @@ transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0, 2,
[connection signal="opened" from="Door" to="Door" method="hide"]
[connection signal="interacted" from="Door/Interactable" to="Door" method="_on_interact"]
[connection signal="pressed" from="CanvasLayer/Control/HBoxContainer/SaveButton" to="CanvasLayer/Control/Persistence" method="save" binds= ["save1.sav"]]
[connection signal="pressed" from="CanvasLayer/Control/HBoxContainer/LoadButton" to="CanvasLayer/Control/Persistence" method="load" binds= ["save1.sav"]]
[connection signal="pressed" from="GameUI/UIManager/Control/HBoxContainer/SaveButton" to="GameUI/UIManager/Control/Persistence" method="save" binds= ["save1.sav"]]
[connection signal="pressed" from="GameUI/UIManager/Control/HBoxContainer/LoadButton" to="GameUI/UIManager/Control/Persistence" method="load" binds= ["save1.sav"]]
[connection signal="pressed" from="GameUI/InventoryListeners/OpenInventory" to="GameUI/UIManager" method="open_inventory_menu"]
[editable path="GameUI/UIManager/Inventory"]
[editable path="GameUI/UIManager/Inventory/MarginContainer/Contents/Details/PlayerDetails"]
[editable path="GameUI/UIManager/Inventory/MarginContainer/Contents/Details/ItemDisplay"]
[editable path="GameUI/UIManager/Inventory/MarginContainer/Contents/Details/ItemDescription"]
[editable path="GameUI/UIManager/Inventory/MarginContainer/Contents/Details/ItemDescription/Container/Content/MarginContainer/ContextMenu"]

View file

@ -1,11 +1,11 @@
[gd_scene load_steps=49 format=3 uid="uid://crbrniwi6kd3p"]
[ext_resource type="PackedScene" uid="uid://dpmbimh6m4ari" path="res://scenes/player_mesh.tscn" id="1_3vyb7"]
[ext_resource type="Script" uid="uid://50vv0ta67tgl" path="res://src/player.gd" id="1_qhqgy"]
[ext_resource type="Script" uid="uid://cngjp2wws4ld2" path="res://src/player_input.gd" id="3_dqkch"]
[ext_resource type="Script" uid="uid://c3wlcxy4vnm2i" path="res://src/interactor.gd" id="4_dqkch"]
[ext_resource type="Script" uid="uid://csjl56hf0fnoy" path="res://src/item_container.gd" id="5_qlg0r"]
[ext_resource type="Script" uid="uid://k1ihjmhj7ix" path="res://src/equipment_handler.gd" id="5_smehm"]
[ext_resource type="Script" uid="uid://50vv0ta67tgl" path="res://src/entity/player.gd" id="1_qhqgy"]
[ext_resource type="Script" uid="uid://cngjp2wws4ld2" path="res://src/entity/player_input.gd" id="3_dqkch"]
[ext_resource type="Script" uid="uid://c3wlcxy4vnm2i" path="res://src/world/interactor.gd" id="4_dqkch"]
[ext_resource type="Script" path="res://src/items/item_container.gd" id="5_qlg0r"]
[ext_resource type="Script" uid="uid://k1ihjmhj7ix" path="res://src/entity/equipment_handler.gd" id="5_smehm"]
[ext_resource type="Resource" uid="uid://cxm3s081hnw8l" path="res://resources/player_equipment.tres" id="6_smehm"]
[ext_resource type="Resource" uid="uid://bllq6ri54q3ne" path="res://resources/player_inventory.tres" id="6_tuyoq"]

View file

@ -0,0 +1,5 @@
class_name AmmoAttribute extends Attribute
@export var ammo_type: Item
@export var max_capacity: int

View file

@ -0,0 +1 @@
uid://bbigpwchxitb5

View file

@ -0,0 +1 @@
class_name Attribute extends Resource

View file

@ -0,0 +1 @@
uid://d1imxjix6ljul

View file

@ -0,0 +1,2 @@
class_name CombinableAttribute extends Attribute

View file

@ -0,0 +1 @@
uid://dfkjh55qql76v

View file

@ -0,0 +1,13 @@
class_name EquippableAttribute extends Attribute
enum Type {
PRIMARY,
SECONDARY
}
@export var type: Type = Type.PRIMARY
func equip_to(equipment: Equipment, item: Item):
match type:
Type.PRIMARY: equipment.primary = Option.some(item)
Type.SECONDARY: equipment.secondary = Option.some(item)

View file

@ -0,0 +1 @@
uid://c1y3loxtmkeg3

View file

@ -0,0 +1,2 @@
class_name UsableAttribute extends Attribute

View file

@ -0,0 +1 @@
uid://dpyiysj7aigc3

View file

@ -67,3 +67,5 @@ func on_before_load():
func on_load(data: Dictionary):
position = data.position
rotation = data.rotation

View file

@ -1,29 +0,0 @@
class_name InputListener extends Control
enum ActionEvent {
Pressed,
Released
}
signal opened
signal closed
@export var input_event: ActionEvent
@export var open_action: StringName
@export var close_action: StringName
func _is_active(event: InputEvent, action: StringName) -> bool:
match input_event:
ActionEvent.Pressed: return event.is_action_pressed(action)
ActionEvent.Released: return event.is_action_released(action)
_: return false
func _unhandled_input(event: InputEvent) -> void:
if _is_active(event, open_action):
accept_event()
opened.emit()
func _gui_input(event: InputEvent) -> void:
if _is_active(event, close_action):
accept_event()
closed.emit()

View file

@ -1 +0,0 @@
uid://bbkm8bt2mrq1c

View file

@ -1,67 +0,0 @@
class_name ItemDetailsUI extends HBoxContainer
@export var equipment: Equipment
@export var viewport: SubViewport
@export var description_label: Label
@export var action_menu: Control
var current_item: Option = Option.none
var _displayed_item: Node3D
var _default_description: String
func _ready() -> void:
action_menu.hide()
_default_description = description_label.text
func _set_default():
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()
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()

View file

@ -1,11 +1,11 @@
class_name Equipment extends Resource
signal unequipped_primary(equipment: EquippableItem)
signal equipped_primary(equipment: EquippableItem)
signal unequipped_secondary(equipment: EquippableItem)
signal equipped_secondary(equipment: EquippableItem)
signal unequipped_primary(equipment: Item)
signal equipped_primary(equipment: Item)
signal unequipped_secondary(equipment: Item)
signal equipped_secondary(equipment: Item)
@export var _primary: EquippableItem
@export var _primary: Item
var primary: Option:
get: return Option.from(_primary)
@ -17,7 +17,7 @@ func _unequip_primary():
_primary = null
unequipped_primary.emit(previous)
func _equip_primary(item: EquippableItem):
func _equip_primary(item: Item):
if _primary != null:
_unequip_primary()
@ -31,7 +31,7 @@ func set_primary(item: Option):
_equip_primary(x.unwrap())
_: _unequip_primary()
@export var _secondary: EquippableItem
@export var _secondary: Item
var secondary: Option:
get: return Option.from(_secondary)
@ -43,7 +43,7 @@ func _unequip_secondary():
_secondary = null
unequipped_secondary.emit(previous)
func _equip_secondary(item: EquippableItem):
func _equip_secondary(item: Item):
if _secondary != null:
_unequip_secondary()
@ -67,24 +67,24 @@ func _ready():
if _secondary != null:
_equip_secondary(_secondary)
func equip(item: EquippableItem):
func equip(item: Item):
match item.type:
EquippableItem.EquipmentType.PRIMARY: primary = Option.some(item)
EquippableItem.EquipmentType.SECONDARY: secondary = Option.some(item)
EquippableAttribute.Type.PRIMARY: primary = Option.some(item)
EquippableAttribute.Type.SECONDARY: secondary = Option.some(item)
func unequip(equip_type: EquippableItem.EquipmentType):
func unequip(equip_type: EquippableAttribute.Type):
match equip_type:
EquippableItem.EquipmentType.PRIMARY: primary = Option.none
EquippableItem.EquipmentType.SECONDARY:secondary = Option.none
EquippableAttribute.Type.PRIMARY: primary = Option.none
EquippableAttribute.Type.SECONDARY:secondary = Option.none
func unequip_item(item: EquippableItem):
func unequip_item(item: Item):
equipped_to(item).inspect(unequip)
func is_equipped(item: EquippableItem) -> bool:
func is_equipped(item: Item) -> bool:
return equipped_to(item).is_some()
func equipped_to(item: EquippableItem) -> Option:
func equipped_to(item: Item) -> 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)
EquippableAttribute.Type.PRIMARY when item == _primary: return Option.some(EquippableItem.EquipmentType.PRIMARY)
EquippableAttribute.Type.SECONDARY when item == _secondary: return Option.some(EquippableItem.EquipmentType.SECONDARY)
return Option.none

View file

@ -6,6 +6,14 @@ enum EquipmentType {
}
@export var type: EquipmentType = EquipmentType.PRIMARY
@export var ammo_type: Item
@export var ammo_capacity: int
var uses_ammo: bool:
get: return ammo_type != null
var display_ammo: bool:
get: return ammo_capacity < 2
func is_primary() -> bool:
return type == EquipmentType.PRIMARY

View file

@ -6,6 +6,7 @@ class_name Item extends Resource
@export var icon: Texture2D
@export var scene: PackedScene
@export var preview_scene: PackedScene
@export var attributes: Array[Attribute] = []
func _to_string() -> String:
var icon_path = _resource_path_name(icon)
@ -29,9 +30,19 @@ func create() -> Option:
func create_preview() -> Option:
return _create(preview_scene)
func inspect():
pass
func combine(_with: Item) -> bool:
func has_attribute(type: Variant) -> bool:
for value in attributes:
if is_instance_of(value, type):
return true
return false
return ListIterator.from_array(attributes).any(func(x): return is_instance_of(x, type))
func get_attribute(type: Variant) -> Option:
return ListIterator.from_array(attributes).find(func(x): is_instance_of(x, type))
func get_attributes(type: Variant) -> Iterator:
return ListIterator.from_array(attributes).filter(func(x): is_instance_of(x, type))
func use() -> bool:
return false

View file

@ -1,38 +1,48 @@
class_name NodeExt
class NodeChildIterator:
var _node: Node
var _include_internal: bool
var _index: int
var _length: int
var _node: Node
var _include_internal: bool
var _index: int
var _length: int
func _init(node: Node, include_internal: bool) -> void:
_node = node
_include_internal = include_internal
_index = 0
_length = node.get_child_count(include_internal)
func _init(node: Node, include_internal: bool) -> void:
_node = node
_include_internal = include_internal
_index = 0
_length = node.get_child_count(include_internal)
func _continue() -> bool:
return (_index < _length)
func _continue() -> bool:
return (_index < _length)
func _iter_init(_iter: Array) -> bool:
_index = 0
return _continue()
func _iter_init(_iter: Array) -> bool:
_index = 0
return _continue()
func _iter_next(_iter: Array) -> bool:
_index += 1
return _continue()
func _iter_next(_iter: Array) -> bool:
_index += 1
return _continue()
func _iter_get(_iter: Variant) -> Variant:
return _node.get_child(_index, _include_internal)
func _iter_get(_iter: Variant) -> Variant:
return _node.get_child(_index, _include_internal)
static func find_child(node: Node, predicate: Callable, include_internal: bool = false) -> Option:
for child in NodeChildIterator.new(node, include_internal):
if predicate.call(child):
return Option.some(child)
return Option.none
for child in NodeChildIterator.new(node, include_internal):
if predicate.call(child):
return Option.some(child)
return Option.none
static func find_children(node: Node, predicate: Callable, include_internal: bool = false) -> Array[Node]:
var results: Array[Node] = []
for child in NodeChildIterator.new(node, include_internal):
if predicate.call(child):
results.append(child)
return results
static func find_children_variant(node: Node, variant: Variant, include_internal: bool = false) -> Array[Node]:
return find_children(node, func(child: Node) -> bool: return is_instance_of(child, variant), include_internal)
static func find_child_variant(node: Node, variant: Variant, include_internal: bool = false) -> Option:
for child in NodeChildIterator.new(node, include_internal):
if is_instance_of(child, variant):
return Option.some(child)
return Option.none
for child in NodeChildIterator.new(node, include_internal):
if is_instance_of(child, variant):
return Option.some(child)
return Option.none

View file

@ -1,23 +0,0 @@
class_name RootControl extends InputListener
func _ready() -> void:
if self.focus_mode == Control.FOCUS_NONE:
self.focus_mode = Control.FOCUS_ALL
opened.connect(open)
closed.connect(close)
if visible:
grab_focus()
func open():
show()
grab_focus()
func close():
hide()
release_focus()
func _gui_input(event: InputEvent) -> void:
super(event)
KCUtils.propagate_input_event(self, "_gui_input", event, false)

7
godot/src/ui/box.gd Normal file
View file

@ -0,0 +1,7 @@
class_name Box extends PanelContainer
@export var title_label: Label
@export var body_container: Control
func add_content(content: Control) -> void:
body_container.add_child(content)

1
godot/src/ui/box.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://bnumwlio6adb8

View file

@ -6,4 +6,4 @@ 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)
K.notify(get_parent(), NOTIFICATION_FOCUS_EXIT, true)

View file

@ -0,0 +1,7 @@
class_name ContextMenu extends Control
signal requested_close
func set_options_for(item: Item):
pass

View file

@ -0,0 +1 @@
uid://c71q7htypy0i8

View file

@ -0,0 +1,20 @@
class_name InputGroupListener extends Node
signal pressed
signal released
var listeners: Array[InputListener]
func _ready() -> void:
listeners.assign(NodeExt.find_children_variant(self, InputListener))
for listener in listeners:
listener.pressed.connect(_on_pressed)
listener.released.connect(_on_released)
func _on_pressed() -> void:
pressed.emit()
func _on_released() -> void:
released.emit()

View file

@ -0,0 +1,57 @@
class_name InputListener extends Control
enum InputMethod {
GUI_INPUT,
INPUT,
UNHANDLED_INPUT,
UNHANDLED_KEY_INPUT
}
signal pressed
signal released
@export var action: StringName
@export var method: InputMethod = InputMethod.INPUT
func _ready() -> void:
set_process_input(false)
set_process_unhandled_input(false)
set_process_unhandled_key_input(false)
set_enabled(true)
func set_enabled(enabled: bool) -> void:
match method:
InputMethod.GUI_INPUT | InputMethod.INPUT: set_process_input(enabled)
InputMethod.UNHANDLED_INPUT: set_process_unhandled_input(enabled)
InputMethod.UNHANDLED_KEY_INPUT: set_process_unhandled_key_input(enabled)
func enable() -> void:
set_enabled(true)
func disable() -> void:
set_enabled(false)
func _test_action(event: InputEvent):
if event.is_action_pressed(action):
if pressed.has_connections():
pressed.emit()
accept_event()
elif event.is_action_released(action):
if released.has_connections():
released.emit()
accept_event()
func _gui_input(event: InputEvent) -> void:
if method == InputMethod.GUI_INPUT:
_test_action(event)
func _input(event: InputEvent) -> void:
if method == InputMethod.INPUT:
_test_action(event)
func _unhandled_input(event: InputEvent) -> void:
_test_action(event)
func _unhandled_key_input(event: InputEvent) -> void:
_test_action(event)

View file

@ -0,0 +1,79 @@
class_name InventoryScreen extends Control
signal item_selected(item: Item)
signal requested_close
@export_group("Dependencies")
@export var inventory: Inventory
@export var equipment: Equipment
@export_group("Carousel")
@export var inventory_item_scene: PackedScene
@export var carousel: IndexCarousel
@export var item_details: ItemDetailUI
func _ready() -> void:
_connect_signals()
func _connect_signals() -> void:
inventory.updated.connect(_build_carousel)
carousel.index_changed.connect(_on_item_changed)
enum Direction {
Right = 1,
Left = -1
}
func _gui_input(event: InputEvent) -> void:
if event.is_action_pressed(PlayerInput.UIAction.Right):
move_carousel(Direction.Right)
accept_event()
elif event.is_action_pressed(PlayerInput.UIAction.Left):
move_carousel(Direction.Left)
accept_event()
elif event.is_action_pressed(PlayerInput.UIAction.Accept):
_items().nth(carousel.current_index).inspect(item_selected.emit)
accept_event()
func _items() -> Iterator:
return inventory.iter().map(func(x): return x.value.item)
func _build_carousel() -> void:
K.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))
for item in item_iter.fuse(empty_iter):
var scene = inventory_item_scene.instantiate()
var option = Option.from(item)
bind_item(scene, option)
carousel.add_child(scene)
func bind_item(node: Node, item: Option) -> void:
if node.has_method('bind'):
node.bind(item)
func move_carousel(delta: int):
var next_index = carousel.get_carousel_index() + delta
carousel.go_to_index(next_index)
func close():
requested_close.emit()
func _on_item_changed(index: int) -> void:
item_details.set_item(_items().nth(index))
func _use() -> void:
pass
func _equip() -> void:
pass
func _combine() -> void:
pass
func _inspect() -> void:
pass

View file

@ -0,0 +1 @@
uid://b7j7weoa8tikm

View file

@ -0,0 +1 @@
uid://bjwhkpqabr7sg

View file

@ -21,7 +21,7 @@ func _on_item_changed(index: int) -> void:
_: item_focused.emit(Option.none)
func _build_carousel() -> void:
KCUtils.remove_children(carousel)
K.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))

View file

@ -0,0 +1,35 @@
class_name ItemDetailUI extends HBoxContainer
@export var viewport: SubViewport
@export var description_label: Label
var current_item: Option = Option.none
var _displayed_item: Node3D
var _default_description: String
func _ready() -> void:
_default_description = description_label.text
func _set_default():
if _displayed_item != null:
viewport.remove_child(_displayed_item)
_displayed_item.queue_free()
description_label.text = _default_description
func set_item(item: Option):
current_item = item
if item.is_some():
var _item: Item = item.unwrap()
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:
clear_item()
func clear_item():
_set_default()

View file

@ -1,4 +1,4 @@
class_name ItemUI extends Control
class_name ItemSlotUI extends Control
@export var name_label: Label
@export var icon_texture: TextureRect

27
godot/src/ui/item_ui.gd Normal file
View file

@ -0,0 +1,27 @@
class_name ItemUI extends Control
@export var _title_label: Label
@export var _icon_texture: TextureRect
var _default_title: String
var _default_icon: Texture2D
func _ready() -> void:
_default_title = _title_label.text
_default_icon = _icon_texture.texture
func _set_default() -> void:
_title_label.text = _default_title
_icon_texture.texture = _default_icon
func bind(item: Option) -> void:
match item:
var x when x.is_some():
print(x)
var _item = x.unwrap()
_title_label.text = _item.name
_icon_texture.texture = _item.icon
_: _set_default()
func clear() -> void:
_set_default()

View file

@ -0,0 +1 @@
uid://c2yaayl4msnf1

159
godot/src/ui/ui_manager.gd Normal file
View file

@ -0,0 +1,159 @@
class_name UIManager extends Control
@export var inventory_menu: Control
@export var context_menu: Control
class StackFrame extends RefCounted:
var root: Control
var children: Array[Control] = []
func _init(element: Control) -> void:
root = element
var stack: Array[StackFrame] = []
func _ready() -> void:
if inventory_menu.has_signal('requested_close'):
inventory_menu.requested_close.connect(close_inventory_menu)
#if context_menu.has_signal('requested_close'):
# context_menu.requested_close.connect(close_context_menu)
func get_current_frame() -> Option:
if stack.is_empty(): return Option.none
else: return Option.some(stack.back())
func _focus_current_frame(frame: StackFrame) -> void:
if not frame.children.is_empty():
frame.children.back().grab_focus()
else:
frame.root.grab_focus()
func focus_current_frame() -> void:
get_current_frame().inspect(_focus_current_frame)
func clamp_rect(rect: Rect2) -> Rect2:
var result = Rect2(rect)
var viewport_rect = get_viewport().get_visible_rect()
if result.end.x > viewport_rect.size.x:
result.x = viewport_rect.size.x - result.size.x
result.position.x = maxf(0, rect.position.x)
if result.end.y > viewport_rect.size.y:
result.y = viewport_rect.size.y - result.size.y
result.position.y = maxf(0, rect.position.y)
return result
func open_inventory_menu() -> void:
if is_open(inventory_menu):
return
var new_frame = StackFrame.new(inventory_menu)
stack.append(new_frame)
inventory_menu.show()
inventory_menu.grab_focus()
func close_inventory_menu() -> void:
_handle_root_ui_closed(inventory_menu)
func open_context_menu(_position: Vector2, content: Control) -> void:
if stack.is_empty():
push_error("can't open context menu. no active windows")
return
var current_frame = get_current_frame()
var clamped_rect = clamp_rect(Rect2(_position, context_menu.size))
context_menu.global_position = clamped_rect.position
context_menu.set_content(content)
current_frame.children.append(context_menu)
context_menu.show()
context_menu.grab_focus()
func close_context_menu() -> void:
_handle_child_closed(context_menu)
func is_open(element: Control) -> bool:
for i in range(stack.size()):
if stack[i].root == element:
return true
return false
func _remove_element(element: Control) -> void:
var frame_to_close: StackFrame = null
var frame_index: int = -1
for i in range(stack.size()):
if stack[i].root == element:
frame_to_close = stack[i]
frame_index = i
break
if frame_to_close:
_close_frame(frame_to_close, frame_index)
else:
push_warning("'%s' requested to be closed but was not found as a root UI in any stack frame." % element.name)
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed(PlayerInput.UIAction.Cancel):
var current_frame_option = get_current_frame()
if current_frame_option.is_some():
var current_frame = current_frame_option.unwrap()
if not current_frame.children.is_empty():
var top_child = current_frame.children.back()
if top_child.has_method("cancel"):
top_child.handle_cancel()
else:
top_child.hide()
current_frame.children.pop_back()
focus_current_frame()
else:
var root_element = current_frame.root
if root_element.has_method("cancel"):
root_element.handle_cancel()
else:
root_element.hide()
stack.pop_back()
focus_current_frame()
accept_event()
func _handle_child_closed(child: Control) -> void:
if stack.is_empty(): return
var current_frame = get_current_frame().unwrap()
if not current_frame.children.is_empty() and current_frame.children.back() == child:
current_frame.children.pop_back()
child.hide()
focus_current_frame()
else:
push_warning("A child window '%s' requested to be closed but was not the top-most child of the current stack frame." % child.name)
func _handle_root_ui_closed(root_ui: Control) -> void:
var frame_index = -1
for i in range(stack.size()):
if stack[i].root == root_ui:
frame_index = i
break
if frame_index != -1:
_close_frame(stack[frame_index], frame_index)
else:
push_warning("Root UI '%s' closed but its frame was not found in the stack." % root_ui.name)
func _close_frame(frame: StackFrame, index: int) -> void:
frame.root.hide()
for i in range(frame.children.size() -1, -1, -1):
var child = frame.children[i]
if is_instance_valid(child):
child.hide()
frame.children.clear()
stack.remove_at(index)
focus_current_frame()

View file

@ -0,0 +1 @@
uid://35hnuxagjlo2

View file

View file

@ -1 +0,0 @@
uid://bxd483uvo31jf