diff --git a/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd
new file mode 100644
index 0000000..0fdae28
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd
@@ -0,0 +1,135 @@
+@tool
+@icon("TouchScreenButtonControl.svg")
+class_name TouchScreenButtonControl
+extends TextureButton
+
+const DefaultValues := {
+ "expand": true,
+ "ignore_texture_size": true,
+ "stretch_mode": TextureButton.STRETCH_KEEP_ASPECT_CENTERED,
+ "action_mode": TextureButton.ACTION_MODE_BUTTON_PRESS,
+ "focus_mode": TextureButton.FOCUS_NONE,
+}
+
+@export var use_default_values := true
+@export var touchscreen_only := false
+
+# The actual variable that holds the data
+var input_action: String = ""
+
+# 2. MATCHED the property name here...
+func _get_property_list() -> Array:
+ var properties: Array = []
+
+ if Engine.is_editor_hint():
+ InputMap.load_from_project_settings()
+
+ # Get actions and format them for the dropdown
+ var actions = InputMap.get_actions()
+ var action_list = ",".join(actions)
+
+ properties.append({
+ "name": "input_action",
+ "type": TYPE_STRING,
+ "hint": PROPERTY_HINT_ENUM_SUGGESTION,
+ "hint_string": ",".join(actions),
+ "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR
+ })
+
+ return properties
+
+func _set(property: StringName, value: Variant) -> bool:
+ if property == "input_action":
+ input_action = value
+ return true
+ return false
+
+func _get(property: StringName) -> Variant:
+ if property == "input_action":
+ return input_action
+ return null
+
+# Track multiple simultaneous touches for multitouch support
+var active_touches := {} # Dictionary: touch_index -> bool (true if pressed)
+var initial_press_touches := {} # Dictionary: touch_index -> bool (true if this button was pressed on initial touch)
+
+func _init():
+ if use_default_values:
+ for k in DefaultValues.keys():
+ self.set(k, DefaultValues.get(k))
+
+ # Set mouse_filter to IGNORE so the button doesn't consume touch events
+ # This allows multiple buttons to detect the same touch simultaneously
+ mouse_filter = Control.MOUSE_FILTER_IGNORE
+
+ if touchscreen_only and not DisplayServer.is_touchscreen_available():
+ hide()
+
+func press():
+ var input_event: InputEvent = InputMap.action_get_events(input_action)[0]
+ input_event.pressed = true
+ Input.parse_input_event(input_event)
+
+func release():
+ var input_event: InputEvent = InputMap.action_get_events(input_action)[0]
+ input_event.pressed = false
+ Input.parse_input_event(input_event)
+
+func is_in(pos: Vector2) -> bool:
+ # Get the global rect of this Control node in screen coordinates
+ var global_rect = get_global_rect()
+ # Check if the touch position is within the button's global rect
+ if pos.x >= global_rect.position.x and pos.x <= global_rect.position.x + global_rect.size.x:
+ if pos.y >= global_rect.position.y and pos.y <= global_rect.position.y + global_rect.size.y:
+ return true
+ return false
+
+func _input(event):
+ # Use _input to receive all touch events
+ # IMPORTANT: _input is called on ALL nodes in the scene tree, so multiple buttons
+ # can receive the same event. We don't consume the event so others can too.
+ if event is InputEventScreenTouch:
+ if event.pressed:
+ # Check if this touch is within this button's bounds
+ if is_in(event.position):
+ # Start tracking this touch for this button
+ if event.index not in active_touches:
+ active_touches[event.index] = true
+ initial_press_touches[event.index] = true # Mark as initial press
+ press()
+ else:
+ # Touch released - check if we were tracking it
+ if event.index in active_touches:
+ # This touch was being tracked by this button, release it
+ active_touches.erase(event.index)
+ initial_press_touches.erase(event.index)
+ # Only release the action if no other touches are active for this button
+ if active_touches.is_empty():
+ release()
+ elif event is InputEventScreenDrag:
+ # Handle touch drag with smart re-activation logic
+ if event.index in active_touches:
+ # We're tracking this touch
+ if initial_press_touches.has(event.index):
+ # This was an initial press - keep it active even if touch moves outside
+ # Don't release until touch ends
+ pass
+ else:
+ # This was a re-activation (touch moved back into bounds)
+ # Check if touch moved back out of bounds
+ if not is_in(event.position):
+ # Touch moved out of bounds, release this re-activated button
+ active_touches.erase(event.index)
+ if active_touches.is_empty():
+ release()
+ else:
+ # We're not tracking this touch - check if it moved into our bounds
+ # This allows "tapping" behavior - touch can re-enter and activate button
+ if is_in(event.position):
+ # Touch moved into bounds, start tracking (but not as initial press)
+ active_touches[event.index] = true
+ press()
+
+ # CRITICAL: Never call get_viewport().set_input_as_handled() here
+ # This would prevent other buttons from receiving the same touch event
+ # mouse_filter is set to IGNORE so the TextureButton doesn't consume mouse/touch events
diff --git a/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd.uid b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd.uid
new file mode 100644
index 0000000..37e884e
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd.uid
@@ -0,0 +1 @@
+uid://bh5a3ydiu51eo
diff --git a/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg
new file mode 100644
index 0000000..ed7c755
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg.import b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg.import
new file mode 100644
index 0000000..dc380c2
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ckvwnehwdvwyq"
+path="res://.godot/imported/TouchScreenButtonControl.svg-ec8e7f48e271699010d76650daf1583d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg"
+dest_files=["res://.godot/imported/TouchScreenButtonControl.svg-ec8e7f48e271699010d76650daf1583d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.tscn b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.tscn
new file mode 100644
index 0000000..95938ee
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=3 uid="uid://dsj828xm2e28w"]
+
+[ext_resource type="Script" path="res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd" id="1_5k641"]
+
+[node name="TouchScreenButtonControl" type="TextureButton"]
+script = ExtResource("1_5k641")
diff --git a/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControlPlugin.gd b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControlPlugin.gd
new file mode 100644
index 0000000..d594c0e
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControlPlugin.gd
@@ -0,0 +1,15 @@
+@tool
+extends EditorPlugin
+
+var MyCustomNode = preload("res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd")
+
+func _enter_tree():
+ add_custom_type(
+ "TouchScreenButtonControl",
+ "Control",
+ TouchScreenButtonControl,
+ preload("res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg")
+ )
+
+func _exit_tree():
+ remove_custom_type("TouchScreenButtonControl")
diff --git a/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControlPlugin.gd.uid b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControlPlugin.gd.uid
new file mode 100644
index 0000000..a9e0ed5
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/TouchScreenButtonControlPlugin.gd.uid
@@ -0,0 +1 @@
+uid://cq0bml8epsqa
diff --git a/src/addons/touchscreenbuttoncontrol/button_style.tres b/src/addons/touchscreenbuttoncontrol/button_style.tres
new file mode 100644
index 0000000..52a9a3f
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/button_style.tres
@@ -0,0 +1,13 @@
+[gd_resource type="StyleBoxFlat" format=3 uid="uid://cv5o175a2677e"]
+
+[resource]
+bg_color = Color(0.3, 0.3, 0.3, 0.7)
+border_width_left = 2
+border_width_top = 2
+border_width_right = 2
+border_width_bottom = 2
+border_color = Color(0.8, 0.8, 0.8, 0.9)
+corner_radius_top_left = 40
+corner_radius_top_right = 40
+corner_radius_bottom_right = 40
+corner_radius_bottom_left = 40
diff --git a/src/addons/touchscreenbuttoncontrol/icon.svg b/src/addons/touchscreenbuttoncontrol/icon.svg
new file mode 100644
index 0000000..ed7c755
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/addons/touchscreenbuttoncontrol/icon.svg.import b/src/addons/touchscreenbuttoncontrol/icon.svg.import
new file mode 100644
index 0000000..1b95715
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/icon.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://x5ggo5vlsqwn"
+path="res://.godot/imported/icon.svg-e7770945a21c9fca528355bbf6b1708f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/touchscreenbuttoncontrol/icon.svg"
+dest_files=["res://.godot/imported/icon.svg-e7770945a21c9fca528355bbf6b1708f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/src/addons/touchscreenbuttoncontrol/plugin.cfg b/src/addons/touchscreenbuttoncontrol/plugin.cfg
new file mode 100644
index 0000000..faffc24
--- /dev/null
+++ b/src/addons/touchscreenbuttoncontrol/plugin.cfg
@@ -0,0 +1,7 @@
+[plugin]
+
+name="TouchScreenButtonControl"
+description="A Control Node version to TouchScreenButton2D"
+author="Matata.exe"
+version="1.0"
+script="TouchScreenButtonControlPlugin.gd"
diff --git a/src/addons/virtual_joystick/icon.svg b/src/addons/virtual_joystick/icon.svg
new file mode 100644
index 0000000..bd9b8e1
--- /dev/null
+++ b/src/addons/virtual_joystick/icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/addons/virtual_joystick/icon.svg.import b/src/addons/virtual_joystick/icon.svg.import
new file mode 100644
index 0000000..912cd8e
--- /dev/null
+++ b/src/addons/virtual_joystick/icon.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ndaordejurrl"
+path="res://.godot/imported/icon.svg-3eaf29e1973fdc580c89279657f85e37.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/icon.svg"
+dest_files=["res://.godot/imported/icon.svg-3eaf29e1973fdc580c89279657f85e37.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/src/addons/virtual_joystick/plugin.cfg b/src/addons/virtual_joystick/plugin.cfg
new file mode 100644
index 0000000..f9cfc04
--- /dev/null
+++ b/src/addons/virtual_joystick/plugin.cfg
@@ -0,0 +1,8 @@
+[plugin]
+
+name="Virtual Joystick"
+description="Virtual Joystick is a lightweight and fully configurable plugin that adds a virtual joystick to the screen, ideal for mobile games or touch-based interfaces.
+With it, you can control player movement or any other input action using a simple, responsive, and customizable visual stick."
+author="Saulo de Souza"
+version="1.0.7"
+script="plugin.gd"
diff --git a/src/addons/virtual_joystick/plugin.gd b/src/addons/virtual_joystick/plugin.gd
new file mode 100644
index 0000000..575cfe6
--- /dev/null
+++ b/src/addons/virtual_joystick/plugin.gd
@@ -0,0 +1,11 @@
+@tool
+extends EditorPlugin
+
+var icon = preload("res://addons/virtual_joystick/icon.svg")
+var script_main = preload("res://addons/virtual_joystick/virtual_joystick.gd")
+
+func _enter_tree():
+ add_custom_type("VirtualJoystick", "Control", script_main, icon)
+
+func _exit_tree():
+ remove_custom_type("VirtualJoystick")
diff --git a/src/addons/virtual_joystick/plugin.gd.uid b/src/addons/virtual_joystick/plugin.gd.uid
new file mode 100644
index 0000000..6403728
--- /dev/null
+++ b/src/addons/virtual_joystick/plugin.gd.uid
@@ -0,0 +1 @@
+uid://e7m2yqefj838
diff --git a/src/addons/virtual_joystick/resources/textures/joystick_texture_1.png b/src/addons/virtual_joystick/resources/textures/joystick_texture_1.png
new file mode 100644
index 0000000..e562981
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/joystick_texture_1.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/joystick_texture_1.png.import b/src/addons/virtual_joystick/resources/textures/joystick_texture_1.png.import
new file mode 100644
index 0000000..8f6f1d3
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/joystick_texture_1.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://mfjv5h7sdlhy"
+path="res://.godot/imported/joystick_texture_1.png-9fe11098e467f8f7500bf2529275c515.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_1.png"
+dest_files=["res://.godot/imported/joystick_texture_1.png-9fe11098e467f8f7500bf2529275c515.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/joystick_texture_2.png b/src/addons/virtual_joystick/resources/textures/joystick_texture_2.png
new file mode 100644
index 0000000..43efc90
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/joystick_texture_2.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/joystick_texture_2.png.import b/src/addons/virtual_joystick/resources/textures/joystick_texture_2.png.import
new file mode 100644
index 0000000..7ed5ccd
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/joystick_texture_2.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cppp7p7l040i5"
+path="res://.godot/imported/joystick_texture_2.png-bd8e129c570c51a41d34619540e549b1.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_2.png"
+dest_files=["res://.godot/imported/joystick_texture_2.png-bd8e129c570c51a41d34619540e549b1.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/joystick_texture_3.png b/src/addons/virtual_joystick/resources/textures/joystick_texture_3.png
new file mode 100644
index 0000000..f617a46
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/joystick_texture_3.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/joystick_texture_3.png.import b/src/addons/virtual_joystick/resources/textures/joystick_texture_3.png.import
new file mode 100644
index 0000000..5fbba47
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/joystick_texture_3.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ct6r0wagtmapd"
+path="res://.godot/imported/joystick_texture_3.png-d28d8fdffe3dd01bcd800f8da8ffad5c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_3.png"
+dest_files=["res://.godot/imported/joystick_texture_3.png-d28d8fdffe3dd01bcd800f8da8ffad5c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/joystick_texture_4.png b/src/addons/virtual_joystick/resources/textures/joystick_texture_4.png
new file mode 100644
index 0000000..54672be
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/joystick_texture_4.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/joystick_texture_4.png.import b/src/addons/virtual_joystick/resources/textures/joystick_texture_4.png.import
new file mode 100644
index 0000000..a33562b
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/joystick_texture_4.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://rxah3fc1lih3"
+path="res://.godot/imported/joystick_texture_4.png-288403f1a78edebf82b0917d63d71545.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_4.png"
+dest_files=["res://.godot/imported/joystick_texture_4.png-288403f1a78edebf82b0917d63d71545.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/joystick_texture_5.png b/src/addons/virtual_joystick/resources/textures/joystick_texture_5.png
new file mode 100644
index 0000000..5afe13c
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/joystick_texture_5.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/joystick_texture_5.png.import b/src/addons/virtual_joystick/resources/textures/joystick_texture_5.png.import
new file mode 100644
index 0000000..313700d
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/joystick_texture_5.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://01qhightlcso"
+path="res://.godot/imported/joystick_texture_5.png-b4d7bb661b1dfa9d44580770afad2948.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_5.png"
+dest_files=["res://.godot/imported/joystick_texture_5.png-b4d7bb661b1dfa9d44580770afad2948.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/joystick_texture_6.png b/src/addons/virtual_joystick/resources/textures/joystick_texture_6.png
new file mode 100644
index 0000000..8f1b90f
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/joystick_texture_6.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/joystick_texture_6.png.import b/src/addons/virtual_joystick/resources/textures/joystick_texture_6.png.import
new file mode 100644
index 0000000..5bff998
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/joystick_texture_6.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://don118m3unno4"
+path="res://.godot/imported/joystick_texture_6.png-2b34481992ebc7f5529547a31713f9e4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_6.png"
+dest_files=["res://.godot/imported/joystick_texture_6.png-2b34481992ebc7f5529547a31713f9e4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/stick_texture_1.png b/src/addons/virtual_joystick/resources/textures/stick_texture_1.png
new file mode 100644
index 0000000..e486508
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/stick_texture_1.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/stick_texture_1.png.import b/src/addons/virtual_joystick/resources/textures/stick_texture_1.png.import
new file mode 100644
index 0000000..fcd1e16
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/stick_texture_1.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dv7m8ofd7vjkg"
+path="res://.godot/imported/stick_texture_1.png-b7322c6c9fa9ceca47042e9525a31e3d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/stick_texture_1.png"
+dest_files=["res://.godot/imported/stick_texture_1.png-b7322c6c9fa9ceca47042e9525a31e3d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/stick_texture_2.png b/src/addons/virtual_joystick/resources/textures/stick_texture_2.png
new file mode 100644
index 0000000..8b6826f
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/stick_texture_2.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/stick_texture_2.png.import b/src/addons/virtual_joystick/resources/textures/stick_texture_2.png.import
new file mode 100644
index 0000000..57f7c8c
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/stick_texture_2.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bra3aeybagspi"
+path="res://.godot/imported/stick_texture_2.png-56a0dc5972515a4c813acb0018d59897.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/stick_texture_2.png"
+dest_files=["res://.godot/imported/stick_texture_2.png-56a0dc5972515a4c813acb0018d59897.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/stick_texture_3.png b/src/addons/virtual_joystick/resources/textures/stick_texture_3.png
new file mode 100644
index 0000000..fa345e5
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/stick_texture_3.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/stick_texture_3.png.import b/src/addons/virtual_joystick/resources/textures/stick_texture_3.png.import
new file mode 100644
index 0000000..3f16d56
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/stick_texture_3.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b76m3oio3bpve"
+path="res://.godot/imported/stick_texture_3.png-ac8c0e09219e9294012c766efb28a6dd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/stick_texture_3.png"
+dest_files=["res://.godot/imported/stick_texture_3.png-ac8c0e09219e9294012c766efb28a6dd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/stick_texture_4.png b/src/addons/virtual_joystick/resources/textures/stick_texture_4.png
new file mode 100644
index 0000000..3b13e51
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/stick_texture_4.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/stick_texture_4.png.import b/src/addons/virtual_joystick/resources/textures/stick_texture_4.png.import
new file mode 100644
index 0000000..2b9e125
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/stick_texture_4.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dt4ujdvuod0ei"
+path="res://.godot/imported/stick_texture_4.png-ea228bad22a241c375a4eb387cc66da7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/stick_texture_4.png"
+dest_files=["res://.godot/imported/stick_texture_4.png-ea228bad22a241c375a4eb387cc66da7.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/stick_texture_5.png b/src/addons/virtual_joystick/resources/textures/stick_texture_5.png
new file mode 100644
index 0000000..a2fec7a
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/stick_texture_5.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/stick_texture_5.png.import b/src/addons/virtual_joystick/resources/textures/stick_texture_5.png.import
new file mode 100644
index 0000000..be99b9e
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/stick_texture_5.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dywm4x5vqdtsm"
+path="res://.godot/imported/stick_texture_5.png-f76da9fbec9ae506d29c25a5b2e273b4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/stick_texture_5.png"
+dest_files=["res://.godot/imported/stick_texture_5.png-f76da9fbec9ae506d29c25a5b2e273b4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/resources/textures/stick_texture_6.png b/src/addons/virtual_joystick/resources/textures/stick_texture_6.png
new file mode 100644
index 0000000..39259e8
Binary files /dev/null and b/src/addons/virtual_joystick/resources/textures/stick_texture_6.png differ
diff --git a/src/addons/virtual_joystick/resources/textures/stick_texture_6.png.import b/src/addons/virtual_joystick/resources/textures/stick_texture_6.png.import
new file mode 100644
index 0000000..0470110
--- /dev/null
+++ b/src/addons/virtual_joystick/resources/textures/stick_texture_6.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://fts4nb53arsl"
+path="res://.godot/imported/stick_texture_6.png-0fdb4087c1eca258d05fa6e2a535cbbe.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/virtual_joystick/resources/textures/stick_texture_6.png"
+dest_files=["res://.godot/imported/stick_texture_6.png-0fdb4087c1eca258d05fa6e2a535cbbe.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/src/addons/virtual_joystick/virtual_joystick.gd b/src/addons/virtual_joystick/virtual_joystick.gd
new file mode 100644
index 0000000..049369d
--- /dev/null
+++ b/src/addons/virtual_joystick/virtual_joystick.gd
@@ -0,0 +1,496 @@
+@tool
+@icon("res://addons/virtual_joystick/icon.svg")
+class_name VirtualJoystick
+extends Control
+
+#region Signals =================================================
+## Emitted when the stick is moved.
+signal analogic_changed(
+ value: Vector2,
+ distance: float,
+ angle: float,
+ angle_clockwise: float,
+ angle_not_clockwise: float
+)
+
+## Emitted when the stick enters the dead zone.
+signal deadzone_enter
+
+## Emitted when the stick leaves the dead zone.
+signal deadzone_leave
+#endregion Signals ===============================================
+
+
+#region Private Properties ======================================
+var _joystick: VirtualJoystickCircle
+var _stick: VirtualJoystickCircle
+
+var _joystick_radius: float = 100.0
+var _joystick_border_width: float = 10.0
+var _joystick_start_position: Vector2 = Vector2(_joystick_radius + _joystick_border_width, _joystick_radius + _joystick_border_width)
+
+var _stick_radius: float = 45.0
+var _stick_border_width: float = -1.0
+var _stick_start_position: Vector2 = _joystick_start_position
+
+var _drag_started_inside := false
+var _click_in := false
+var _delta: Vector2 = Vector2.ZERO
+var _in_deadzone: bool = false:
+ set(value):
+ if value != _in_deadzone:
+ _in_deadzone = value
+ if not active:
+ return
+ if _in_deadzone:
+ deadzone_enter.emit()
+ else:
+ deadzone_leave.emit()
+
+var _real_size: Vector2 = size * scale
+var _warnings: PackedStringArray = []
+
+var _DEFAULT_JOYSTICK_TEXTURE = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_1.png")
+var _JOYSTICK_TEXTURE_2 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_2.png")
+var _JOYSTICK_TEXTURE_3 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_3.png")
+var _JOYSTICK_TEXTURE_4 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_4.png")
+var _JOYSTICK_TEXTURE_5 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_5.png")
+var _JOYSTICK_TEXTURE_6 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_6.png")
+
+var _DEFAULT_STICK_TEXTURE = preload("res://addons/virtual_joystick/resources/textures/stick_texture_1.png")
+var _STICK_TEXTURE_2 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_2.png")
+var _STICK_TEXTURE_3 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_3.png")
+var _STICK_TEXTURE_4 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_4.png")
+var _STICK_TEXTURE_5 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_5.png")
+var _STICK_TEXTURE_6 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_6.png")
+
+enum _preset_enum {
+ ## Nothing
+ NONE,
+ ## Default preset texture
+ PRESET_DEFAULT,
+ ## Texture 2
+ PRESET_2,
+ ## Texture 3
+ PRESET_3,
+ ## Texture 4
+ PRESET_4,
+ ## Texture 5
+ PRESET_5,
+ ## Texture 6
+ PRESET_6,
+
+}
+#endregion Private Properties ====================================
+
+
+#region Public Properties =======================================
+## Normalized joystick direction vector (X, Y).
+var value: Vector2 = Vector2.ZERO
+
+## Distance of the stick from the joystick center (0.0 to 1.0).
+var distance: float = 0.0
+
+## Angle in degrees (universal reference, 0° = right).
+var angle_degrees: float = 0.0
+
+## Angle in degrees, measured clockwise.
+var angle_degrees_clockwise: float = 0.0
+
+## Angle in degrees, measured counter-clockwise.
+var angle_degrees_not_clockwise: float = 0.0
+#endregion Public Properties =====================================
+
+
+#region Exports ===================================================
+@export_category("Virtual Joystick")
+## Enables or disables the joystick input.
+@export var active: bool = true
+## Deadzone threshold (0.0 = off, 1.0 = full range).
+@export_range(0.0, 0.9, 0.001, "suffix:length") var deadzone: float = 0.1
+## Global scale factor of the joystick.
+@export_range(0.1, 2.0, 0.001, "suffix:x", "or_greater") var scale_factor: float = 1.0:
+ set(value):
+ scale_factor = value
+ scale = Vector2(value, value)
+ _update_real_size()
+ queue_redraw()
+## If true, the Joystick will only be displayed on the screen on mobile devices.
+@export var only_mobile: bool = false:
+ set(value):
+ only_mobile = value
+ if only_mobile == true and OS.get_name().to_lower() not in ["android", "ios"]:
+ visible = false
+ else:
+ visible = true
+
+@export_category("Joystick")
+## Enable the use of textures for the joystick.
+@export var joystick_use_textures: bool = true:
+ set(value):
+ joystick_use_textures = value
+ if value and joystick_texture == null:
+ _set_joystick_preset(joystick_preset_texture)
+ _verify_can_use_border()
+ update_configuration_warnings()
+ queue_redraw()
+## Select one of the available models. More models will be available soon.
+@export var joystick_preset_texture: _preset_enum = _preset_enum.PRESET_5: set = _set_joystick_preset
+## Select a texture for the joystick figure.
+@export var joystick_texture: Texture2D = _JOYSTICK_TEXTURE_5:
+ set(value):
+ joystick_texture = value
+ update_configuration_warnings()
+ _verify_can_use_border()
+ queue_redraw()
+## Base color of the joystick background.
+@export_color_no_alpha() var joystick_color: Color = Color.WHITE:
+ set(value):
+ joystick_color = value
+ if _joystick:
+ _joystick.color = value
+ _joystick.opacity = joystick_opacity
+ queue_redraw()
+## Opacity of the joystick base.
+@export_range(0.0, 1.0, 0.001, "suffix:alpha") var joystick_opacity: float = 0.8:
+ set(value):
+ joystick_opacity = value
+ if _joystick:
+ _joystick.opacity = value
+ queue_redraw()
+## Width of the joystick base border.
+@export_range(1.0, 20.0, 0.01, "suffix:px", "or_greater") var joystick_border: float = 1.0:
+ set(value):
+ joystick_border = value
+ _joystick.width = value
+ _joystick_border_width = value
+ _joystick_start_position = Vector2(_joystick_radius + _joystick_border_width, _joystick_radius + _joystick_border_width)
+ _joystick.position = _joystick_start_position
+ _stick_start_position = Vector2(_joystick_radius + _joystick_border_width, _joystick_radius + _joystick_border_width)
+ _stick.position = _stick_start_position
+ update_configuration_warnings()
+ queue_redraw()
+
+
+@export_category("Stick")
+## Enable the use of textures for the stick.
+@export var stick_use_textures: bool = true:
+ set(value):
+ stick_use_textures = value
+ if value and stick_texture == null:
+ _set_stick_preset(stick_preset_texture)
+ update_configuration_warnings()
+ queue_redraw()
+## Select one of the available models. More models will be available soon.
+@export var stick_preset_texture: _preset_enum = _preset_enum.PRESET_5: set = _set_stick_preset
+## Select a texture for the stick figure.
+@export var stick_texture: Texture2D = _STICK_TEXTURE_5:
+ set(value):
+ stick_texture = value
+ update_configuration_warnings()
+ queue_redraw()
+## Stick (thumb) color.
+@export_color_no_alpha() var stick_color: Color = Color.WHITE:
+ set(value):
+ stick_color = value
+ if _stick:
+ _stick.color = value
+ _stick.opacity = stick_opacity
+ queue_redraw()
+## Opacity of the stick.
+@export_range(0.0, 1.0, 0.001, "suffix:alpha") var stick_opacity: float = 0.8:
+ set(value):
+ stick_opacity = value
+ if _stick:
+ _stick.opacity = value
+ queue_redraw()
+#endregion Exports =================================================
+
+
+#region Engine Methods =============================================
+func _init() -> void:
+ _joystick = VirtualJoystickCircle.new(_joystick_start_position, _joystick_radius, _joystick_border_width, false, joystick_color, joystick_opacity)
+ _stick = VirtualJoystickCircle.new(_stick_start_position, _stick_radius, _stick_border_width, true, stick_color, stick_opacity)
+ queue_redraw()
+
+
+func _ready() -> void:
+ set_size(Vector2(_joystick_radius * 2 + _joystick_border_width * 2, _joystick_radius * 2 + _joystick_border_width * 2))
+ _update_real_size()
+
+
+func _draw() -> void:
+ if joystick_use_textures and joystick_texture:
+ var base_size = joystick_texture.get_size()
+ var base_scale = (_joystick_radius * 2) / base_size.x
+ draw_set_transform(_joystick.position, 0, Vector2(base_scale, base_scale))
+ draw_texture(joystick_texture, -base_size / 2, Color(joystick_color.r, joystick_color.g, joystick_color.b, joystick_opacity))
+ draw_set_transform(Vector2.ZERO, 0, Vector2.ONE)
+ else:
+ _joystick.draw(self, false)
+
+ if stick_use_textures and stick_texture:
+ var stick_size = stick_texture.get_size()
+ var stick_scale = (_stick_radius * 2) / stick_size.x
+ draw_set_transform(_stick.position, 0, Vector2(stick_scale, stick_scale))
+ draw_texture(stick_texture, -stick_size / 2, Color(stick_color.r, stick_color.g, stick_color.b, stick_opacity))
+ draw_set_transform(Vector2.ZERO, 0, Vector2.ONE)
+ else:
+ _stick.draw(self, false)
+
+ scale = Vector2(scale_factor, scale_factor)
+ set_size(Vector2((_joystick_radius * 2) + (_joystick_border_width * 2), (_joystick_radius * 2) + (_joystick_border_width * 2)))
+
+
+func _gui_input(event: InputEvent) -> void:
+ if event is InputEventScreenTouch:
+ if event.pressed:
+ distance = event.position.distance_to(_joystick.position)
+ _drag_started_inside = distance <= _joystick.radius + _joystick.width / 2
+ if _drag_started_inside:
+ _click_in = true
+ _update_stick(event.position)
+ else:
+ _click_in = false
+ else:
+ if _click_in:
+ _reset_values()
+ _update_emit_signals()
+ _click_in = false
+ _drag_started_inside = false
+ _stick.position = _stick_start_position
+ queue_redraw()
+
+ elif event is InputEventScreenDrag:
+ if _drag_started_inside:
+ _update_stick(event.position)
+
+
+func _get_configuration_warnings() -> PackedStringArray:
+ _warnings = []
+ if joystick_use_textures and (joystick_texture == null):
+ _warnings.append("The joystick_texture properties must be set when using joystick_use_textures = true.")
+ if stick_use_textures and (stick_texture == null):
+ _warnings.append("The stick_texture properties must be set when using stick_use_textures = true.")
+ if joystick_use_textures and joystick_texture != null and joystick_preset_texture != _preset_enum.NONE and joystick_border > 1.0:
+ _warnings.append("When using a texture preset, the ideal border height would be 1.0.")
+ return _warnings
+
+#endregion Engine Methods =============================================
+
+
+#region Private Methods ============================================
+func _update_stick(_position: Vector2) -> void:
+ _delta = _position - _stick_start_position
+ if _delta.length() > _joystick.radius:
+ _delta = _delta.normalized() * _joystick.radius
+ _stick.position = _stick_start_position + _delta
+ queue_redraw()
+
+ var processed = _apply_deadzone(_delta / _joystick.radius)
+ value = processed.value
+ distance = processed.distance
+ angle_degrees = processed.angle_degrees
+ angle_degrees_clockwise = processed.angle_clockwise
+ angle_degrees_not_clockwise = processed.angle_not_clockwise
+
+ _update_emit_signals()
+
+
+func _reset_values() -> void:
+ _delta = Vector2.ZERO
+ value = Vector2.ZERO
+ distance = 0.0
+ angle_degrees = 0.0
+ angle_degrees_clockwise = 0.0
+ angle_degrees_not_clockwise = 0.0
+ _stick.position = _stick_start_position
+
+ var length = (_delta / _joystick.radius).length()
+ var dz = clamp(deadzone, 0.0, 0.99)
+ if length <= dz:
+ _in_deadzone = true
+
+ queue_redraw()
+
+
+## Applies linear deadzone adjustment and calculates resulting angles.
+func _apply_deadzone(input_value: Vector2) -> Dictionary:
+ var length = input_value.length()
+ var result = Vector2.ZERO
+ var dz = clamp(deadzone, 0.0, 0.99)
+
+ if length <= dz:
+ _in_deadzone = true
+ result = Vector2.ZERO
+ length = 0.0
+ else:
+ _in_deadzone = false
+ # Re-scale linearly between deadzone and full range
+ var adjusted = (length - dz) / (1.0 - dz)
+ result = input_value.normalized() * adjusted
+ length = adjusted
+
+ var angle_cw = _get_angle_delta(result * _joystick.radius, true, true)
+ var angle_ccw = _get_angle_delta(result * _joystick.radius, true, false)
+ var angle = _get_angle_delta(result * _joystick.radius, false, false)
+
+ if active:
+ return {
+ "value": result,
+ "distance": length,
+ "angle_clockwise": angle_cw,
+ "angle_not_clockwise": angle_ccw,
+ "angle_degrees": angle
+ }
+ else:
+ return {
+ "value": Vector2.ZERO,
+ "distance": 0.0,
+ "angle_clockwise": 0.0,
+ "angle_not_clockwise": 0.0,
+ "angle_degrees": 0.0
+ }
+
+
+func _update_emit_signals() -> void:
+ if not active:
+ return
+ if _in_deadzone:
+ analogic_changed.emit(
+ Vector2.ZERO,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0
+ )
+ else:
+ analogic_changed.emit(
+ value,
+ distance,
+ angle_degrees,
+ angle_degrees_clockwise,
+ angle_degrees_not_clockwise
+ )
+
+
+func _update_real_size() -> void:
+ _real_size = size * scale
+ pivot_offset = size / 2
+
+
+## Calculates the angle of a vector in degrees.
+func _get_angle_delta(delta: Vector2, continuous: bool, clockwise: bool) -> float:
+ var angle_deg = 0.0
+ if continuous and not clockwise:
+ angle_deg = rad_to_deg(atan2(-delta.y, delta.x))
+ else:
+ angle_deg = rad_to_deg(atan2(delta.y, delta.x))
+ if continuous and angle_deg < 0.0:
+ angle_deg += 360.0
+ return angle_deg
+
+
+func _set_joystick_preset(_value: _preset_enum) -> void:
+ joystick_preset_texture = _value
+ match (_value):
+ _preset_enum.PRESET_DEFAULT:
+ joystick_texture = _DEFAULT_JOYSTICK_TEXTURE
+ _preset_enum.PRESET_2:
+ joystick_texture = _JOYSTICK_TEXTURE_2
+ _preset_enum.PRESET_3:
+ joystick_texture = _JOYSTICK_TEXTURE_3
+ _preset_enum.PRESET_4:
+ joystick_texture = _JOYSTICK_TEXTURE_4
+ _preset_enum.PRESET_5:
+ joystick_texture = _JOYSTICK_TEXTURE_5
+ _preset_enum.PRESET_6:
+ joystick_texture = _JOYSTICK_TEXTURE_6
+ _preset_enum.NONE:
+ if joystick_texture in [_DEFAULT_JOYSTICK_TEXTURE, _JOYSTICK_TEXTURE_2, _JOYSTICK_TEXTURE_3, _JOYSTICK_TEXTURE_4, _JOYSTICK_TEXTURE_5, _JOYSTICK_TEXTURE_6]:
+ joystick_texture = null
+ _verify_can_use_border()
+ update_configuration_warnings()
+
+func _set_stick_preset(_value: _preset_enum) -> void:
+ stick_preset_texture = _value
+ match (_value):
+ _preset_enum.PRESET_DEFAULT:
+ stick_texture = _DEFAULT_STICK_TEXTURE
+ _preset_enum.PRESET_2:
+ stick_texture = _STICK_TEXTURE_2
+ _preset_enum.PRESET_3:
+ stick_texture = _STICK_TEXTURE_3
+ _preset_enum.PRESET_4:
+ stick_texture = _STICK_TEXTURE_4
+ _preset_enum.PRESET_5:
+ stick_texture = _STICK_TEXTURE_5
+ _preset_enum.PRESET_6:
+ stick_texture = _STICK_TEXTURE_6
+ _preset_enum.NONE:
+ if stick_texture in [_DEFAULT_STICK_TEXTURE, _STICK_TEXTURE_2, _STICK_TEXTURE_3, _STICK_TEXTURE_4, _STICK_TEXTURE_5, _STICK_TEXTURE_6]:
+ stick_texture = null
+
+
+func _verify_can_use_border() -> bool:
+ if joystick_use_textures and not joystick_texture == null:
+ joystick_border = 1.0
+ return false
+ return true
+#endregion Private Methods ===========================================
+
+
+#region Public Methods =============================================
+## Returns the current joystick vector value.
+func get_value() -> Vector2:
+ return value
+
+
+## Returns the joystick distance (0 to 1).
+func get_distance() -> float:
+ return distance
+
+
+## Returns the current joystick angle (clockwise).
+func get_angle_degrees_clockwise() -> float:
+ return angle_degrees_clockwise
+
+
+## Returns the current joystick angle (counter-clockwise).
+func get_angle_degrees_not_clockwise() -> float:
+ return angle_degrees_not_clockwise
+
+
+## Returns a specific angle configuration.
+func get_angle_degrees(continuous: bool = true, clockwise: bool = false) -> float:
+ return _get_angle_delta(_delta, continuous, clockwise)
+#endregion Public Methods ============================================
+
+
+#region Classes ====================================================
+class VirtualJoystickCircle extends RefCounted:
+ var position: Vector2
+ var radius: float
+ var color: Color
+ var width: float
+ var filled: bool
+ var antialiased: bool
+ var opacity: float:
+ set(value):
+ opacity = value
+ self.color.a = opacity
+
+ func _init(_position: Vector2, _radius: float, _width: float = -1.0, _filled: bool = true, _color: Color = Color.WHITE, _opacity: float = 1.0, _antialiased: bool = true):
+ self.position = _position
+ self.radius = _radius
+ self.color = _color
+ self.width = _width
+ self.filled = _filled
+ self.antialiased = _antialiased
+ self.opacity = _opacity
+ self.color.a = _opacity
+
+ func draw(canvas_item: CanvasItem, offset: bool) -> void:
+ var pos = self.position + (Vector2(self.radius, self.radius) if offset else Vector2.ZERO)
+ canvas_item.draw_circle(pos, self.radius, self.color, self.filled, self.width, self.antialiased)
+#endregion Classes ===================================================
diff --git a/src/addons/virtual_joystick/virtual_joystick.gd.uid b/src/addons/virtual_joystick/virtual_joystick.gd.uid
new file mode 100644
index 0000000..5acc943
--- /dev/null
+++ b/src/addons/virtual_joystick/virtual_joystick.gd.uid
@@ -0,0 +1 @@
+uid://dhn1uax7qtt1v
diff --git a/src/export_presets.cfg b/src/export_presets.cfg
index e5bccec..12cf959 100644
--- a/src/export_presets.cfg
+++ b/src/export_presets.cfg
@@ -69,3 +69,53 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"
+
+[preset.1]
+
+name="Web"
+platform="Web"
+runnable=true
+dedicated_server=false
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path="../export/www/index.html"
+patches=PackedStringArray()
+patch_delta_encoding=false
+patch_delta_compression_level_zstd=19
+patch_delta_min_reduction=0.1
+patch_delta_include_filters="*"
+patch_delta_exclude_filters=""
+encryption_include_filters=""
+encryption_exclude_filters=""
+seed=0
+encrypt_pck=false
+encrypt_directory=false
+script_export_mode=2
+
+[preset.1.options]
+
+custom_template/debug=""
+custom_template/release=""
+variant/extensions_support=false
+variant/thread_support=true
+vram_texture_compression/for_desktop=true
+vram_texture_compression/for_mobile=false
+html/export_icon=true
+html/custom_html_shell=""
+html/head_include=""
+html/canvas_resize_policy=2
+html/focus_canvas_on_start=true
+html/experimental_virtual_keyboard=false
+progressive_web_app/enabled=false
+progressive_web_app/ensure_cross_origin_isolation_headers=true
+progressive_web_app/offline_page=""
+progressive_web_app/display=1
+progressive_web_app/orientation=1
+progressive_web_app/icon_144x144=""
+progressive_web_app/icon_180x180=""
+progressive_web_app/icon_512x512=""
+progressive_web_app/background_color=Color(0, 0, 0, 1)
+threads/emscripten_pool_size=8
+threads/godot_pool_size=4
diff --git a/src/project.godot b/src/project.godot
index 5b5d96f..26a9571 100644
--- a/src/project.godot
+++ b/src/project.godot
@@ -32,6 +32,10 @@ window/size/viewport_height=720
window/stretch/mode="canvas_items"
window/stretch/scale_mode="integer"
+[editor_plugins]
+
+enabled=PackedStringArray("res://addons/touchscreenbuttoncontrol/plugin.cfg", "res://addons/virtual_joystick/plugin.cfg")
+
[input]
move_left={
@@ -74,6 +78,10 @@ attack={
]
}
+[input_devices]
+
+pointing/emulate_touch_from_mouse=true
+
[physics]
3d/physics_engine="Jolt Physics"
diff --git a/src/scenes/chat_ui.tscn b/src/scenes/chat_ui.tscn
index a5d0b53..b88616d 100644
--- a/src/scenes/chat_ui.tscn
+++ b/src/scenes/chat_ui.tscn
@@ -12,15 +12,6 @@ layer = 200
script = ExtResource("1_chat_ui")
[node name="ChatContainer" type="Control" parent="." unique_id=-1294967296]
-layout_mode = 3
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-mouse_filter = 1
-
-[node name="BottomLeft" type="MarginContainer" parent="ChatContainer" unique_id=-294967296]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
@@ -31,6 +22,16 @@ offset_right = 400.0
offset_bottom = -10.0
grow_horizontal = 0
grow_vertical = 0
+mouse_filter = 1
+
+[node name="BottomLeft" type="MarginContainer" parent="ChatContainer" unique_id=-294967296]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 1
[node name="Background" type="ColorRect" parent="ChatContainer/BottomLeft" unique_id=705032704]
visible = false
@@ -40,16 +41,21 @@ color = Color(0, 0, 0, 0.5)
[node name="VBox" type="VBoxContainer" parent="ChatContainer/BottomLeft" unique_id=1705032704]
layout_mode = 2
+mouse_filter = 2
[node name="MessageScroll" type="ScrollContainer" parent="ChatContainer/BottomLeft/VBox" unique_id=-1589934592]
custom_minimum_size = Vector2(380, 150)
layout_mode = 2
size_flags_vertical = 3
+mouse_filter = 1
+scroll_horizontal_enabled = false
+scroll_vertical_enabled = true
[node name="MessageList" type="VBoxContainer" parent="ChatContainer/BottomLeft/VBox/MessageScroll" unique_id=-589934592]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
+mouse_filter = 1
[node name="ChatInput" type="LineEdit" parent="ChatContainer/BottomLeft/VBox" unique_id=1410065408]
visible = false
diff --git a/src/scenes/game_world.tscn b/src/scenes/game_world.tscn
index 5293148..e0233c6 100644
--- a/src/scenes/game_world.tscn
+++ b/src/scenes/game_world.tscn
@@ -4,7 +4,6 @@
[ext_resource type="PackedScene" uid="uid://cxfvw8y7jqn2p" path="res://scenes/player.tscn" id="2"]
[ext_resource type="Script" uid="uid://db58xcyo4cjk" path="res://scripts/game_world.gd" id="4"]
[ext_resource type="Script" uid="uid://wff5063ctp7g" path="res://scripts/debug_overlay.gd" id="5"]
-[ext_resource type="Script" path="res://scripts/room_lighting_system.gd" id="6"]
[ext_resource type="AudioStream" uid="uid://dthr2w8x0cj6v" path="res://assets/audio/sfx/ambience/wind-castle-loop.wav.mp3" id="6_6c6v5"]
[ext_resource type="TileSet" uid="uid://dqem5tbvooxrg" path="res://assets/gfx/RPG DUNGEON VOL 3.tres" id="9"]
@@ -40,8 +39,5 @@ light_mask = 1048575
visibility_layer = 1048575
color = Color(0.4140625, 0.4140625, 0.4140625, 1)
-[node name="RoomLightingSystem" type="Node2D" parent="." unique_id=1234567893]
-script = ExtResource("6")
-
[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." unique_id=1141138343]
stream = ExtResource("6_6c6v5")
diff --git a/src/scenes/ingame_hud.tscn b/src/scenes/ingame_hud.tscn
index e6b574e..753e39b 100644
--- a/src/scenes/ingame_hud.tscn
+++ b/src/scenes/ingame_hud.tscn
@@ -3,7 +3,13 @@
[ext_resource type="Script" uid="uid://da5sp508nk1tx" path="res://scripts/ingame_hud.gd" id="1_hud_script"]
[ext_resource type="FontFile" uid="uid://bajcvmidrnc33" path="res://assets/fonts/standard_font.png" id="2_standard_font"]
[ext_resource type="Texture2D" uid="uid://dkisxs8ecfaul" path="res://assets/gfx/ui/hearts_filled.png" id="4_hearts_filled"]
+[ext_resource type="Script" uid="uid://5hepk3l8u2eg" path="res://scripts/mobile_input.gd" id="5_44yxk"]
+[ext_resource type="Script" uid="uid://dhn1uax7qtt1v" path="res://addons/virtual_joystick/virtual_joystick.gd" id="5_i0hld"]
[ext_resource type="Texture2D" uid="uid://dkpritx47nd4m" path="res://assets/gfx/pickups/items_n_shit.png" id="5_key_texture"]
+[ext_resource type="Texture2D" uid="uid://01qhightlcso" path="res://addons/virtual_joystick/resources/textures/joystick_texture_5.png" id="6_yeruy"]
+[ext_resource type="Texture2D" uid="uid://dywm4x5vqdtsm" path="res://addons/virtual_joystick/resources/textures/stick_texture_5.png" id="7_44yxk"]
+[ext_resource type="Script" uid="uid://bh5a3ydiu51eo" path="res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd" id="8_cu5yl"]
+[ext_resource type="StyleBox" uid="uid://cv5o175a2677e" path="res://addons/touchscreenbuttoncontrol/button_style.tres" id="8_yeruy"]
[sub_resource type="Theme" id="Theme_standard_font"]
default_font = ExtResource("2_standard_font")
@@ -15,6 +21,7 @@ region = Rect2(160, 208, 16, 16)
margin = Rect2(0, -2, 0, 0)
[node name="IngameHUD" type="CanvasLayer" unique_id=846985801]
+layer = 201
script = ExtResource("1_hud_script")
[node name="UpperLeft" type="MarginContainer" parent="." unique_id=22752255]
@@ -128,3 +135,149 @@ horizontal_alignment = 1
[node name="TextureProgressBarBossHP" type="TextureProgressBar" parent="UpperRight/HBoxContainer/VBoxContainerBoss" unique_id=1266602557]
layout_mode = 2
texture_progress = ExtResource("4_hearts_filled")
+
+[node name="MobileInput" type="Control" parent="." unique_id=1373461519]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 1
+script = ExtResource("5_44yxk")
+
+[node name="VirtualJoystick" type="Control" parent="MobileInput" unique_id=1151061008]
+z_index = 4096
+layout_mode = 1
+anchors_preset = 4
+anchor_top = 0.5
+anchor_bottom = 0.5
+offset_left = 48.0
+offset_top = -114.0
+offset_right = 250.0
+offset_bottom = 88.0
+grow_vertical = 2
+pivot_offset = Vector2(101, 101)
+script = ExtResource("5_i0hld")
+joystick_texture = ExtResource("6_yeruy")
+joystick_opacity = 0.235
+stick_texture = ExtResource("7_44yxk")
+stick_opacity = 0.746
+metadata/_custom_type_script = "uid://dhn1uax7qtt1v"
+
+[node name="Control" type="Control" parent="MobileInput" unique_id=131649841]
+layout_mode = 1
+anchors_preset = 6
+anchor_left = 1.0
+anchor_top = 0.5
+anchor_right = 1.0
+anchor_bottom = 0.5
+offset_left = -40.0
+offset_top = -20.0
+offset_bottom = 20.0
+grow_horizontal = 0
+grow_vertical = 2
+
+[node name="MarginContainer" type="MarginContainer" parent="MobileInput/Control" unique_id=710364056]
+layout_mode = 1
+anchors_preset = 6
+anchor_left = 1.0
+anchor_top = 0.5
+anchor_right = 1.0
+anchor_bottom = 0.5
+offset_left = -205.765
+offset_top = -94.475
+offset_right = -5.7649994
+offset_bottom = 25.525024
+grow_horizontal = 0
+grow_vertical = 2
+theme_override_constants/margin_right = 42
+
+[node name="B_ButtonContainer" type="Control" parent="MobileInput/Control/MarginContainer" unique_id=297390115]
+layout_mode = 2
+
+[node name="B_Circle" type="Panel" parent="MobileInput/Control/MarginContainer/B_ButtonContainer" unique_id=2138926309]
+layout_mode = 1
+anchors_preset = 4
+anchor_top = 0.5
+anchor_bottom = 0.5
+offset_top = -32.0
+offset_right = 64.0
+offset_bottom = 32.0
+grow_vertical = 2
+theme_override_styles/panel = ExtResource("8_yeruy")
+
+[node name="B_Label" type="Label" parent="MobileInput/Control/MarginContainer/B_ButtonContainer/B_Circle" unique_id=1440094044]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+text = "B"
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[node name="TouchScreenButtonControl" type="TextureButton" parent="MobileInput/Control/MarginContainer/B_ButtonContainer/B_Circle" unique_id=1583063757]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+focus_mode = 0
+mouse_filter = 2
+action_mode = 0
+ignore_texture_size = true
+stretch_mode = 5
+script = ExtResource("8_cu5yl")
+touchscreen_only = true
+input_action = "attack"
+metadata/_custom_type_script = "uid://bh5a3ydiu51eo"
+
+[node name="A_ButtonContainer" type="Control" parent="MobileInput/Control/MarginContainer" unique_id=1039434657]
+layout_mode = 2
+
+[node name="A_Circle" type="Panel" parent="MobileInput/Control/MarginContainer/A_ButtonContainer" unique_id=1415076009]
+layout_mode = 1
+anchors_preset = 6
+anchor_left = 1.0
+anchor_top = 0.5
+anchor_right = 1.0
+anchor_bottom = 0.5
+offset_left = -64.0
+offset_top = -32.0
+offset_bottom = 32.0
+grow_horizontal = 0
+grow_vertical = 2
+theme_override_styles/panel = ExtResource("8_yeruy")
+
+[node name="A_Label" type="Label" parent="MobileInput/Control/MarginContainer/A_ButtonContainer/A_Circle" unique_id=619215455]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+text = "A"
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[node name="TouchScreenButtonControl" type="TextureButton" parent="MobileInput/Control/MarginContainer/A_ButtonContainer/A_Circle" unique_id=322194330]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+focus_mode = 0
+mouse_filter = 2
+action_mode = 0
+ignore_texture_size = true
+stretch_mode = 5
+script = ExtResource("8_cu5yl")
+touchscreen_only = true
+input_action = "grab"
+metadata/_custom_type_script = "uid://bh5a3ydiu51eo"
+
+[connection signal="analogic_changed" from="MobileInput/VirtualJoystick" to="MobileInput" method="_on_virtual_joystick_analogic_changed"]
diff --git a/src/scenes/test.tscn b/src/scenes/test.tscn
new file mode 100644
index 0000000..14164e9
--- /dev/null
+++ b/src/scenes/test.tscn
@@ -0,0 +1,20 @@
+[gd_scene format=3 uid="uid://o8cbi1whsbo0"]
+
+[ext_resource type="Script" uid="uid://dhn1uax7qtt1v" path="res://addons/virtual_joystick/virtual_joystick.gd" id="1_iyx0m"]
+[ext_resource type="Texture2D" uid="uid://01qhightlcso" path="res://addons/virtual_joystick/resources/textures/joystick_texture_5.png" id="2_74lek"]
+[ext_resource type="Texture2D" uid="uid://dywm4x5vqdtsm" path="res://addons/virtual_joystick/resources/textures/stick_texture_5.png" id="3_j5jx5"]
+
+[node name="Test" type="Node2D" unique_id=459289533]
+
+[node name="VirtualJoystick" type="Control" parent="." unique_id=322625393]
+layout_mode = 3
+anchors_preset = 0
+offset_left = 391.0
+offset_top = 172.0
+offset_right = 611.0
+offset_bottom = 392.0
+pivot_offset = Vector2(110, 110)
+script = ExtResource("1_iyx0m")
+joystick_texture = ExtResource("2_74lek")
+stick_texture = ExtResource("3_j5jx5")
+metadata/_custom_type_script = "uid://dhn1uax7qtt1v"
diff --git a/src/scripts/chat_ui.gd b/src/scripts/chat_ui.gd
index f031d86..972728a 100644
--- a/src/scripts/chat_ui.gd
+++ b/src/scripts/chat_ui.gd
@@ -57,7 +57,7 @@ func _ready():
visible = true # Chat UI is always visible (background and messages fade)
- # Hide scrollbar by default (will show when chat is opened)
+ # Hide scrollbar permanently
if message_scroll:
var scroll_bar = message_scroll.get_v_scroll_bar()
if scroll_bar:
@@ -71,6 +71,23 @@ func _input(event):
else:
_send_and_close_chat()
get_viewport().set_input_as_handled()
+
+ # Don't consume touch events outside chat area - let them pass through to joystick
+ # Only consume keyboard events for chat
+ if event is InputEventScreenTouch or event is InputEventScreenDrag:
+ # Check if touch is in chat area
+ if chat_container:
+ var bottom_left = chat_container.get_node_or_null("BottomLeft")
+ if bottom_left:
+ var chat_rect = bottom_left.get_global_rect()
+ if event is InputEventScreenTouch:
+ if not chat_rect.has_point(event.position):
+ # Touch is outside chat area, don't consume it
+ return
+ elif event is InputEventScreenDrag:
+ if not chat_rect.has_point(event.position):
+ # Drag is outside chat area, don't consume it
+ return
func _open_chat():
chat_open = true
@@ -79,11 +96,15 @@ func _open_chat():
chat_input.grab_focus()
background.visible = true
- # Show scrollbar when chat is open
+ # Enable scrolling when chat is open
if message_scroll:
+ message_scroll.mouse_filter = Control.MOUSE_FILTER_STOP # Allow scrolling
+ # Keep scrollbar hidden
var scroll_bar = message_scroll.get_v_scroll_bar()
if scroll_bar:
- scroll_bar.visible = true
+ scroll_bar.visible = false
+ if message_list:
+ message_list.mouse_filter = Control.MOUSE_FILTER_STOP # Allow interaction
# Make all messages fully visible when chat is opened
_show_all_messages()
@@ -101,11 +122,15 @@ func _send_and_close_chat():
chat_input.visible = false
chat_input.release_focus()
- # Hide scrollbar when chat is closed
+ # Disable scrolling when chat is closed (so it doesn't block joystick)
if message_scroll:
+ message_scroll.mouse_filter = Control.MOUSE_FILTER_IGNORE # Don't block input
+ # Keep scrollbar hidden
var scroll_bar = message_scroll.get_v_scroll_bar()
if scroll_bar:
scroll_bar.visible = false
+ if message_list:
+ message_list.mouse_filter = Control.MOUSE_FILTER_IGNORE # Don't block input
# Unlock player controls
_lock_player_controls(false)
diff --git a/src/scripts/game_world.gd b/src/scripts/game_world.gd
index 38bfa0f..889631f 100644
--- a/src/scripts/game_world.gd
+++ b/src/scripts/game_world.gd
@@ -688,11 +688,6 @@ func _generate_dungeon():
# Restore players (make visible and restore collision)
_restore_all_players()
- # Reinitialize room lighting system for new level
- var room_lighting = get_node_or_null("RoomLightingSystem")
- if room_lighting and room_lighting.has_method("reinitialize"):
- room_lighting.reinitialize()
-
# Update camera immediately to ensure it's looking at the players
await get_tree().process_frame # Wait a frame for players to be fully in scene tree
_update_camera()
@@ -1141,11 +1136,6 @@ func _sync_dungeon(dungeon_data_sync: Dictionary, seed_value: int, level: int, h
# Spawn room triggers on client
_spawn_room_triggers()
- # Reinitialize room lighting system for new level (client)
- var room_lighting = get_node_or_null("RoomLightingSystem")
- if room_lighting and room_lighting.has_method("reinitialize"):
- room_lighting.reinitialize()
-
# Wait a frame to ensure all enemies and objects are properly added to scene tree and initialized
await get_tree().process_frame
await get_tree().process_frame # Wait an extra frame to ensure enemies are fully ready
diff --git a/src/scripts/inspiration_scripts/coin.gd b/src/scripts/inspiration_scripts/coin.gd
deleted file mode 100644
index 7c5d361..0000000
--- a/src/scripts/inspiration_scripts/coin.gd
+++ /dev/null
@@ -1,161 +0,0 @@
-extends CharacterBody2D
-
-var friction = 8.0 # Lower values make the slowdown more gradual
-var is_collected = false
-var bounceTimer = 0.0
-var timeBeforePickup = 0.8
-@onready var damage_number_scene = preload("res://assets/scripts/components/damage_number.tscn")
-
-# Z-axis variables
-var positionZ = 4.0 # Start slightly in the air
-var velocityZ = 10.0 # Initial upward velocity
-var accelerationZ = -300.0 # Gravity
-var bounceRestitution = 0.6 # How much bounce energy is retained (0-1)
-var minBounceVelocity = 40.0 # Minimum velocity needed to bounce
-
-var bodyToPickUp:Node2D = null
-
-var sync_position := Vector2()
-var sync_velocity := Vector2()
-var sync_positionZ: float = 4.0
-var sync_velocityZ: float = 10.0
-
-func _ready() -> void:
- add_to_group("coins")
- $Area2DCollision.set_deferred("monitoring", false)
- update_sprite_scale()
-
- # Start animation
- $AnimationPlayer.play("idle")
-
-func _process(delta: float) -> void:
- if bodyToPickUp != null and !is_collected and timeBeforePickup == 0 and positionZ < 5:
- visible = false
- $SfxCoinCollect.play()
- is_collected = true
- $Area2DCollision.set_deferred("monitoring", false)
-
- var damage_number = damage_number_scene.instantiate() as Label
- if damage_number:
- get_tree().current_scene.add_child(damage_number)
- damage_number.global_position = global_position + Vector2(0, -16)
- if "direction" in damage_number:
- damage_number.direction = Vector2(0, -1)
- damage_number.move_duration = 1.0
- if "label" in damage_number:
- damage_number.label = "+1 COIN"
- if "color" in damage_number:
- damage_number.color = Color.YELLOW
- if "stats" in bodyToPickUp:
- bodyToPickUp.stats.add_coin(1)
- await $SfxCoinCollect.finished
- call_deferred("queue_free")
- return
- if is_collected:
- return
- if timeBeforePickup > 0.0:
- timeBeforePickup -= delta
- if timeBeforePickup < 0:
- $Area2DCollision.set_deferred("monitoring", true)
- timeBeforePickup = 0
- if bounceTimer > 0.0:
- bounceTimer -= delta
- if bounceTimer < 0:
- bounceTimer = 0
-
- # Update vertical movement
- velocityZ += accelerationZ * delta
- positionZ += velocityZ * delta
-
- # Ground collision and bounce
- if positionZ <= 0:
- velocity = velocity.lerp(Vector2.ZERO, 1.0 - exp(-friction * delta)) # only slow down if on floor
- positionZ = 0
- if abs(velocityZ) > minBounceVelocity:
- #print(velocityZ)
- $SfxCoinBounce.volume_db = -1 + (-10 - (velocityZ * 0.1))
- $SfxCoinBounce.play()
- velocityZ = -velocityZ * bounceRestitution
- else:
- velocityZ = 0
-
- update_sprite_scale()
- move_and_slide()
-'
-func _physics_process(delta: float) -> void:
- if multiplayer.is_server():
- for peer_id in multiplayer.get_peers():
- sync_coin.rpc_id(peer_id, position, velocity, positionZ, velocityZ)
- if !multiplayer.is_server():
- position = position.lerp(sync_position, delta * 15.0)
- velocity = velocity.lerp(sync_velocity, delta * 15.0)
- positionZ = sync_positionZ
- velocityZ = sync_velocityZ
- if positionZ <= 0:
- velocity = velocity.lerp(Vector2.ZERO, 1.0 - exp(-friction * delta)) # only slow down if on floor
- positionZ = 0
- if abs(velocityZ) > minBounceVelocity:
- #print(velocityZ)
- $SfxCoinBounce.volume_db = -1 + (-10 - (velocityZ * 0.1))
- $SfxCoinBounce.play()
-
- update_sprite_scale()
- pass
-'
-@rpc("unreliable")
-func sync_coin(pos: Vector2, vel: Vector2, posZ: float, velZ: float):
- sync_position = pos
- sync_velocity = vel
- sync_positionZ = posZ
- sync_velocityZ = velZ
- pass
-
-func update_sprite_scale() -> void:
- # Calculate scale based on height
- # Maximum height will have scale 1.3, ground will have scale 1.0
- var height_factor = positionZ / 50.0 # Assuming 20 is max height
- var posY = 0.0 + (2 * positionZ)
- var sc = 1.0 + (0.8 * height_factor)
- $Sprite2D.scale = Vector2(sc, sc)
- $Sprite2D.position.y = -posY
-
-func _on_area_2d_collision_body_entered(_body: Node2D) -> void:
- if bounceTimer == 0:
- $SfxCoinBounce.play()
- bounceTimer = 0.08
- # inverse the direction and slow down slightly
- var collision_shape = $Area2DCollision.get_overlapping_bodies()
-
- if collision_shape.size() > 0:
- var collider = collision_shape[0]
- var normal = (global_position - collider.global_position).normalized()
- velocity = velocity.bounce(normal)
-
- pass # Replace with function body.
-
-@rpc("any_peer", "reliable")
-func pick_up(_char: CharacterBody2D):
- # does nothing... handled by coin itself!
- return false
-
-func _on_area_2d_pickup_body_entered(body: Node2D) -> void:
- if !is_collected:
- bodyToPickUp = body.get_parent()
-
- pass # Replace with function body.
-
-
-func _on_area_2d_pickup_body_exited(_body: Node2D) -> void:
- bodyToPickUp = null
- pass # Replace with function body.
-
-
-func _on_area_2d_pickup_area_entered(area: Area2D) -> void:
- if !is_collected:
- bodyToPickUp = area.get_parent()
- pass # Replace with function body.
-
-
-func _on_area_2d_pickup_area_exited(_area: Area2D) -> void:
- bodyToPickUp = null
- pass # Replace with function body.
diff --git a/src/scripts/inspiration_scripts/coin.gd.uid b/src/scripts/inspiration_scripts/coin.gd.uid
deleted file mode 100644
index c6c4820..0000000
--- a/src/scripts/inspiration_scripts/coin.gd.uid
+++ /dev/null
@@ -1 +0,0 @@
-uid://dxkd5t8jbbmdm
diff --git a/src/scripts/inspiration_scripts/dungeon_generator.gd b/src/scripts/inspiration_scripts/dungeon_generator.gd
deleted file mode 100644
index 8ebf198..0000000
--- a/src/scripts/inspiration_scripts/dungeon_generator.gd
+++ /dev/null
@@ -1,617 +0,0 @@
-extends RefCounted # Using RefCounted instead of Node since this is a utility class
-
-enum DUNGEON_ENTITY_TYPES {
- ENEMY,
- OBJECT,
- TRAP
-}
-
-# Constants
-const DOOR_MODIFIERS = [
- {"name": "Locked Door", "type": "Locked"},
- {"name": "Bomb Wall", "type": "Bombable"}
-]
-
-const FLOOR_TILES = [
- 7,8,9,10,11,12,
- 25,26,27,28,29,30,31,
- 44,45,46,47,48,49,50,
- 63,64,65,66,67,68,69
-]
-
-const WALL_VARIATIONS = [
- 0.45,
- 0.15,
- 0.15,
- 0.15,
- 0.1
-]
-
-const OBJECT_TYPES = [
- {"name": "Barrel", "ti": [70], "ti2": [89], "openable": false, "liftable": true, "throwable": false, "hp": - 1, "pushable": true, "size": {"x": 1, "y": 1}},
- {"name": "Pot", "ti": [13, 14, 15], "ti2": [51, 52, 53], "openable": false, "liftable": true, "throwable": true, "hp": 1, "pushable": true, "size": {"x": 1, "y": 1}},
- {"name": "Chest", "ti": [108], "ti2": [127], "openable": true, "liftable": false, "throwable": false, "hp": - 1, "pushable": false, "size": {"x": 1, "y": 1}},
- {"name": "Bench", "ti": [35, 36], "ti2": [16, 17], "openable": false, "liftable": false, "throwable": false, "hp": - 1, "pushable": false, "size": {"x": 2, "y": 1}}
-]
-
-const MONSTER_TYPES = [
- {
- "name": "Goblin",
- },
- {
- "name": "Slime",
- },
- # ... other monster types similar to JS version
-]
-
-const TRAP_TYPES = [
- {"name": "Spike Trap", "description": "Spikes shoot up from the floor when triggered."},
- {"name": "Arrow Trap", "description": "Arrows fire from the walls when a player steps on a pressure plate."},
- # ... other trap types
-]
-
-const ROOM_MODIFIERS = [
- {"name": "Player Start", "description": "The players start here.", "type": "START", "negative_modifiers": {"min": 0, "max": 0}},
- {"name": "Exit", "description": "Room contains an exit.", "type": "EXIT", "negative_modifiers": {"min": 0, "max": 0}},
- # ... other room modifiers
-]
-
-# Main generation function
-func generate_dungeon(map_size: Vector2, _num_rooms: int, min_room_size: int, max_room_size: int) -> Dictionary:
- # Initialize grid
- var grid = []
- var randgrid = []
- for x in range(map_size.x):
- grid.append([])
- randgrid.append([])
- for y in range(map_size.y):
- grid[x].append(0)
- randgrid[x].append(0)
-
- var all_rooms = []
- var all_doors = []
-
- # 1. Create first room at a random position
- var first_w = rand_range_i(min_room_size, max_room_size)
- var first_h = rand_range_i(min_room_size, max_room_size)
- var first_room = {
- "x": rand_range_i(4, map_size.x - first_w - 4), # Random position with buffer
- "y": rand_range_i(4, map_size.y - first_h - 4),
- "w": first_w,
- "h": first_h,
- "modifiers": []
- }
-
- set_floor(first_room, grid, map_size)
- all_rooms.append(first_room)
-
- var nrOfDoorErrors = 0
- var nrOfRoomErrors = 0
-
- # 2. Try to place rooms until we can't fit any more
- var attempts = 1000 # Prevent infinite loops
- while attempts > 0 and all_rooms.size() > 0:
- # Pick a random existing room
- var source_room = all_rooms[randi() % all_rooms.size()]
-
- # Try to place a new room near it
- var new_room = try_place_room_near(source_room, grid, map_size, min_room_size, max_room_size)
- if new_room.w > 0: # Valid room created
- set_floor(new_room, grid, map_size)
- all_rooms.append(new_room)
-
- attempts -= 1
- if attempts <= 0:
- nrOfRoomErrors += 1
- break
-
- # 3. Connect rooms with corridors/doors
- if all_rooms.size() > 1:
- var connected_rooms = {}
- for room in all_rooms:
- connected_rooms[room] = []
-
- # First pass: try to connect each room to its closest neighbors
- for room in all_rooms:
- var closest_rooms = find_closest_rooms(room, all_rooms)
- #print("Connecting room at ", room.x, ",", room.y)
-
- var connection_attempts = 0
- var max_connection_attempts = 3 # Try to connect to multiple neighbors
-
- for target_room in closest_rooms:
- if connection_attempts >= max_connection_attempts:
- break
-
- if not rooms_are_connected(room, target_room, all_doors):
- var door = create_corridor_between_rooms(room, target_room, grid)
- if door.size() > 0:
- #print("Created direct connection between rooms")
- set_door(door, grid)
- all_doors.append(door)
- connected_rooms[room].append(target_room)
- connected_rooms[target_room].append(room)
- connection_attempts += 1
-
- # Second pass: ensure all rooms are connected
- var attempts2 = 100
- while attempts2 > 0:
- var reachable = find_reachable_rooms(all_rooms[0], all_rooms, all_doors)
- #print("Reachable rooms: ", reachable.size(), "/", all_rooms.size())
-
- if reachable.size() == all_rooms.size():
- #print("All rooms connected!")
- break
-
- # Find an unreachable room and try to connect it
- for room in all_rooms:
- if not reachable.has(room):
- var connected = false
-
- # Try to connect to each reachable room until success
- for target_room in reachable:
- var door = create_corridor_between_rooms(room, target_room, grid)
- if door.size() > 0:
- set_door(door, grid)
- all_doors.append(door)
- connected = true
- break
-
- if not connected:
- # Try creating intermediate room with multiple positions
- for offset_x in [-2, 0, 2]:
- for offset_y in [-2, 0, 2]:
- var mid_room = create_intermediate_room(room, reachable[0], offset_x, offset_y)
- if is_valid_room_position(mid_room, grid, map_size):
- set_floor(mid_room, grid, map_size)
- all_rooms.append(mid_room)
-
- var door1 = create_corridor_between_rooms(room, mid_room, grid)
- var door2 = create_corridor_between_rooms(mid_room, reachable[0], grid)
-
- if door1.size() > 0 and door2.size() > 0:
- set_door(door1, grid)
- set_door(door2, grid)
- all_doors.append(door1)
- all_doors.append(door2)
- connected = true
- break
- if connected:
- break
-
- if connected:
- break
-
- attempts2 -= 1
- if attempts2 <= 0:
- nrOfDoorErrors += 1
- break
-
- for x in range(map_size.x):
- for y in range(map_size.y):
- if grid[x][y] == 0: # wall
- var rand = randf()
- var sum:float = 0.0
- for i in WALL_VARIATIONS.size():
- sum += WALL_VARIATIONS[i];
- if rand <= sum:
- randgrid[x][y] = i
- break
- elif grid[x][y] == 1: # floor
- if randf() < 0.6:
- randgrid[x][y] = 0
- else:
- randgrid[x][y] = randi_range(1,FLOOR_TILES.size()-1)
- elif grid[x][y] == 2: # door
- randgrid[x][y] = 0 # we dont care about these... only have 1 variant
-
- var startRoomIndex = randi_range(0,all_rooms.size()-1)
- all_rooms[startRoomIndex].modifiers.push_back(ROOM_MODIFIERS[0])
-
- var farthestRoom = null
- var maxDistance = 0
- var exitRoomIndex = -1
- var roomIndex = 0
- for r in all_rooms:
- var distance = abs(r.x - all_rooms[startRoomIndex].x) + abs(r.y - all_rooms[startRoomIndex].y)
- if (distance > maxDistance):
- maxDistance = distance
- farthestRoom = r
- exitRoomIndex = roomIndex
- roomIndex+=1
- pass
-
- farthestRoom.modifiers.push_back(ROOM_MODIFIERS[1])
-
- var entities = []
- var TILE_SIZE = 16
-
- roomIndex = 0
- #populate rooms and decide modifiers for rooms
- for r in all_rooms:
- if roomIndex != startRoomIndex and roomIndex != exitRoomIndex:
- var validRoomLocations = []
- var min_x = (r.x + 1)
- var max_x = ((r.x + r.w) - 1)
- var min_y = (r.y + 1)
- var max_y = ((r.y + r.h) - 1)
- for rw in range(min_x,max_x):
- for rh in range(min_y, max_y):
- validRoomLocations.push_back(Vector2(rw*TILE_SIZE - 8, rh*TILE_SIZE - 8)) # we assume entities are 16x16 are centered
- # bigger rooms can have a larger content number!
- var randNrOfEntities = randi_range(0, 4)
-
- for entI in randNrOfEntities:
-
- var enttype:DUNGEON_ENTITY_TYPES = randi_range(0, DUNGEON_ENTITY_TYPES.size()-1) as DUNGEON_ENTITY_TYPES
- var entStats = {}
- # hand code to only be enemies atm
- if enttype == DUNGEON_ENTITY_TYPES.TRAP:
- enttype = DUNGEON_ENTITY_TYPES.OBJECT
- #enttype = DUNGEON_ENTITY_TYPES.OBJECT ## only objects now...
- var subtype = "goblin"
- if enttype == DUNGEON_ENTITY_TYPES.ENEMY:
- var randType = randi_range(0, 1)
- var cStats = CharacterStats.new()
- if randType == 1:
- cStats.hp = 2
- subtype = "slime"
- else:
- cStats.hp = 3
- cStats.skin = "res://assets/gfx/Puny-Characters/Layer 0 - Skins/Orc1.png"
- cStats.skin = "res://assets/gfx/Puny-Characters/Layer 0 - Skins/Orc2.png"
-
- var hair = 0
- if randf() > 0.6:
- hair = randi_range(1,13)
- cStats.setHair(hair, randi_range(0,8))
- var facialhair = 0
- if randf() > 0.75: # very uncommon for facial hair on goblins
- facialhair = randi_range(1,3)
- cStats.setFacialHair(facialhair, randi_range(0, 4))
-
- #cStats.add_on = "res://assets/gfx/Puny-Characters/Layer 7 - Add-ons/Orc Add-ons/GoblinEars1.png"
- cStats.add_on = "res://assets/gfx/Puny-Characters/Layer 7 - Add-ons/Orc Add-ons/GoblinEars2.png"
- #cStats.add_on = "res://assets/gfx/Puny-Characters/Layer 7 - Add-ons/Orc Add-ons/OrcJaw1.png"
- #cStats.add_on = "res://assets/gfx/Puny-Characters/Layer 7 - Add-ons/Orc Add-ons/OrcJaw2.png"
- # randomize if the goblin will have a weapon like dagger or sword
- # randomize if the goblin will have bow and arrows also
- # randomize if the goblin will have an armour and helmet etc.
-
- entStats = cStats.save()
- elif enttype == DUNGEON_ENTITY_TYPES.OBJECT:
- subtype = "pot"
- else:
- subtype = "spike"
-
- var posI = randi_range(0, validRoomLocations.size()-1)
-
- var entity = {
- "type": enttype,
- "subtype": subtype,
- "stats": entStats,
- "position": {
- "x": validRoomLocations[posI].x,
- "y": validRoomLocations[posI].y
- }
- }
- entities.push_back(entity)
- validRoomLocations.remove_at(posI) # this is now occupied... don't allow anything else spawn on it.
-
- # fill up modifiers per room
- if ROOM_MODIFIERS.size() > 2:
- r.modifiers.push_back(ROOM_MODIFIERS[randi_range(2, ROOM_MODIFIERS.size()-2)])
- pass
- roomIndex += 1
-
-
-
- return {
- "rooms": all_rooms,
- "entities": entities,
- "doors": all_doors,
- "grid": grid,
- "randgrid": randgrid, # grid containing actual tile index-ish(ish)
- "mapSize": map_size,
- "nrOfDoorErrors": nrOfDoorErrors,
- "nrOfRoomErrors": nrOfRoomErrors
- }
-
-# Helper functions
-func create_random_room(map_size: Vector2, min_size: int, max_size: int) -> Dictionary:
- var x = randi() % (int(map_size.x) - max_size - 2) + 1
- var y = randi() % (int(map_size.y) - max_size - 2) + 1
- var w = rand_range_i(min_size, max_size)
- var h = rand_range_i(min_size, max_size)
- return {"x": x, "y": y, "w": w, "h": h, "modifiers": []}
-
-func rand_range_i(min_val: int, max_val: int) -> int:
- return min_val + (randi() % (max_val - min_val + 1))
-
-func set_floor(room: Dictionary, grid: Array, map_size: Vector2) -> void:
- for x in range(room.x, room.x + room.w):
- for y in range(room.y, room.y + room.h):
- if x >= 0 and x < map_size.x and y >= 0 and y < map_size.y:
- grid[x][y] = 1 # Set as floor tile
-
-# ... Additional helper functions and implementation details would follow ...
-# ... previous code ...
-
-func try_place_room_near(source_room: Dictionary, grid: Array, map_size: Vector2,
- min_room_size: int, max_room_size: int) -> Dictionary:
- var attempts = 20
- while attempts > 0:
- var w = rand_range_i(min_room_size, max_room_size)
- var h = rand_range_i(min_room_size, max_room_size)
-
- # Try all four sides of the source room
- var sides = ["N", "S", "E", "W"]
- sides.shuffle()
-
- for side in sides:
- var x = source_room.x
- var y = source_room.y
-
- match side:
- "N":
- x = source_room.x + (randi() % max(1, source_room.w - w))
- y = source_room.y - h - 4 # 4 tiles away
- "S":
- x = source_room.x + (randi() % max(1, source_room.w - w))
- y = source_room.y + source_room.h + 4
- "W":
- x = source_room.x - w - 4
- y = source_room.y + (randi() % max(1, source_room.h - h))
- "E":
- x = source_room.x + source_room.w + 4
- y = source_room.y + (randi() % max(1, source_room.h - h))
-
- if is_valid_room_position({"x": x, "y": y, "w": w, "h": h}, grid, map_size):
- return {"x": x, "y": y, "w": w, "h": h, "modifiers": []}
-
- attempts -= 1
-
- return {"x": 0, "y": 0, "w": 0, "h": 0, "modifiers": []}
-
-func find_closest_rooms(room: Dictionary, all_rooms: Array) -> Array:
- if all_rooms.size() <= 1:
- return []
-
- var distances = []
- for other in all_rooms:
- if other == room:
- continue
- var dist = abs(room.x - other.x) + abs(room.y - other.y)
- distances.append({"room": other, "distance": dist})
-
- # Sort by distance
- if distances.size() > 0:
- distances.sort_custom(func(a, b): return a.distance < b.distance)
- # Return the rooms only, in order of distance
- return distances.map(func(item): return item.room)
-
- return []
-
-func rooms_are_connected(room1: Dictionary, room2: Dictionary, doors: Array) -> bool:
- for door in doors:
- if (door.room1 == room1 and door.room2 == room2) or \
- (door.room1 == room2 and door.room2 == room1):
- return true
- return false
-
-func create_corridor_between_rooms(room1: Dictionary, room2: Dictionary, _grid: Array) -> Dictionary:
- # Determine if rooms are more horizontal or vertical from each other
- var dx = abs(room2.x - room1.x)
- var dy = abs(room2.y - room1.y)
-
- # Check if rooms are too far apart (more than 8 tiles)
- if dx > 8 and dy > 8:
- return {}
-
- if dx > dy:
- # Horizontal corridor
- var leftRoom = room1 if room1.x < room2.x else room2
- var rightRoom = room2 if room1.x < room2.x else room1
-
- # Check if rooms are horizontally adjacent (gap should be reasonable)
- if rightRoom.x - (leftRoom.x + leftRoom.w) > 8:
- return {}
-
- # Door must start at the right edge of left room plus 1 tile gap
- var door_x = leftRoom.x + leftRoom.w
-
- # Door y must be within both rooms' height ranges, accounting for walls
- var min_y = max(leftRoom.y + 1, rightRoom.y + 1) # +1 to account for walls
- var max_y = min(leftRoom.y + leftRoom.h - 2, rightRoom.y + rightRoom.h - 2) # -2 to ensure both tiles fit
-
- # Make sure we have a valid range
- if max_y < min_y:
- return {}
-
- # Pick a valid y position within the range
- var door_y = min_y + (randi() % max(1, max_y - min_y + 1))
-
- # Calculate actual width needed (distance between rooms)
- var door_width = rightRoom.x - (leftRoom.x + leftRoom.w + 1)
- # Use the larger of minimum width (4) or actual distance
- door_width = max(4, door_width + 1)
-
- # Create door with calculated width
- var door = {
- "x": door_x,
- "y": door_y,
- "w": door_width, # Use calculated width
- "h": 2, # Fixed height for horizontal doors
- "dir": "E" if leftRoom == room1 else "W",
- "room1": room1,
- "room2": room2
- }
-
- return door
- else:
- # Vertical corridor
- var topRoom = room1 if room1.y < room2.y else room2
- var bottomRoom = room2 if room1.y < room2.y else room1
-
- # Check if rooms are vertically adjacent (gap should be reasonable)
- if bottomRoom.y - (topRoom.y + topRoom.h) > 8:
- return {}
-
- # Door must start at the bottom edge of top room plus 1 tile gap
- var door_y = topRoom.y + topRoom.h
-
- # Door x must be within both rooms' width ranges, accounting for walls
- var min_x = max(topRoom.x + 1, bottomRoom.x + 1) # +1 to account for walls
- var max_x = min(topRoom.x + topRoom.w - 2, bottomRoom.x + bottomRoom.w - 2) # -2 to ensure both tiles fit
-
- # Make sure we have a valid range
- if max_x < min_x:
- return {}
-
- # Pick a valid x position within the range
- var door_x = min_x + (randi() % max(1, max_x - min_x + 1))
-
- # Calculate actual height needed (distance between rooms)
- var door_height = bottomRoom.y - (topRoom.y + topRoom.h + 1)
- # Use the larger of minimum height (4) or actual distance
- door_height = max(4, door_height + 1)
-
- # Create door with calculated height
- var door = {
- "x": door_x,
- "y": door_y,
- "w": 2, # Fixed width for vertical doors
- "h": door_height, # Use calculated height
- "dir": "S" if topRoom == room1 else "N",
- "room1": room1,
- "room2": room2
- }
-
- return door
-
-
-func add_room_modifiers(rooms: Array) -> void:
- # Add start room modifier to first room
- rooms[0].modifiers.append(ROOM_MODIFIERS[0]) # START modifier
-
- # Add exit to last room
- rooms[-1].modifiers.append(ROOM_MODIFIERS[1]) # EXIT modifier
-
- # Add random modifiers to other rooms
- for i in range(1, rooms.size() - 1):
- if randf() < 0.3: # 30% chance for a modifier
- var available_modifiers = ROOM_MODIFIERS.slice(2, ROOM_MODIFIERS.size())
- # Only add modifier if there are available ones
- if available_modifiers.size() > 0:
- rooms[i].modifiers.append(available_modifiers[randi() % available_modifiers.size()])
-
-func generate_all_room_objects(rooms: Array, doors: Array) -> Array:
- var room_objects = []
-
- # Generate objects for each room
- for room in rooms:
- var objects = generate_room_objects(room)
- room_objects.append_array(objects)
-
- # Add door modifiers
- for door in doors:
- if randf() < 0.2: # 20% chance for door modifier
- var modifier = DOOR_MODIFIERS[randi() % DOOR_MODIFIERS.size()]
- room_objects.append({
- "type": "Door",
- "x": door.x,
- "y": door.y,
- "modifier": modifier
- })
-
- return room_objects
-
-func generate_room_objects(room: Dictionary) -> Array:
- var objects = []
- var max_objects = int((room.w * room.h) / 16) # Roughly one object per 16 tiles
-
- for _i in range(max_objects):
- if randf() < 0.7: # 70% chance to place each potential object
- var obj_type = OBJECT_TYPES[randi() % OBJECT_TYPES.size()]
- var x = rand_range_i(room.x + 1, room.x + room.w - obj_type.size.x - 1)
- var y = rand_range_i(room.y + 1, room.y + room.h - obj_type.size.y - 1)
-
- # Check if position is free
- var can_place = true
- for obj in objects:
- if abs(obj.x - x) < 2 and abs(obj.y - y) < 2:
- can_place = false
- break
-
- if can_place:
- objects.append({
- "type": obj_type.name,
- "x": x,
- "y": y,
- "properties": obj_type
- })
-
- return objects
-
-func set_door(door: Dictionary, grid: Array) -> void:
- match door.dir:
- "N", "S":
- if door.h > 4:
- # Set 2x4 corridor
- for dx in range(2):
- for dy in range(door.h):
- #if grid[door.x + dx][door.y + dy] != 1: # Don't overwrite room
- grid[door.x + dx][door.y + dy] = 2
- "E", "W":
- if door.w > 4:
- # Set 4x2 corridor
- for dx in range(door.w):
- for dy in range(2):
- #if grid[door.x + dx][door.y + dy] != 1: # Don't overwrite room
- grid[door.x + dx][door.y + dy] = 2
-
-func is_valid_room_position(room: Dictionary, grid: Array, map_size: Vector2) -> bool:
- # Check if room is within map bounds with buffer
- if room.x < 4 or room.y < 4 or room.x + room.w >= map_size.x - 4 or room.y + room.h >= map_size.y - 4:
- #print("Room outside map bounds")
- return false
-
- # Check if room overlaps with existing rooms or corridors
- # Check the actual room area plus 4-tile buffer for spacing
- for x in range(room.x - 4, room.x + room.w + 4):
- for y in range(room.y - 4, room.y + room.h + 4):
- if x >= 0 and x < map_size.x and y >= 0 and y < map_size.y:
- if grid[x][y] != 0: # If tile is not empty
- #print("Room overlaps at ", Vector2(x, y))
- return false
-
- return true
-
-# Add this helper function to check room connectivity
-func find_reachable_rooms(start_room: Dictionary, _all_rooms: Array, all_doors: Array) -> Array:
- var reachable = [start_room]
- var queue = [start_room]
-
- while queue.size() > 0:
- var current = queue.pop_front()
- for door in all_doors:
- var next_room = null
- if door.room1 == current:
- next_room = door.room2
- elif door.room2 == current:
- next_room = door.room1
-
- if next_room != null and not reachable.has(next_room):
- reachable.append(next_room)
- queue.append(next_room)
-
- return reachable
-
-func create_intermediate_room(room1: Dictionary, room2: Dictionary, offset_x: int, offset_y: int) -> Dictionary:
- return {
- "x": room1.x + (room2.x - room1.x) / 2 + offset_x,
- "y": room1.y + (room2.y - room1.y) / 2 + offset_y,
- "w": 6,
- "h": 6,
- "modifiers": []
- }
diff --git a/src/scripts/inspiration_scripts/dungeon_generator.gd.uid b/src/scripts/inspiration_scripts/dungeon_generator.gd.uid
deleted file mode 100644
index e56aab8..0000000
--- a/src/scripts/inspiration_scripts/dungeon_generator.gd.uid
+++ /dev/null
@@ -1 +0,0 @@
-uid://dj0n3aevweyhu
diff --git a/src/scripts/inspiration_scripts/inventory.gd b/src/scripts/inspiration_scripts/inventory.gd
deleted file mode 100644
index 30c4f19..0000000
--- a/src/scripts/inspiration_scripts/inventory.gd
+++ /dev/null
@@ -1,491 +0,0 @@
-extends CanvasLayer
-
-var is_showing_inventory = true
-var finished_tween = true
-
-var selectedItem:Item = null
-var selectedEquipment:Item = null
-var lastPressedItem:Item = null
-var lastPressedType = "Item"
-
-var timerSelect:float = 0.0
-
-func bindInventory():
- if GameManager.character_data.is_connected("character_changed", _charChanged):
- GameManager.character_data.disconnect("character_changed", _charChanged)
- GameManager.character_data.connect("character_changed", _charChanged)
- pass
-
-func _ready() -> void:
-
- is_showing_inventory = false
- var move_range = -119
- $ControlContainer/ControlStats.position.x += move_range
- move_range = 80
- $ControlContainer/ControlInventory.position.x += move_range
- move_range = 33
- $ControlContainer/ControlInfo.position.y += move_range
-
- $ControlContainer.mouse_filter = Control.MOUSE_FILTER_IGNORE
-
-
- # Set up multiplayer peer
- '
- GameManager.host(21212, false)
-
- GameManager.character_data.connect("character_changed", _charChanged)
-
- #$Player.position = Vector2(30, 30)
-
- var item = Item.new()
- item.item_type = Item.ItemType.Equippable
- item.equipment_type = Item.EquipmentType.ARMOUR
- item.item_name = "Leather Armour"
- item.description = "A nice leather armour"
- item.spriteFrame = 12
- item.modifiers["def"] = 2
- item.equipmentPath = "res://assets/gfx/Puny-Characters/Layer 2 - Clothes/Tunic Body/BrownTunic.png"
- GameManager.character_data.add_item(item)
-
-
- var item2 = Item.new()
- item2.item_type = Item.ItemType.Equippable
- item2.equipment_type = Item.EquipmentType.HEADGEAR
- item2.item_name = "Leather helm"
- item2.description = "A nice leather helm"
- item2.spriteFrame = 31
- item2.modifiers["def"] = 1
- item2.equipmentPath = "res://assets/gfx/Puny-Characters/Layer 6 - Headgears/Basic Mage/MageHatRed.png"
- item2.colorReplacements = [
- { "original": Color(255/255.0, 39/255.0, 44/255.0), "replace": Color(255/255.0,106/255.0,39/255.0)},
- { "original": Color(182/255.0, 0, 0), "replace": Color(182/255.0,106/255.0,0)},
- { "original": Color(118/255.0, 1/255.0, 0), "replace": Color(118/255.0,66/255.0,0)},
- { "original": Color(72/255.0, 0, 12/255.0), "replace": Color(72/255.0,34/255.0,0)}
- ]
- GameManager.character_data.add_item(item2)
-
- var item3 = Item.new()
- item3.item_type = Item.ItemType.Equippable
- item3.equipment_type = Item.EquipmentType.MAINHAND
- item3.weapon_type = Item.WeaponType.SWORD
- item3.item_name = "Dagger"
- item3.description = "A sharp dagger"
- item3.spriteFrame = 5*20 + 10
- item3.modifiers["dmg"] = 2
- GameManager.character_data.add_item(item3)
-
- var item4 = Item.new()
- item4.item_type = Item.ItemType.Equippable
- item4.equipment_type = Item.EquipmentType.MAINHAND
- item4.weapon_type = Item.WeaponType.AXE
- item4.item_name = "Hand Axe"
- item4.description = "A sharp hand axe"
- item4.spriteFrame = 5*20 + 11
- item4.modifiers["dmg"] = 4
- GameManager.character_data.add_item(item4)
-
- var item5 = Item.new()
- item5.item_type = Item.ItemType.Equippable
- item5.equipment_type = Item.EquipmentType.OFFHAND
- item5.weapon_type = Item.WeaponType.AMMUNITION
- item5.quantity = 13
- item5.can_have_multiple_of = true
- item5.item_name = "Iron Arrow"
- item5.description = "A sharp arrow made of iron and feathers from pelican birds"
- item5.spriteFrame = 7*20 + 11
- item5.modifiers["dmg"] = 3
- GameManager.character_data.add_item(item5)
-
- var item6 = Item.new()
- item6.item_type = Item.ItemType.Equippable
- item6.equipment_type = Item.EquipmentType.MAINHAND
- item6.weapon_type = Item.WeaponType.BOW
- item6.item_name = "Wooden Bow"
- item6.description = "A wooden bow made of elfish lembas trees"
- item6.spriteFrame = 6*20 + 16
- item6.modifiers["dmg"] = 3
- GameManager.character_data.add_item(item6)
-
- var item7 = Item.new()
- item7.item_type = Item.ItemType.Equippable
- item7.equipment_type = Item.EquipmentType.BOOTS
- item7.weapon_type = Item.WeaponType.NONE
- item7.item_name = "Sandals"
- item7.description = "A pair of shitty sandals"
- item7.equipmentPath = "res://assets/gfx/Puny-Characters/Layer 1 - Shoes/ShoesBrown.png"
- item7.spriteFrame = 2*20 + 10
- item7.modifiers["def"] = 1
- GameManager.character_data.add_item(item7)
- '
-
- # clear default stuff
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.texture = null
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/LabelItemDescription.text = ""
-
- pass
-
-func _charChanged(iChar:CharacterStats):
- # update all stats:
- $ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer/LabelBaseStatsValue.text = str(iChar.level) + "\r\n" + \
- "\r\n" + \
- str(floori(iChar.hp)) + "/" + str(floori(iChar.maxhp)) + "\r\n" + \
- str(floori(iChar.mp)) + "/" + str(floori(iChar.maxmp)) + "\r\n" + \
- "\r\n" + \
- str(iChar.baseStats.str) + "\r\n" + \
- str(iChar.baseStats.dex) + "\r\n" + \
- str(iChar.baseStats.end) + "\r\n" + \
- str(iChar.baseStats.int) + "\r\n" + \
- str(iChar.baseStats.wis) + "\r\n" + \
- str(iChar.baseStats.lck)
-
- $ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer/LabelDerivedStatsValue.text = str(floori(iChar.xp)) + "/" + str(floori(iChar.xp_to_next_level)) + "\r\n" + \
- str(iChar.coin) + "\r\n" + \
- "\r\n" + \
- "\r\n" + \
- "\r\n" + \
- str(iChar.damage) + "\r\n" + \
- str(iChar.defense) + "\r\n" + \
- str(iChar.move_speed) + "\r\n" + \
- str(iChar.attack_speed) + "\r\n" + \
- str(iChar.sight) + "\r\n" + \
- str(iChar.spell_amp) + "\r\n" + \
- str(iChar.crit_chance) + "%"
-
- # read inventory and populate inventory
- var vboxInvent = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory
- for child in vboxInvent.find_child("HBoxControl1").get_children():
- child.get_parent().remove_child(child)
- child.propagate_call("queue_free", [])
- for child in vboxInvent.find_child("HBoxControl2").get_children():
- child.get_parent().remove_child(child)
- child.propagate_call("queue_free", [])
- for child in vboxInvent.find_child("HBoxControl3").get_children():
- child.get_parent().remove_child(child)
- child.propagate_call("queue_free", [])
-
- var selected_tex = preload("res://assets/gfx/ui/inventory_slot_kenny_white.png")
- var styleBoxHover:StyleBox = StyleBoxTexture.new()
- var styleBoxFocused:StyleBox = StyleBoxTexture.new()
- var styleBoxPressed:StyleBox = StyleBoxTexture.new()
- var styleBoxEmpty:StyleBox = StyleBoxEmpty.new()
- styleBoxHover.texture = selected_tex
- styleBoxFocused.texture = selected_tex
- styleBoxPressed.texture = selected_tex
-
- var quantityFont:Font = load("res://assets/fonts/dmg_numbers.png")
- for item:Item in iChar.inventory:
- var btn:Button = Button.new()
- btn.add_theme_stylebox_override("normal", styleBoxEmpty)
- btn.add_theme_stylebox_override("hover", styleBoxHover)
- btn.add_theme_stylebox_override("focus", styleBoxFocused)
- btn.add_theme_stylebox_override("pressed", styleBoxPressed)
- btn.custom_minimum_size = Vector2(24, 24)
- btn.size = Vector2(24, 24)
-
- vboxInvent.find_child("HBoxControl1").add_child(btn)
- var spr:Sprite2D = Sprite2D.new()
- spr.texture = load(item.spritePath)
- spr.hframes = item.spriteFrames.x
- spr.vframes = item.spriteFrames.y
- spr.frame = item.spriteFrame
- spr.centered = false
- spr.position = Vector2(4,4)
- btn.add_child(spr)
-
- if item.can_have_multiple_of:
- var lblQuantity:Label = Label.new()
- lblQuantity.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
- lblQuantity.size = Vector2(24, 24)
- lblQuantity.custom_minimum_size = Vector2(0,0)
- lblQuantity.position = Vector2(10, 2)
- lblQuantity.text = str(item.quantity)
- lblQuantity.add_theme_font_override("font", quantityFont)
- lblQuantity.add_theme_font_size_override("font", 8)
- lblQuantity.scale = Vector2(0.5, 0.5)
- btn.add_child(lblQuantity)
- pass
-
- btn.connect("pressed", _selectItem.bind(item, true))
- btn.connect("focus_entered", _selectItem.bind(item, false))
-
- pass
- # clear eq container...
- var eqContainer = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer
- for child in eqContainer.get_children():
- child.get_parent().remove_child(child)
- child.propagate_call("queue_free", [])
- '"mainhand": null,
- "offhand": null,
- "headgear": null,
- "armour": null,
- "boots": null,
- "accessory": null'
- addEq(iChar, "mainhand", eqContainer, styleBoxEmpty, styleBoxHover, styleBoxFocused, styleBoxPressed, quantityFont)
- addEq(iChar, "offhand", eqContainer, styleBoxEmpty, styleBoxHover, styleBoxFocused, styleBoxPressed, quantityFont)
- addEq(iChar, "headgear", eqContainer, styleBoxEmpty, styleBoxHover, styleBoxFocused, styleBoxPressed, quantityFont)
- addEq(iChar, "armour", eqContainer, styleBoxEmpty, styleBoxHover, styleBoxFocused, styleBoxPressed, quantityFont)
- addEq(iChar, "boots", eqContainer, styleBoxEmpty, styleBoxHover, styleBoxFocused, styleBoxPressed, quantityFont)
- addEq(iChar, "accessory", eqContainer, styleBoxEmpty, styleBoxHover, styleBoxFocused, styleBoxPressed, quantityFont)
-
- pass
-
-func addEq(iChar:CharacterStats, iPiece:String, eqContainer:Control, styleBoxEmpty: StyleBox, styleBoxHover: StyleBox, styleBoxFocused: StyleBox, styleBoxPressed: StyleBox, quantityFont: Font):
- if iChar.equipment[iPiece] != null:
- var btn:Button = Button.new()
- btn.add_theme_stylebox_override("normal", styleBoxEmpty)
- btn.add_theme_stylebox_override("hover", styleBoxHover)
- btn.add_theme_stylebox_override("focus", styleBoxFocused)
- btn.add_theme_stylebox_override("pressed", styleBoxPressed)
- btn.custom_minimum_size = Vector2(24, 24)
- btn.position = Vector2(1,9)
- match iPiece:
- "armour":
- btn.position = Vector2(28, 9)
- pass
- "offhand":
- btn.position = Vector2(55, 9)
- pass
- "headgear":
- btn.position = Vector2(1, 36)
- pass
- "boots":
- btn.position = Vector2(28, 36)
- pass
- "accessory":
- btn.position = Vector2(55, 36)
- pass
- pass
-
- eqContainer.add_child(btn)
- var spr:Sprite2D = Sprite2D.new()
- spr.texture = load(iChar.equipment[iPiece].spritePath)
- spr.hframes = iChar.equipment[iPiece].spriteFrames.x
- spr.vframes = iChar.equipment[iPiece].spriteFrames.y
- spr.frame = iChar.equipment[iPiece].spriteFrame
- spr.centered = false
- spr.position = Vector2(4,4)
- btn.add_child(spr)
- btn.connect("pressed", _selectEquipment.bind(iChar.equipment[iPiece], true))
- btn.connect("focus_entered", _selectEquipment.bind(iChar.equipment[iPiece], false))
-
- if iChar.equipment[iPiece].can_have_multiple_of:
- var lblQuantity:Label = Label.new()
- lblQuantity.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
- lblQuantity.size = Vector2(24, 24)
- lblQuantity.custom_minimum_size = Vector2(0,0)
- lblQuantity.position = Vector2(10, 2)
- lblQuantity.text = str(iChar.equipment[iPiece].quantity)
- lblQuantity.add_theme_font_override("font", quantityFont)
- lblQuantity.add_theme_font_size_override("font", 8)
- lblQuantity.scale = Vector2(0.5, 0.5)
- btn.add_child(lblQuantity)
- pass
- pass
- pass
-
- # draw equipment buttons (for unequipping)
-func _selectEquipment(item:Item, isPress: bool):
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/ButtonDrop.visible = true
- if !is_showing_inventory:
- return
- if lastPressedItem == item and lastPressedType == "Equipment" and timerSelect > 0:
- $SfxUnequip.play()
- GameManager.character_data.unequip_item(selectedEquipment)
- selectedItem = selectedEquipment
- lastPressedItem = null
- selectedEquipment = null
- lastPressedType = "Item"
- var vboxInvent = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory
- for child in vboxInvent.find_child("HBoxControl1").get_children():
- child.grab_focus()
- break
- return
- lastPressedType = "Equipment"
- selectedEquipment = item
- # update description in bottom
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.texture = load(item.spritePath)
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.hframes = item.spriteFrames.x
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.vframes = item.spriteFrames.y
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.frame = item.spriteFrame
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/LabelItemDescription.text = item.description
- if isPress:
- lastPressedItem = item
- timerSelect = 0.4
- # unequip item
- pass
-
-func _selectItem(item:Item, isPress: bool):
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/ButtonDrop.visible = true
- if !is_showing_inventory:
- return
- if lastPressedItem == item and lastPressedType == "Item" and timerSelect > 0:
- timerSelect = 0
- $SfxEquip.play()
- GameManager.character_data.equip_item(selectedItem)
- selectedEquipment = selectedItem
- selectedItem = null
- lastPressedItem = null
- lastPressedType = "Equipment"
- var eqContainer = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer
- for child in eqContainer.get_children():
- child.grab_focus()
- break
- return
- lastPressedType = "Item"
- selectedItem = item
- # update description in bottom
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.texture = load(item.spritePath)
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.hframes = item.spriteFrames.x
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.vframes = item.spriteFrames.y
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.frame = item.spriteFrame
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/LabelItemDescription.text = item.description
- if isPress:
- lastPressedItem = item
- timerSelect = 0.4
- pass
-
-func _process(delta: float) -> void:
- if timerSelect > 0:
- timerSelect -= delta
- if timerSelect <= 0:
- timerSelect = 0
- pass
-
-func _input(_event: InputEvent):
- #print("connected to newtwork:", GameManager.is_network_connected)
- #print("finished tween:", finished_tween)
- if !GameManager.is_network_connected or finished_tween == false:
- return
- if is_showing_inventory:
- if !$ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/ButtonDrop.has_focus():
- if lastPressedType == "Equipment" and selectedEquipment != null and Input.is_action_just_pressed("ui_accept"):
- $SfxUnequip.play()
- GameManager.character_data.unequip_item(selectedEquipment)
- selectedItem = selectedEquipment
- selectedEquipment = null
- lastPressedItem = null
- lastPressedType = "Item"
- var vboxInvent = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory
- for child in vboxInvent.find_child("HBoxControl1").get_children():
- child.grab_focus()
- break
- return
- if lastPressedType == "Item" and selectedItem != null and Input.is_action_just_pressed("ui_accept"):
- $SfxEquip.play()
- GameManager.character_data.equip_item(selectedItem)
- selectedEquipment = selectedItem
- selectedItem = null
- lastPressedItem = null
- lastPressedType = "Equipment"
- var eqContainer = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer
- for child in eqContainer.get_children():
- child.grab_focus()
- break
- return
-
- if Input.is_action_just_pressed("inventory") and finished_tween == true:
- finished_tween = false
- var move_range = 119
- var move_duration = 0.3
- if is_showing_inventory:
- move_range = -move_range
- #stats movement
- var move_tween = get_tree().create_tween()
- move_tween.tween_property($ControlContainer/ControlStats, "position:x",$ControlContainer/ControlStats.position.x + move_range,move_duration).from($ControlContainer/ControlStats.position.x).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_IN_OUT)
- move_range = -80
- if is_showing_inventory:
- move_range = -move_range
- #inventory movement
- var move_tween2 = get_tree().create_tween()
- move_tween2.tween_property($ControlContainer/ControlInventory, "position:x",$ControlContainer/ControlInventory.position.x + move_range,move_duration).from($ControlContainer/ControlInventory.position.x).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_IN_OUT)
-
- move_range = -33
- if is_showing_inventory:
- $SfxInventoryClose.play()
- move_range = -move_range
- else:
- $SfxInventoryOpen.play()
- #info movement
- var move_tween3 = get_tree().create_tween()
- move_tween3.tween_property($ControlContainer/ControlInfo, "position:y",$ControlContainer/ControlInfo.position.y + move_range,move_duration).from($ControlContainer/ControlInfo.position.y).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_IN_OUT)
-
- is_showing_inventory = !is_showing_inventory
- await move_tween3.finished
- finished_tween = true
-
- if is_showing_inventory:
- # preselect first item
- var vboxInvent = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory
- var hadInventoryItem = false
- for child in vboxInvent.find_child("HBoxControl1").get_children():
- child.grab_focus()
- hadInventoryItem = true
- break
- lastPressedType = "Item"
- if hadInventoryItem == false:
- # preselect something in equipment instead
- selectedItem = null
- lastPressedItem = null
- lastPressedType = "Equipment"
- var eqContainer = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer
- for child in eqContainer.get_children():
- child.grab_focus()
- break
- pass
-
- pass
- '
- if Input.is_action_just_pressed("ui_right"):
- $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer.
- pass
- if Input.is_action_just_pressed("ui_left"):
-
- pass'
- '
- if Input.is_action_just_pressed("ui_up"):
- $ControlContainer/ControlInventory/Sprite2DSelector.position.y -= 20
- pass
-
- if Input.is_action_just_pressed("ui_down"):
- $ControlContainer/ControlInventory/Sprite2DSelector.position.y += 20
- pass'
-
-
-func _on_button_drop_pressed() -> void:
- if !is_showing_inventory:
- return
- if lastPressedType == "Item":
- if selectedItem != null:
- GameManager.character_data.drop_item(selectedItem)
- selectedItem = null
- # clear default stuff
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.texture = null
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/LabelItemDescription.text = ""
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/ButtonDrop.visible = false
- else:
- if selectedEquipment != null:
- GameManager.character_data.drop_equipment(selectedEquipment)
- selectedEquipment = null
- # clear default stuff
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control/Sprite2DItem.texture = null
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/LabelItemDescription.text = ""
- $ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/ButtonDrop.visible = false
-
- var vboxInvent = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory
- var hadInventoryItem = false
- for child in vboxInvent.find_child("HBoxControl1").get_children():
- child.grab_focus()
- hadInventoryItem = true
- break
- lastPressedType = "Item"
- if hadInventoryItem == false:
- selectedItem = null
- lastPressedItem = null
- lastPressedType = "Equipment"
- var eqContainer = $ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer
- for child in eqContainer.get_children():
- child.grab_focus()
- break
-
-
- pass # Replace with function body.
diff --git a/src/scripts/inspiration_scripts/inventory.gd.uid b/src/scripts/inspiration_scripts/inventory.gd.uid
deleted file mode 100644
index 6e3ef11..0000000
--- a/src/scripts/inspiration_scripts/inventory.gd.uid
+++ /dev/null
@@ -1 +0,0 @@
-uid://20kfmxrtt20e
diff --git a/src/scripts/inspiration_scripts/inventory.tscn b/src/scripts/inspiration_scripts/inventory.tscn
deleted file mode 100644
index 25fac6f..0000000
--- a/src/scripts/inspiration_scripts/inventory.tscn
+++ /dev/null
@@ -1,693 +0,0 @@
-[gd_scene format=3 uid="uid://du1cpug8yag6w"]
-
-[ext_resource type="Texture2D" uid="uid://b7u7dbiaub8lp" path="res://assets/gfx/ruinborn_mImwZSNWBM.png" id="1_0amil"]
-[ext_resource type="Script" uid="uid://20kfmxrtt20e" path="res://assets/scripts/ui/inventory.gd" id="1_k81k7"]
-[ext_resource type="Texture2D" uid="uid://hib38y541eog" path="res://assets/gfx/items_n_shit.png" id="2_7vwhs"]
-[ext_resource type="Texture2D" uid="uid://ct0rllwve2s1y" path="res://assets/gfx/ui/inventory_panel_small.png" id="2_voqm7"]
-[ext_resource type="Texture2D" uid="uid://who0clhmi5cl" path="res://assets/gfx/ui/inventory_panel.png" id="4_nlhqn"]
-[ext_resource type="Texture2D" uid="uid://cxend0ndnfn32" path="res://assets/gfx/ui/inventory_slot_kenny_white.png" id="4_nxmsh"]
-[ext_resource type="Texture2D" uid="uid://bsnfadlf1dgnw" path="res://assets/gfx/ui/inventory_slot_kenny_black_sword.png" id="6_k81k7"]
-[ext_resource type="FontFile" uid="uid://cbmcfue0ek0tk" path="res://assets/fonts/dmg_numbers.png" id="7_kiwfx"]
-[ext_resource type="Texture2D" uid="uid://tdivehfcj0el" path="res://assets/gfx/ui/inventory_slot_kenny_black_shield.png" id="7_vardb"]
-[ext_resource type="Texture2D" uid="uid://b1l30o2ljhl2t" path="res://assets/gfx/ui/inventory_slot_kenny_black_armour.png" id="8_mnwqb"]
-[ext_resource type="Texture2D" uid="uid://jgbrhnsaxvg" path="res://assets/gfx/ui/inventory_slot_kenny_black_helm.png" id="9_nbh80"]
-[ext_resource type="Texture2D" uid="uid://b71gs7h2v0rdi" path="res://assets/gfx/ui/inventory_slot_kenny_black_ring.png" id="10_kiwfx"]
-[ext_resource type="Texture2D" uid="uid://ckctmypotajtf" path="res://assets/gfx/ui/inventory_slot_kenny_black_shoes.png" id="11_ylqbh"]
-[ext_resource type="Texture2D" uid="uid://c21a60s4funrr" path="res://assets/gfx/ui/inventory_info_panel.png" id="13_vardb"]
-[ext_resource type="AudioStream" uid="uid://x6lxrywls7e2" path="res://assets/audio/sfx/inventory/inventory_open.mp3" id="14_mnwqb"]
-[ext_resource type="AudioStream" uid="uid://cfsubtwvpi7yn" path="res://assets/audio/sfx/inventory/inventory_open_inverted.mp3" id="14_nbh80"]
-[ext_resource type="AudioStream" uid="uid://djw6c5rb4mm60" path="res://assets/audio/sfx/cloth/leather_cloth_02.wav.mp3" id="17_51fgf"]
-[ext_resource type="AudioStream" uid="uid://umoxmryvbm01" path="res://assets/audio/sfx/cloth/leather_cloth_01.wav.mp3" id="18_qk47y"]
-
-[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_nbh80"]
-texture = ExtResource("4_nxmsh")
-modulate_color = Color(0.511719, 0.511719, 0.511719, 1)
-
-[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_kiwfx"]
-texture = ExtResource("4_nxmsh")
-modulate_color = Color(0, 0, 0, 1)
-
-[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_ylqbh"]
-texture = ExtResource("4_nxmsh")
-
-[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_nbh80"]
-
-[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_51fgf"]
-texture = ExtResource("4_nxmsh")
-
-[node name="Inventory" type="CanvasLayer"]
-layer = 21
-script = ExtResource("1_k81k7")
-
-[node name="Sprite2D" type="Sprite2D" parent="."]
-visible = false
-modulate = Color(0.980057, 0.975295, 1, 1)
-z_index = -2
-z_as_relative = false
-position = Vector2(164.625, 92.75)
-scale = Vector2(0.258803, 0.263268)
-texture = ExtResource("1_0amil")
-
-[node name="ControlContainer" type="Control" parent="."]
-layout_mode = 3
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-
-[node name="ControlStats" type="Control" parent="ControlContainer"]
-layout_mode = 1
-anchors_preset = 9
-anchor_bottom = 1.0
-grow_vertical = 2
-
-[node name="Sprite2DPanelz" type="Sprite2D" parent="ControlContainer/ControlStats"]
-texture = ExtResource("4_nlhqn")
-centered = false
-
-[node name="MarginContainer" type="MarginContainer" parent="ControlContainer/ControlStats"]
-layout_mode = 0
-offset_right = 40.0
-offset_bottom = 40.0
-theme_override_constants/margin_left = 3
-theme_override_constants/margin_top = 3
-theme_override_constants/margin_right = 3
-theme_override_constants/margin_bottom = 3
-
-[node name="VBoxContainer" type="VBoxContainer" parent="ControlContainer/ControlStats/MarginContainer"]
-layout_mode = 2
-
-[node name="LabelPlayerName" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer"]
-layout_mode = 2
-theme_override_font_sizes/font_size = 6
-text = "Fronko"
-horizontal_alignment = 1
-
-[node name="HBoxContainer" type="HBoxContainer" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer"]
-layout_mode = 2
-
-[node name="LabelBaseStats" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_constants/line_spacing = 0
-theme_override_font_sizes/font_size = 6
-text = "Level
-
-Hp
-Mp
-
-Str
-Dex
-End
-Int
-Wis
-Lck"
-
-[node name="LabelBaseStatsValue" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_constants/line_spacing = 0
-theme_override_font_sizes/font_size = 6
-text = "1
-
-30 / 30
-20 / 20
-
-10
-10
-10
-10
-10
-10"
-horizontal_alignment = 2
-
-[node name="LabelDerivedStats" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_constants/line_spacing = 0
-theme_override_font_sizes/font_size = 6
-text = "Exp
-Coin
-
-
-
-Damage
-Defense
-MovSpd
-AtkSpd
-Sight
-SpellAmp
-CritChance"
-
-[node name="LabelDerivedStatsValue" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_constants/line_spacing = 0
-theme_override_font_sizes/font_size = 6
-text = "400 / 1000
-1
-
-
-
-2
-3
-2.1
-1.4
-7.0
-3.0
-12.0%"
-horizontal_alignment = 2
-
-[node name="ControlInventory" type="Control" parent="ControlContainer"]
-custom_minimum_size = Vector2(80, 0)
-layout_mode = 1
-anchors_preset = 11
-anchor_left = 1.0
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 0
-grow_vertical = 2
-
-[node name="Sprite2DPanel" type="Sprite2D" parent="ControlContainer/ControlInventory"]
-modulate = Color(0, 0, 0, 0.862745)
-texture = ExtResource("2_voqm7")
-centered = false
-
-[node name="MarginContainer" type="MarginContainer" parent="ControlContainer/ControlInventory"]
-custom_minimum_size = Vector2(80, 0)
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-theme_override_constants/margin_left = 2
-theme_override_constants/margin_top = 2
-theme_override_constants/margin_right = 2
-theme_override_constants/margin_bottom = 2
-
-[node name="VBoxContainer" type="VBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer"]
-layout_mode = 2
-theme_override_constants/separation = 0
-
-[node name="LabelInventory" type="Label" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer"]
-layout_mode = 2
-theme_override_font_sizes/font_size = 6
-text = "Inventory"
-horizontal_alignment = 1
-
-[node name="ControlInventory" type="Control" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer"]
-custom_minimum_size = Vector2(0, 72)
-layout_mode = 2
-
-[node name="MarginContainer" type="MarginContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory"]
-layout_mode = 2
-offset_left = 2.0
-offset_top = 2.0
-offset_right = 78.0
-offset_bottom = 70.0
-grow_horizontal = 2
-grow_vertical = 2
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_constants/margin_left = 2
-theme_override_constants/margin_top = 2
-theme_override_constants/margin_right = 2
-theme_override_constants/margin_bottom = 2
-
-[node name="ScrollContainer" type="ScrollContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer"]
-layout_mode = 2
-follow_focus = true
-
-[node name="VBoxContainerInventory" type="VBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer"]
-layout_mode = 2
-theme_override_constants/separation = -4
-
-[node name="HBoxControl1" type="HBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory"]
-layout_mode = 2
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_constants/separation = 0
-
-[node name="Button3" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button3"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="LabelStack" type="Label" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button3"]
-layout_mode = 1
-anchors_preset = 1
-anchor_left = 1.0
-anchor_right = 1.0
-offset_left = -26.0
-offset_top = 2.0
-offset_right = -2.0
-offset_bottom = 26.0
-grow_horizontal = 0
-theme_override_fonts/font = ExtResource("7_kiwfx")
-theme_override_font_sizes/font_size = 8
-text = "5"
-horizontal_alignment = 2
-
-[node name="Button6" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button6"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button5" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button5"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button4" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button4"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="HBoxControl2" type="HBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory"]
-layout_mode = 2
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_constants/separation = 0
-
-[node name="Button3" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2/Button3"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button5" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2/Button5"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button4" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2/Button4"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="HBoxControl3" type="HBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory"]
-layout_mode = 2
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_constants/separation = 0
-
-[node name="Button3" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3/Button3"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button5" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3/Button5"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button4" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3/Button4"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="ControlEquipment" type="Control" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer"]
-custom_minimum_size = Vector2(80, 64)
-layout_mode = 2
-
-[node name="Label" type="Label" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-layout_mode = 1
-anchors_preset = 5
-anchor_left = 0.5
-anchor_right = 0.5
-offset_left = -21.5
-offset_right = 21.5
-offset_bottom = 23.0
-grow_horizontal = 2
-theme_override_font_sizes/font_size = 6
-text = "Equipment"
-horizontal_alignment = 1
-
-[node name="Sprite2D" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(13, 21)
-texture = ExtResource("6_k81k7")
-
-[node name="Sprite2D2" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(67, 21)
-texture = ExtResource("7_vardb")
-
-[node name="Sprite2D3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(40, 21)
-texture = ExtResource("8_mnwqb")
-
-[node name="Sprite2D4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(13, 48)
-texture = ExtResource("9_nbh80")
-
-[node name="Sprite2D9" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(67, 48)
-texture = ExtResource("10_kiwfx")
-
-[node name="Sprite2D5" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(40, 48)
-texture = ExtResource("11_ylqbh")
-
-[node name="ControlEquipmentContainer" type="Control" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-
-[node name="Button" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 1.0
-offset_top = 9.0
-offset_right = 25.0
-offset_bottom = 33.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button2" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 28.0
-offset_top = 9.0
-offset_right = 52.0
-offset_bottom = 33.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button2"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button3" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 55.0
-offset_top = 9.0
-offset_right = 79.0
-offset_bottom = 33.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button3"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button4" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 1.0
-offset_top = 36.0
-offset_right = 25.0
-offset_bottom = 60.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button4"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button5" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 28.0
-offset_top = 36.0
-offset_right = 52.0
-offset_bottom = 60.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button5"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button6" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 55.0
-offset_top = 36.0
-offset_right = 79.0
-offset_bottom = 60.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button6"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="ControlInfo" type="Control" parent="ControlContainer"]
-custom_minimum_size = Vector2(0, 33)
-layout_mode = 1
-anchors_preset = 12
-anchor_top = 1.0
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 0
-
-[node name="Control" type="Control" parent="ControlContainer/ControlInfo"]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-
-[node name="Sprite2D" type="Sprite2D" parent="ControlContainer/ControlInfo/Control"]
-texture = ExtResource("13_vardb")
-centered = false
-
-[node name="MarginContainer" type="MarginContainer" parent="ControlContainer/ControlInfo/Control"]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-theme_override_constants/margin_left = 5
-theme_override_constants/margin_top = 5
-theme_override_constants/margin_right = 5
-theme_override_constants/margin_bottom = 5
-
-[node name="HBoxContainer" type="HBoxContainer" parent="ControlContainer/ControlInfo/Control/MarginContainer"]
-layout_mode = 2
-
-[node name="Control" type="Control" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_vertical = 4
-
-[node name="Sprite2DSelector" type="Sprite2D" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control"]
-modulate = Color(0.20704, 0.205805, 0.214844, 1)
-texture = ExtResource("4_nxmsh")
-centered = false
-
-[node name="Sprite2DItem" type="Sprite2D" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="LabelItemDescription" type="Label" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer"]
-layout_mode = 2
-size_flags_vertical = 1
-theme_override_font_sizes/font_size = 6
-text = "A small, but sturdy wooden shield. + 1 DEF"
-
-[node name="ButtonDrop" type="Button" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_font_sizes/font_size = 8
-text = "Drop"
-
-[node name="SfxInventoryClose" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("14_nbh80")
-volume_db = -10.0
-
-[node name="SfxInventoryOpen" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("14_mnwqb")
-volume_db = -10.0
-
-[node name="SfxUnequip" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("17_51fgf")
-
-[node name="SfxEquip" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("18_qk47y")
-
-[connection signal="pressed" from="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/ButtonDrop" to="." method="_on_button_drop_pressed"]
diff --git a/src/scripts/inspiration_scripts/inventory.tscn3980824984.tmp b/src/scripts/inspiration_scripts/inventory.tscn3980824984.tmp
deleted file mode 100644
index c796774..0000000
--- a/src/scripts/inspiration_scripts/inventory.tscn3980824984.tmp
+++ /dev/null
@@ -1,692 +0,0 @@
-[gd_scene load_steps=24 format=3 uid="uid://du1cpug8yag6w"]
-
-[ext_resource type="Texture2D" uid="uid://b7u7dbiaub8lp" path="res://assets/gfx/ruinborn_mImwZSNWBM.png" id="1_0amil"]
-[ext_resource type="Script" uid="uid://20kfmxrtt20e" path="res://assets/scripts/ui/inventory.gd" id="1_k81k7"]
-[ext_resource type="Texture2D" uid="uid://hib38y541eog" path="res://assets/gfx/items_n_shit.png" id="2_7vwhs"]
-[ext_resource type="Texture2D" uid="uid://ct0rllwve2s1y" path="res://assets/gfx/ui/inventory_panel_small.png" id="2_voqm7"]
-[ext_resource type="Texture2D" uid="uid://who0clhmi5cl" path="res://assets/gfx/ui/inventory_panel.png" id="4_nlhqn"]
-[ext_resource type="Texture2D" uid="uid://cxend0ndnfn32" path="res://assets/gfx/ui/inventory_slot_kenny_white.png" id="4_nxmsh"]
-[ext_resource type="Texture2D" uid="uid://bsnfadlf1dgnw" path="res://assets/gfx/ui/inventory_slot_kenny_black_sword.png" id="6_k81k7"]
-[ext_resource type="FontFile" uid="uid://cbmcfue0ek0tk" path="res://assets/fonts/dmg_numbers.png" id="7_kiwfx"]
-[ext_resource type="Texture2D" uid="uid://tdivehfcj0el" path="res://assets/gfx/ui/inventory_slot_kenny_black_shield.png" id="7_vardb"]
-[ext_resource type="Texture2D" uid="uid://b1l30o2ljhl2t" path="res://assets/gfx/ui/inventory_slot_kenny_black_armour.png" id="8_mnwqb"]
-[ext_resource type="Texture2D" uid="uid://jgbrhnsaxvg" path="res://assets/gfx/ui/inventory_slot_kenny_black_helm.png" id="9_nbh80"]
-[ext_resource type="Texture2D" uid="uid://b71gs7h2v0rdi" path="res://assets/gfx/ui/inventory_slot_kenny_black_ring.png" id="10_kiwfx"]
-[ext_resource type="Texture2D" uid="uid://ckctmypotajtf" path="res://assets/gfx/ui/inventory_slot_kenny_black_shoes.png" id="11_ylqbh"]
-[ext_resource type="Texture2D" uid="uid://c21a60s4funrr" path="res://assets/gfx/ui/inventory_info_panel.png" id="13_vardb"]
-[ext_resource type="AudioStream" uid="uid://x6lxrywls7e2" path="res://assets/audio/sfx/inventory/inventory_open.mp3" id="14_mnwqb"]
-[ext_resource type="AudioStream" uid="uid://cfsubtwvpi7yn" path="res://assets/audio/sfx/inventory/inventory_open_inverted.mp3" id="14_nbh80"]
-[ext_resource type="AudioStream" uid="uid://djw6c5rb4mm60" path="res://assets/audio/sfx/cloth/leather_cloth_02.wav.mp3" id="17_51fgf"]
-[ext_resource type="AudioStream" uid="uid://umoxmryvbm01" path="res://assets/audio/sfx/cloth/leather_cloth_01.wav.mp3" id="18_qk47y"]
-
-[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_nbh80"]
-texture = ExtResource("4_nxmsh")
-modulate_color = Color(0.511719, 0.511719, 0.511719, 1)
-
-[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_kiwfx"]
-texture = ExtResource("4_nxmsh")
-modulate_color = Color(0, 0, 0, 1)
-
-[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_ylqbh"]
-texture = ExtResource("4_nxmsh")
-
-[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_nbh80"]
-
-[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_51fgf"]
-texture = ExtResource("4_nxmsh")
-
-[node name="Inventory" type="CanvasLayer"]
-layer = 21
-script = ExtResource("1_k81k7")
-
-[node name="Sprite2D" type="Sprite2D" parent="."]
-visible = false
-modulate = Color(0.980057, 0.975295, 1, 1)
-z_index = -2
-z_as_relative = false
-position = Vector2(164.625, 92.75)
-scale = Vector2(0.258803, 0.263268)
-texture = ExtResource("1_0amil")
-
-[node name="ControlContainer" type="Control" parent="."]
-layout_mode = 3
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-
-[node name="ControlStats" type="Control" parent="ControlContainer"]
-layout_mode = 1
-anchors_preset = 9
-anchor_bottom = 1.0
-grow_vertical = 2
-
-[node name="Sprite2DPanelz" type="Sprite2D" parent="ControlContainer/ControlStats"]
-texture = ExtResource("4_nlhqn")
-centered = false
-
-[node name="MarginContainer" type="MarginContainer" parent="ControlContainer/ControlStats"]
-layout_mode = 0
-offset_right = 40.0
-offset_bottom = 40.0
-theme_override_constants/margin_left = 3
-theme_override_constants/margin_top = 3
-theme_override_constants/margin_right = 3
-theme_override_constants/margin_bottom = 3
-
-[node name="VBoxContainer" type="VBoxContainer" parent="ControlContainer/ControlStats/MarginContainer"]
-layout_mode = 2
-
-[node name="LabelPlayerName" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer"]
-layout_mode = 2
-theme_override_font_sizes/font_size = 6
-text = "Fronko"
-horizontal_alignment = 1
-
-[node name="HBoxContainer" type="HBoxContainer" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer"]
-layout_mode = 2
-
-[node name="LabelBaseStats" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_constants/line_spacing = 0
-theme_override_font_sizes/font_size = 6
-text = "Level
-
-Hp
-Mp
-
-Str
-Dex
-End
-Int
-Wis
-Lck"
-
-[node name="LabelBaseStatsValue" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_constants/line_spacing = 0
-theme_override_font_sizes/font_size = 6
-text = "1
-
-30 / 30
-20 / 20
-
-10
-10
-10
-10
-10
-10"
-horizontal_alignment = 2
-
-[node name="LabelDerivedStats" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_constants/line_spacing = 0
-theme_override_font_sizes/font_size = 6
-text = "Exp
-Coin
-
-
-
-Damage
-Defense
-MovSpd
-AtkSpd
-Sight
-SpellAmp
-CritChance"
-
-[node name="LabelDerivedStatsValue" type="Label" parent="ControlContainer/ControlStats/MarginContainer/VBoxContainer/HBoxContainer"]
-layout_mode = 2
-theme_override_constants/line_spacing = 0
-theme_override_font_sizes/font_size = 6
-text = "400 / 1000
-1
-
-
-
-2
-3
-2.1
-1.4
-7.0
-3.0
-12.0%"
-horizontal_alignment = 2
-
-[node name="ControlInventory" type="Control" parent="ControlContainer"]
-custom_minimum_size = Vector2(80, 0)
-layout_mode = 1
-anchors_preset = 11
-anchor_left = 1.0
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 0
-grow_vertical = 2
-
-[node name="Sprite2DPanel" type="Sprite2D" parent="ControlContainer/ControlInventory"]
-modulate = Color(0, 0, 0, 0.862745)
-texture = ExtResource("2_voqm7")
-centered = false
-
-[node name="MarginContainer" type="MarginContainer" parent="ControlContainer/ControlInventory"]
-custom_minimum_size = Vector2(80, 0)
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-theme_override_constants/margin_left = 2
-theme_override_constants/margin_top = 2
-theme_override_constants/margin_right = 2
-theme_override_constants/margin_bottom = 2
-
-[node name="VBoxContainer" type="VBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer"]
-layout_mode = 2
-theme_override_constants/separation = 0
-
-[node name="LabelInventory" type="Label" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer"]
-layout_mode = 2
-theme_override_font_sizes/font_size = 6
-text = "Inventory"
-horizontal_alignment = 1
-
-[node name="ControlInventory" type="Control" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer"]
-custom_minimum_size = Vector2(0, 72)
-layout_mode = 2
-
-[node name="MarginContainer" type="MarginContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory"]
-layout_mode = 2
-offset_left = 2.0
-offset_top = 2.0
-offset_right = 78.0
-offset_bottom = 70.0
-grow_horizontal = 2
-grow_vertical = 2
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_constants/margin_left = 2
-theme_override_constants/margin_top = 2
-theme_override_constants/margin_right = 2
-theme_override_constants/margin_bottom = 2
-
-[node name="ScrollContainer" type="ScrollContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer"]
-layout_mode = 2
-follow_focus = true
-
-[node name="VBoxContainerInventory" type="VBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer"]
-layout_mode = 2
-theme_override_constants/separation = -4
-
-[node name="HBoxControl1" type="HBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory"]
-layout_mode = 2
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_constants/separation = 0
-
-[node name="Button3" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button3"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="LabelStack" type="Label" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button3"]
-layout_mode = 1
-anchors_preset = 1
-anchor_left = 1.0
-anchor_right = 1.0
-offset_left = -26.0
-offset_top = 2.0
-offset_right = -2.0
-offset_bottom = 26.0
-grow_horizontal = 0
-theme_override_fonts/font = ExtResource("7_kiwfx")
-theme_override_font_sizes/font_size = 8
-text = "5"
-horizontal_alignment = 2
-
-[node name="Button6" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button6"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button5" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button5"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button4" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl1/Button4"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="HBoxControl2" type="HBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory"]
-layout_mode = 2
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_constants/separation = 0
-
-[node name="Button3" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2/Button3"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button5" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2/Button5"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button4" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl2/Button4"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="HBoxControl3" type="HBoxContainer" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory"]
-layout_mode = 2
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_constants/separation = 0
-
-[node name="Button3" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3/Button3"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button5" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3/Button5"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button4" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_horizontal = 0
-size_flags_vertical = 0
-theme_override_styles/focus = SubResource("StyleBoxTexture_nbh80")
-theme_override_styles/hover = SubResource("StyleBoxTexture_kiwfx")
-theme_override_styles/pressed = SubResource("StyleBoxTexture_ylqbh")
-theme_override_styles/normal = SubResource("StyleBoxEmpty_nbh80")
-text = " "
-
-[node name="Sprite2DShield4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlInventory/MarginContainer/ScrollContainer/VBoxContainerInventory/HBoxControl3/Button4"]
-process_mode = 4
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="ControlEquipment" type="Control" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer"]
-custom_minimum_size = Vector2(80, 64)
-layout_mode = 2
-
-[node name="Label" type="Label" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-layout_mode = 1
-anchors_preset = 5
-anchor_left = 0.5
-anchor_right = 0.5
-offset_left = -21.5
-offset_right = 21.5
-offset_bottom = 23.0
-grow_horizontal = 2
-theme_override_font_sizes/font_size = 6
-text = "Equipment"
-horizontal_alignment = 1
-
-[node name="Sprite2D" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(13, 21)
-texture = ExtResource("6_k81k7")
-
-[node name="Sprite2D2" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(67, 21)
-texture = ExtResource("7_vardb")
-
-[node name="Sprite2D3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(40, 21)
-texture = ExtResource("8_mnwqb")
-
-[node name="Sprite2D4" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(13, 48)
-texture = ExtResource("9_nbh80")
-
-[node name="Sprite2D9" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(67, 48)
-texture = ExtResource("10_kiwfx")
-
-[node name="Sprite2D5" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-modulate = Color(1, 1, 1, 0.670588)
-position = Vector2(40, 48)
-texture = ExtResource("11_ylqbh")
-
-[node name="ControlEquipmentContainer" type="Control" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment"]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-
-[node name="Button" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 1.0
-offset_top = 9.0
-offset_right = 25.0
-offset_bottom = 33.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button2" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 28.0
-offset_top = 9.0
-offset_right = 52.0
-offset_bottom = 33.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button2"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button3" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 55.0
-offset_top = 9.0
-offset_right = 79.0
-offset_bottom = 33.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button3"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button4" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 1.0
-offset_top = 36.0
-offset_right = 25.0
-offset_bottom = 60.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button4"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button5" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 28.0
-offset_top = 36.0
-offset_right = 52.0
-offset_bottom = 60.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button5"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="Button6" type="Button" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 0
-offset_left = 55.0
-offset_top = 36.0
-offset_right = 79.0
-offset_bottom = 60.0
-theme_override_styles/normal = SubResource("StyleBoxTexture_51fgf")
-
-[node name="Sprite2DShield3" type="Sprite2D" parent="ControlContainer/ControlInventory/MarginContainer/VBoxContainer/ControlEquipment/ControlEquipmentContainer/Button6"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="ControlInfo" type="Control" parent="ControlContainer"]
-custom_minimum_size = Vector2(0, 33)
-layout_mode = 1
-anchors_preset = 12
-anchor_top = 1.0
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 0
-
-[node name="Control" type="Control" parent="ControlContainer/ControlInfo"]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-
-[node name="Sprite2D" type="Sprite2D" parent="ControlContainer/ControlInfo/Control"]
-texture = ExtResource("13_vardb")
-centered = false
-
-[node name="MarginContainer" type="MarginContainer" parent="ControlContainer/ControlInfo/Control"]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-theme_override_constants/margin_left = 5
-theme_override_constants/margin_top = 5
-theme_override_constants/margin_right = 5
-theme_override_constants/margin_bottom = 5
-
-[node name="HBoxContainer" type="HBoxContainer" parent="ControlContainer/ControlInfo/Control/MarginContainer"]
-layout_mode = 2
-
-[node name="Control" type="Control" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer"]
-custom_minimum_size = Vector2(24, 24)
-layout_mode = 2
-size_flags_vertical = 4
-
-[node name="Sprite2DSelector" type="Sprite2D" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control"]
-modulate = Color(0.20704, 0.205805, 0.214844, 1)
-texture = ExtResource("4_nxmsh")
-centered = false
-
-[node name="Sprite2DItem" type="Sprite2D" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer/Control"]
-position = Vector2(4, 4)
-texture = ExtResource("2_7vwhs")
-centered = false
-hframes = 20
-vframes = 14
-frame = 8
-
-[node name="LabelItemDescription" type="Label" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer"]
-layout_mode = 2
-size_flags_vertical = 1
-theme_override_font_sizes/font_size = 6
-text = "A small, but sturdy wooden shield. + 1 DEF"
-
-[node name="ButtonEquip" type="Button" parent="ControlContainer/ControlInfo/Control/MarginContainer/HBoxContainer"]
-visible = false
-layout_mode = 2
-theme_override_font_sizes/font_size = 8
-text = "Equip"
-
-[node name="SfxInventoryClose" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("14_nbh80")
-volume_db = -10.0
-
-[node name="SfxInventoryOpen" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("14_mnwqb")
-volume_db = -10.0
-
-[node name="SfxUnequip" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("17_51fgf")
-
-[node name="SfxEquip" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("18_qk47y")
diff --git a/src/scripts/inspiration_scripts/loot.gd b/src/scripts/inspiration_scripts/loot.gd
deleted file mode 100644
index 9b5f7b6..0000000
--- a/src/scripts/inspiration_scripts/loot.gd
+++ /dev/null
@@ -1,167 +0,0 @@
-extends CharacterBody2D
-
-var it: Item = null
-@export var sync_has_been_picked_up: bool = false
-
-var friction = 8.0 # Lower values make the slowdown more gradual
-var bounceTimer = 0.0
-# Z-axis variables
-var positionZ = 4.0 # Start slightly in the air
-var velocityZ = 10.0 # Initial upward velocity
-var accelerationZ = -330.0 # Gravity
-var bounceRestitution = 0.3 # How much bounce energy is retained (0-1)
-var minBounceVelocity = 60.0 # Minimum velocity needed to bounce
-
-var sync_position := Vector2()
-var sync_velocity := Vector2()
-var sync_positionZ: float = 4.0
-
-
-func _ready() -> void:
- add_to_group("loot")
-
- # Initialize item if needed
- if it == null:
- setItem()
-
-func _process(delta: float) -> void:
- if multiplayer.is_server():
- if bounceTimer > 0.0:
- bounceTimer -= delta
- if bounceTimer < 0:
- bounceTimer = 0
-
- # Update vertical movement
- velocityZ += accelerationZ * delta
- positionZ += velocityZ * delta
-
- # Ground collision and bounce
- if positionZ <= 0:
- velocity = velocity.lerp(Vector2.ZERO, 1.0 - exp(-friction * delta)) # only slow down if on floor
- positionZ = 0
- if abs(velocityZ) > minBounceVelocity:
- #Bounce sound here for items:
- #$SfxCoinBounce.volume_db = -1 + (-10-(velocityZ*0.1))
- #$SfxCoinBounce.play()
- velocityZ = -velocityZ * bounceRestitution
- else:
- velocityZ = 0
-
- update_sprite_scale()
- move_and_slide()
- pass
-
-func _physics_process(_delta: float) -> void:
- if multiplayer.is_server():
- for peer_id in multiplayer.get_peers():
- sync_loot.rpc_id(peer_id, position, velocity, positionZ)
- if !multiplayer.is_server():
- position = sync_position
- velocity = sync_velocity
- positionZ = sync_positionZ
- update_sprite_scale()
- pass
-
-@rpc("unreliable")
-func sync_loot(pos: Vector2, vel: Vector2, posZ: float):
- sync_position = pos
- sync_velocity = vel
- sync_positionZ = posZ
- pass
-
-func update_sprite_scale() -> void:
- # Calculate scale based on height
- # Maximum height will have scale 1.3, ground will have scale 1.0
- var height_factor = positionZ / 50.0 # Assuming 20 is max height
- var posY = 0.0 + (2 * positionZ)
- var sc = 1.0 + (0.8 * height_factor)
- $Sprite2D.scale = Vector2(sc, sc)
- $Sprite2D.position.y = -posY
- pass
-
-func setItem(iItem: Item = null) -> void:
- $Label.visible = false
- if iItem != null:
- it = iItem
- else:
- it = Item.new()
- if $Sprite2D.texture != null or $Sprite2D.texture.resource_path != it.spritePath:
- $Sprite2D.texture = load(it.spritePath)
- $Sprite2D.frame = it.spriteFrame
- pass
-
-@rpc("any_peer", "reliable", "call_local")
-func request_pickup(_player_id: int):
- if multiplayer.is_server():
- sync_has_been_picked_up = true
- visible = false
- # Tell all clients to remove the loot
- remove_loot.rpc()
- $SfxPickup.play()
- await $SfxPickup.finished
- # Remove loot on server too
- queue_free()
-
-# Called locally by the player picking up the item
-func pick_up_local(player_id: int):
- if sync_has_been_picked_up:
- return
- var player = MultiplayerManager.playersNode.get_node(str(player_id))
- if player:
- sync_has_been_picked_up = true
- visible = false
- # Add item to local inventory
- player.stats.add_item(it)
- # Tell server about pickup
- if not multiplayer.is_server():
- request_pickup.rpc_id(1, player_id)
- else:
- # Tell all clients to remove the loot
- remove_loot.rpc()
- $SfxPickup.play()
- await $SfxPickup.finished
- # Remove loot locally immediately
- queue_free()
-
-@rpc("authority", "reliable")
-func remove_loot():
- visible = false
- sync_has_been_picked_up = true
-
- $SfxPickup.play()
- await $SfxPickup.finished
- queue_free()
-
-func _on_area_2d_body_entered(_body: Node2D) -> void:
- $Label.visible = true
- pass # Replace with function body.
-
-
-func _on_area_2d_body_exited(_body: Node2D) -> void:
- $Label.visible = false
- pass # Replace with function body.
-
-
-func _on_area_2d_collision_body_entered(_body: Node2D) -> void:
- if bounceTimer == 0:
- #$SfxCoinBounce.play()
- bounceTimer = 0.08
- # inverse the direction and slow down slightly
- var collision_shape = $Area2DCollision.get_overlapping_bodies()
-
- if collision_shape.size() > 0:
- var collider = collision_shape[0]
- var normal = (global_position - collider.global_position).normalized()
- velocity = velocity.bounce(normal)
-
- pass # Replace with function body.
-
-
-func _on_area_2d_pickup_area_entered(_area: Area2D) -> void:
- $Label.visible = true
- pass # Replace with function body.
-
-
-func _on_area_2d_pickup_area_exited(_area: Area2D) -> void:
- $Label.visible = false
- pass # Replace with function body.
diff --git a/src/scripts/inspiration_scripts/loot.gd.uid b/src/scripts/inspiration_scripts/loot.gd.uid
deleted file mode 100644
index 21c74d4..0000000
--- a/src/scripts/inspiration_scripts/loot.gd.uid
+++ /dev/null
@@ -1 +0,0 @@
-uid://bawxh5vhj4ii3
diff --git a/src/scripts/inspiration_scripts/pot.tscn30323093389.tmp b/src/scripts/inspiration_scripts/pot.tscn30323093389.tmp
deleted file mode 100644
index 003ecda..0000000
--- a/src/scripts/inspiration_scripts/pot.tscn30323093389.tmp
+++ /dev/null
@@ -1,152 +0,0 @@
-[gd_scene load_steps=21 format=3 uid="uid://bdlg5orah64m5"]
-
-[ext_resource type="Script" uid="uid://bj0ueurl3vovc" path="res://scripts/entities/world/pot.gd" id="1_hsjxb"]
-[ext_resource type="Texture2D" uid="uid://bu4dq78f8lgj5" path="res://assets/gfx/sheet_18.png" id="1_rxnv2"]
-[ext_resource type="AudioStream" uid="uid://fl0rfi4in3n4" path="res://assets/audio/sfx/environment/pot/Drunk lad destroys plant pot.mp3" id="3_vktry"]
-[ext_resource type="AudioStream" uid="uid://dejjc0uqthi1b" path="res://assets/audio/sfx/environment/pot/pot_destroy_sound1.mp3" id="4_nb533"]
-[ext_resource type="AudioStream" uid="uid://iuxunaogc8xr" path="res://assets/audio/sfx/environment/pot/pot_destroy_sound2.mp3" id="5_cmff4"]
-[ext_resource type="AudioStream" uid="uid://bfqusej0pbxem" path="res://assets/audio/sfx/environment/pot/pot_destroy_sound3.mp3" id="6_lq20m"]
-[ext_resource type="AudioStream" uid="uid://dq461vpiih3lc" path="res://assets/audio/sfx/environment/pot/pot_destroy_sound4.mp3" id="7_76fyq"]
-[ext_resource type="AudioStream" uid="uid://cg1ndvx4t7xtd" path="res://assets/audio/sfx/environment/pot/pot_destroy_sound5.mp3" id="8_m11t2"]
-[ext_resource type="AudioStream" uid="uid://bt5npaenq15h2" path="res://assets/audio/sfx/environment/pot/smaller_pot_crash.mp3" id="9_sb38x"]
-[ext_resource type="Texture2D" uid="uid://b1twy68vd7f20" path="res://assets/gfx/pickups/indicator.png" id="10_nb533"]
-
-[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_hsjxb"]
-properties/0/path = NodePath(".:position")
-properties/0/spawn = true
-properties/0/replication_mode = 2
-
-[sub_resource type="Gradient" id="Gradient_nb533"]
-offsets = PackedFloat32Array(0.847255, 0.861575)
-colors = PackedColorArray(0, 0, 0, 0.764706, 0, 0, 0, 0)
-
-[sub_resource type="GradientTexture2D" id="GradientTexture2D_87nuj"]
-gradient = SubResource("Gradient_nb533")
-width = 16
-height = 6
-fill = 1
-fill_from = Vector2(0.504274, 0.478632)
-fill_to = Vector2(0.897436, 0.0769231)
-
-[sub_resource type="RectangleShape2D" id="RectangleShape2D_hsjxb"]
-size = Vector2(12, 8)
-
-[sub_resource type="RectangleShape2D" id="RectangleShape2D_87nuj"]
-size = Vector2(18, 15)
-
-[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_ui3li"]
-streams_count = 7
-stream_0/stream = ExtResource("3_vktry")
-stream_1/stream = ExtResource("4_nb533")
-stream_2/stream = ExtResource("5_cmff4")
-stream_3/stream = ExtResource("6_lq20m")
-stream_4/stream = ExtResource("7_76fyq")
-stream_5/stream = ExtResource("8_m11t2")
-stream_6/stream = ExtResource("9_sb38x")
-
-[sub_resource type="Animation" id="Animation_cmff4"]
-resource_name = "indicate"
-length = 0.8
-loop_mode = 1
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath(".:offset")
-tracks/0/interp = 2
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0, 0.4, 0.8),
-"transitions": PackedFloat32Array(1, 1, 1),
-"update": 0,
-"values": [Vector2(0, 0), Vector2(0, -1), Vector2(0, 0)]
-}
-
-[sub_resource type="Animation" id="Animation_lq20m"]
-length = 0.001
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath(".:offset")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(0, 0)]
-}
-
-[sub_resource type="AnimationLibrary" id="AnimationLibrary_76fyq"]
-_data = {
-&"RESET": SubResource("Animation_lq20m"),
-&"indicate": SubResource("Animation_cmff4")
-}
-
-[sub_resource type="RectangleShape2D" id="RectangleShape2D_nb533"]
-size = Vector2(14, 9)
-
-[node name="Pot" type="CharacterBody2D"]
-collision_layer = 128
-collision_mask = 64
-script = ExtResource("1_hsjxb")
-
-[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
-replication_config = SubResource("SceneReplicationConfig_hsjxb")
-
-[node name="Sprite2DShadow" type="Sprite2D" parent="."]
-position = Vector2(0, 3)
-texture = SubResource("GradientTexture2D_87nuj")
-
-[node name="Sprite2D" type="Sprite2D" parent="."]
-position = Vector2(0, -4)
-texture = ExtResource("1_rxnv2")
-hframes = 19
-vframes = 19
-frame = 14
-
-[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
-position = Vector2(0, -1)
-shape = SubResource("RectangleShape2D_hsjxb")
-
-[node name="Area2DPickup" type="Area2D" parent="."]
-collision_layer = 1024
-collision_mask = 512
-
-[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2DPickup"]
-position = Vector2(0, -1)
-shape = SubResource("RectangleShape2D_87nuj")
-debug_color = Color(0.688142, 0.7, 0.0440007, 0.42)
-
-[node name="SfxShatter" type="AudioStreamPlayer2D" parent="."]
-stream = SubResource("AudioStreamRandomizer_ui3li")
-attenuation = 9.84915
-panning_strength = 1.46
-bus = &"Sfx"
-
-[node name="SfxThrow" type="AudioStreamPlayer2D" parent="."]
-
-[node name="SfxDrop" type="AudioStreamPlayer2D" parent="."]
-
-[node name="Indicator" type="Sprite2D" parent="."]
-position = Vector2(0, -11)
-texture = ExtResource("10_nb533")
-
-[node name="AnimationPlayer" type="AnimationPlayer" parent="Indicator"]
-libraries = {
-&"": SubResource("AnimationLibrary_76fyq")
-}
-autoplay = "indicate"
-
-[node name="Area2DCollision" type="Area2D" parent="."]
-collision_layer = 1024
-collision_mask = 704
-
-[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2DCollision"]
-position = Vector2(0, -1)
-shape = SubResource("RectangleShape2D_nb533")
-debug_color = Color(0.7, 0.132592, 0.232379, 0.42)
-
-[connection signal="body_entered" from="Area2DPickup" to="." method="_on_area_2d_pickup_body_entered"]
-[connection signal="body_exited" from="Area2DPickup" to="." method="_on_area_2d_pickup_body_exited"]
-[connection signal="body_entered" from="Area2DCollision" to="." method="_on_area_2d_collision_body_entered"]
-[connection signal="body_exited" from="Area2DCollision" to="." method="_on_area_2d_collision_body_exited"]
diff --git a/src/scripts/mobile_input.gd b/src/scripts/mobile_input.gd
new file mode 100644
index 0000000..f07530f
--- /dev/null
+++ b/src/scripts/mobile_input.gd
@@ -0,0 +1,56 @@
+extends Control
+
+# Store the current joystick input value
+var virtual_joystick_input: Vector2 = Vector2.ZERO
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ _update_visibility()
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(_delta: float) -> void:
+ pass
+
+func _update_visibility() -> void:
+ # Check if touchscreen is available
+ var has_touchscreen = DisplayServer.is_touchscreen_available()
+
+ # Check if running on mobile platform
+ var os_name = OS.get_name().to_lower()
+ var is_mobile_os = os_name in ["android", "ios"]
+
+ # Show mobile input if touchscreen is available OR if on mobile OS
+ var should_show = has_touchscreen or is_mobile_os
+
+ visible = should_show
+
+ # Debug output (optional, can be removed)
+ if Engine.is_editor_hint():
+ return
+ print("MobileInput visibility: ", should_show, " (touchscreen: ", has_touchscreen, ", mobile OS: ", is_mobile_os, ", OS: ", os_name, ")")
+
+
+func _on_virtual_joystick_analogic_changed(value: Vector2, _distance: float, _angle: float, _angle_clockwise: float, _angle_not_clockwise: float) -> void:
+ # Store the joystick input value
+ # The value is already normalized (0.0 to 1.0) from the joystick
+ virtual_joystick_input = value
+
+ # Update all local players with the joystick input
+ _update_player_input()
+
+func _update_player_input():
+ # Find all local players and set their virtual joystick input
+ var game_world = get_tree().get_first_node_in_group("game_world")
+ if not game_world:
+ return
+
+ var player_manager = game_world.get_node_or_null("PlayerManager")
+ if not player_manager:
+ return
+
+ # Get all local players
+ var local_players = player_manager.get_local_players()
+ for player in local_players:
+ if player and is_instance_valid(player):
+ # Set the virtual joystick input on the player
+ player.virtual_joystick_input = virtual_joystick_input
diff --git a/src/scripts/mobile_input.gd.uid b/src/scripts/mobile_input.gd.uid
new file mode 100644
index 0000000..b2e4fdc
--- /dev/null
+++ b/src/scripts/mobile_input.gd.uid
@@ -0,0 +1 @@
+uid://5hepk3l8u2eg
diff --git a/src/scripts/player.gd b/src/scripts/player.gd
index 4e518aa..2f457ca 100644
--- a/src/scripts/player.gd
+++ b/src/scripts/player.gd
@@ -22,6 +22,7 @@ var teleported_this_frame: bool = false # Flag to prevent position sync from ove
# Input device (for local multiplayer)
var input_device: int = -1 # -1 for keyboard, 0+ for gamepad index
+var virtual_joystick_input: Vector2 = Vector2.ZERO # Virtual joystick input from mobile controls
# Interaction
var held_object = null
@@ -271,9 +272,8 @@ func _ready():
# Set up cone light blend mode, texture, initial rotation, and spread
if cone_light:
- _create_cone_light_texture()
_update_cone_light_rotation()
- _update_cone_light_spread()
+ _update_cone_light_spread() # This calls _create_cone_light_texture()
# Wait before allowing RPCs to ensure player is fully spawned on all clients
# This prevents "Node not found" errors when RPCs try to resolve node paths
@@ -1056,10 +1056,26 @@ func _physics_process(delta):
func _handle_input():
var input_vector = Vector2.ZERO
- if input_device == -1:
+ # Check for virtual joystick input first (mobile/touchscreen)
+ if virtual_joystick_input.length() > 0.01:
+ input_vector = virtual_joystick_input
+ elif input_device == -1:
# Keyboard input
- input_vector.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
- input_vector.y = Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
+ input_vector.x = max(
+ Input.get_action_strength("move_right"),
+ Input.get_action_strength("ui_right")
+ ) - max(
+ Input.get_action_strength("move_left"),
+ Input.get_action_strength("ui_left")
+ )
+
+ input_vector.y = max(
+ Input.get_action_strength("move_down"),
+ Input.get_action_strength("ui_down")
+ ) - max(
+ Input.get_action_strength("move_up"),
+ Input.get_action_strength("ui_up")
+ )
else:
# Gamepad input
input_vector.x = Input.get_joy_axis(input_device, JOY_AXIS_LEFT_X)
@@ -2252,8 +2268,18 @@ func _handle_struggle(delta):
var input_dir = Vector2.ZERO
if input_device == -1: # Keyboard
- input_dir.x = Input.get_axis("move_left", "move_right")
- input_dir.y = Input.get_axis("move_up", "move_down")
+ input_dir.x = clamp(
+ Input.get_axis("move_left", "move_right")
+ + Input.get_axis("ui_left", "ui_right"),
+ -1.0,
+ 1.0
+ )
+ input_dir.y = clamp(
+ Input.get_axis("move_up", "move_down")
+ + Input.get_axis("ui_up", "ui_down"),
+ -1.0,
+ 1.0
+ )
else: # Gamepad
input_dir.x = Input.get_joy_axis(input_device, JOY_AXIS_LEFT_X)
input_dir.y = Input.get_joy_axis(input_device, JOY_AXIS_LEFT_Y)
diff --git a/src/scripts/room_lighting_system.gd b/src/scripts/room_lighting_system.gd
deleted file mode 100644
index b057cc7..0000000
--- a/src/scripts/room_lighting_system.gd
+++ /dev/null
@@ -1,259 +0,0 @@
-extends Node2D
-
-# Room Lighting System
-# Manages per-room darkness and fog of war based on player lights and torch count
-
-@onready var game_world = get_tree().get_first_node_in_group("game_world")
-
-# Room lighting data
-var room_lighting_data: Dictionary = {} # room_id -> {lit: bool, torch_count: int, darkness_level: float}
-var room_darkness_overlays: Dictionary = {} # room_id -> ColorRect node
-
-# Constants
-const TILE_SIZE = 16 # Each tile is 16x16 pixels
-const DARKNESS_COLOR = Color(0, 0, 0, 0.95) # Almost black, slightly transparent
-const MIN_DARKNESS = 0.3 # Minimum darkness even with torches
-const MAX_DARKNESS = 0.95 # Maximum darkness (no torches, unlit)
-
-# Light detection
-var light_check_timer: float = 0.0
-const LIGHT_CHECK_INTERVAL = 0.1 # Check every 0.1 seconds
-
-var darkness_layer: Node2D = null
-
-func _ready():
- # Create Node2D for darkness overlays (in world space, above game world)
- darkness_layer = Node2D.new()
- darkness_layer.name = "RoomDarknessLayer"
- darkness_layer.z_index = 100 # High z-index to be above game world
- add_child(darkness_layer)
-
- # Wait for dungeon to be generated
- call_deferred("_initialize_room_lighting")
-
-func _initialize_room_lighting():
- # Wait for dungeon data to be available
- if not game_world or game_world.dungeon_data.is_empty():
- await get_tree().process_frame
- call_deferred("_initialize_room_lighting")
- return
-
- var dungeon_data = game_world.dungeon_data
- if not dungeon_data.has("rooms") or not dungeon_data.has("torches"):
- print("RoomLightingSystem: Dungeon data not ready yet")
- await get_tree().process_frame
- call_deferred("_initialize_room_lighting")
- return
-
- # Clear old room lighting data and overlays when reinitializing
- room_lighting_data.clear()
- if darkness_layer:
- for child in darkness_layer.get_children():
- child.queue_free()
- room_darkness_overlays.clear()
-
- # Count torches per room
- var torch_counts: Dictionary = {} # room_id -> count
- var rooms = dungeon_data.rooms
- var torches = dungeon_data.torches
-
- # Initialize all rooms as unlit
- for i in range(rooms.size()):
- var room = rooms[i]
- var room_id = _get_room_id(room)
- torch_counts[room_id] = 0
- room_lighting_data[room_id] = {
- "lit": false,
- "torch_count": 0,
- "darkness_level": MAX_DARKNESS
- }
-
- # Count torches in each room
- for torch_data in torches:
- var torch_pos = torch_data.position
- # Find which room this torch belongs to
- for i in range(rooms.size()):
- var room = rooms[i]
- if _is_position_in_room(torch_pos, room):
- var room_id = _get_room_id(room)
- torch_counts[room_id] = torch_counts.get(room_id, 0) + 1
- break
-
- # Update room lighting data with torch counts
- for room_id in torch_counts:
- var torch_count = torch_counts[room_id]
- room_lighting_data[room_id].torch_count = torch_count
- # Calculate darkness level based on torch count (0-4 torches)
- # More torches = less darkness
- var darkness = MAX_DARKNESS - (torch_count * 0.15) # Each torch reduces darkness by 0.15
- darkness = clamp(darkness, MIN_DARKNESS, MAX_DARKNESS)
- room_lighting_data[room_id].darkness_level = darkness
-
- # Create darkness overlays for all rooms (initially all dark)
- _create_darkness_overlays()
-
- print("RoomLightingSystem: Initialized ", rooms.size(), " rooms with lighting data")
-
-# Public method to reinitialize lighting (called when new level is generated)
-func reinitialize():
- call_deferred("_initialize_room_lighting")
-
-func _get_room_id(room: Dictionary) -> String:
- # Create unique ID from room position and size
- return "%d_%d_%d_%d" % [room.x, room.y, room.w, room.h]
-
-func _is_position_in_room(pos: Vector2, room: Dictionary) -> bool:
- # Convert room tile coordinates to world coordinates
- var room_world_x = room.x * TILE_SIZE
- var room_world_y = room.y * TILE_SIZE
- var room_world_w = room.w * TILE_SIZE
- var room_world_h = room.h * TILE_SIZE
-
- # Check if position is within room bounds (including walls)
- return pos.x >= room_world_x and pos.x < room_world_x + room_world_w and \
- pos.y >= room_world_y and pos.y < room_world_y + room_world_h
-
-func _create_darkness_overlays():
- if not darkness_layer:
- push_error("RoomLightingSystem: Darkness layer not found!")
- return
-
- if not game_world or game_world.dungeon_data.is_empty():
- return
-
- var rooms = game_world.dungeon_data.rooms
-
- # Create darkness overlay for each room
- for i in range(rooms.size()):
- var room = rooms[i]
- var room_id = _get_room_id(room)
-
- # Create ColorRect for darkness overlay
- var overlay = ColorRect.new()
- overlay.name = "Darkness_%s" % room_id
-
- # Set position and size (in world coordinates)
- var room_world_x = room.x * TILE_SIZE
- var room_world_y = room.y * TILE_SIZE
- var room_world_w = room.w * TILE_SIZE
- var room_world_h = room.h * TILE_SIZE
-
- overlay.position = Vector2(room_world_x, room_world_y)
- overlay.size = Vector2(room_world_w, room_world_h)
-
- # Set darkness color based on torch count
- var lighting_data = room_lighting_data.get(room_id, {})
- var darkness_level = lighting_data.get("darkness_level", MAX_DARKNESS)
- var is_lit = lighting_data.get("lit", false)
-
- # If room is lit, make it transparent (no darkness)
- # Otherwise, apply darkness based on torch count
- if is_lit:
- overlay.color = Color(0, 0, 0, 0) # Transparent (lit)
- else:
- overlay.color = Color(0, 0, 0, darkness_level) # Dark (unlit)
-
- darkness_layer.add_child(overlay)
- room_darkness_overlays[room_id] = overlay
-
-func _process(delta):
- light_check_timer += delta
- if light_check_timer >= LIGHT_CHECK_INTERVAL:
- light_check_timer = 0.0
- _check_player_lights()
-
-func _check_player_lights():
- if not game_world or game_world.dungeon_data.is_empty():
- return
-
- var rooms = game_world.dungeon_data.rooms
- var players = get_tree().get_nodes_in_group("player")
-
- # Check each room against each player's lights
- for room in rooms:
- var room_id = _get_room_id(room)
- var was_lit = room_lighting_data[room_id].lit
-
- # Check if any player's light intersects this room
- var is_lit_now = false
- for player in players:
- if _player_light_intersects_room(player, room):
- is_lit_now = true
- break
-
- # Update lighting state
- if is_lit_now and not was_lit:
- # Room just became lit
- room_lighting_data[room_id].lit = true
- _update_room_darkness(room_id)
- elif not is_lit_now and was_lit:
- # Room became unlit (shouldn't happen, but handle it)
- # Actually, we keep rooms lit once they've been seen
- pass
-
-func _player_light_intersects_room(player: Node2D, room: Dictionary) -> bool:
- # Check if player's cone light or point light intersects the room
- var player_pos = player.global_position
-
- # Get room bounds in world coordinates
- var room_world_x = room.x * TILE_SIZE
- var room_world_y = room.y * TILE_SIZE
- var room_world_w = room.w * TILE_SIZE
- var room_world_h = room.h * TILE_SIZE
- var room_rect = Rect2(room_world_x, room_world_y, room_world_w, room_world_h)
-
- # Check cone light (PointLight2D named "ConeLight")
- var cone_light = player.get_node_or_null("ConeLight")
- if cone_light:
- # Get light range from texture or use default
- # Cone light texture is 256x256, so range is approximately 128 pixels
- var light_range = 128.0 # Approximate range of cone light
- var light_pos = cone_light.global_position
-
- # Check if light circle intersects room rectangle
- if _circle_intersects_rect(light_pos, light_range, room_rect):
- return true
-
- # Check point light (PointLight2D) - even if not visible, it might be used
- var point_light = player.get_node_or_null("PointLight2D")
- if point_light:
- # Get light range from texture or use default
- # Point light has a gradient texture, estimate range
- var light_range = 64.0 # Approximate range of point light
- var light_pos = point_light.global_position
-
- # Check if light circle intersects room rectangle
- if _circle_intersects_rect(light_pos, light_range, room_rect):
- return true
-
- # Also check if player is inside the room (they can see it)
- if room_rect.has_point(player_pos):
- return true
-
- return false
-
-func _circle_intersects_rect(circle_center: Vector2, circle_radius: float, rect: Rect2) -> bool:
- # Find the closest point on the rectangle to the circle center
- var closest_x = clamp(circle_center.x, rect.position.x, rect.position.x + rect.size.x)
- var closest_y = clamp(circle_center.y, rect.position.y, rect.position.y + rect.size.y)
- var closest_point = Vector2(closest_x, closest_y)
-
- # Check if the closest point is within the circle
- var distance = circle_center.distance_to(closest_point)
- return distance <= circle_radius
-
-func _update_room_darkness(room_id: String):
- var overlay = room_darkness_overlays.get(room_id)
- if not overlay:
- return
-
- var lighting_data = room_lighting_data.get(room_id, {})
- var is_lit = lighting_data.get("lit", false)
- var darkness_level = lighting_data.get("darkness_level", MAX_DARKNESS)
-
- # If room is lit, make overlay transparent
- # Otherwise, apply darkness based on torch count
- if is_lit:
- overlay.color = Color(0, 0, 0, 0) # Transparent (lit)
- else:
- overlay.color = Color(0, 0, 0, darkness_level) # Dark (unlit)