diff --git a/.idea/.idea.Hellswipers/.idea/.gitignore b/.idea/.idea.Hellswipers/.idea/.gitignore
new file mode 100644
index 0000000..cdaf600
--- /dev/null
+++ b/.idea/.idea.Hellswipers/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/modules.xml
+/contentModel.xml
+/.idea.Hellswipers.iml
+/projectSettingsUpdater.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.Hellswipers/.idea/.name b/.idea/.idea.Hellswipers/.idea/.name
new file mode 100644
index 0000000..c70b9f4
--- /dev/null
+++ b/.idea/.idea.Hellswipers/.idea/.name
@@ -0,0 +1 @@
+Hellswipers
\ No newline at end of file
diff --git a/.idea/.idea.Hellswipers/.idea/encodings.xml b/.idea/.idea.Hellswipers/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.Hellswipers/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Hellswipers/.idea/indexLayout.xml b/.idea/.idea.Hellswipers/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.Hellswipers/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Hellswipers/.idea/vcs.xml b/.idea/.idea.Hellswipers/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/.idea.Hellswipers/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Hellswipers.csproj b/Hellswipers.csproj
new file mode 100644
index 0000000..198256e
--- /dev/null
+++ b/Hellswipers.csproj
@@ -0,0 +1,8 @@
+
+
+ net6.0
+ net7.0
+ net8.0
+ true
+
+
\ No newline at end of file
diff --git a/Hellswipers.sln b/Hellswipers.sln
new file mode 100644
index 0000000..20b6cb9
--- /dev/null
+++ b/Hellswipers.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hellswipers", "Hellswipers.csproj", "{422EE1A2-8A73-4E79-8DD6-605A9503D575}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ ExportDebug|Any CPU = ExportDebug|Any CPU
+ ExportRelease|Any CPU = ExportRelease|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {422EE1A2-8A73-4E79-8DD6-605A9503D575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {422EE1A2-8A73-4E79-8DD6-605A9503D575}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {422EE1A2-8A73-4E79-8DD6-605A9503D575}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
+ {422EE1A2-8A73-4E79-8DD6-605A9503D575}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
+ {422EE1A2-8A73-4E79-8DD6-605A9503D575}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
+ {422EE1A2-8A73-4E79-8DD6-605A9503D575}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Hellswipers.sln.DotSettings b/Hellswipers.sln.DotSettings
new file mode 100644
index 0000000..c35dc79
--- /dev/null
+++ b/Hellswipers.sln.DotSettings
@@ -0,0 +1,2 @@
+
+ True
\ No newline at end of file
diff --git a/default_bus_layout.tres b/default_bus_layout.tres
new file mode 100644
index 0000000..3fddfa1
--- /dev/null
+++ b/default_bus_layout.tres
@@ -0,0 +1,15 @@
+[gd_resource type="AudioBusLayout" format=3 uid="uid://fdje4ljsp3di"]
+
+[resource]
+bus/1/name = &"Music"
+bus/1/solo = false
+bus/1/mute = false
+bus/1/bypass_fx = false
+bus/1/volume_db = 0.0
+bus/1/send = &"Master"
+bus/2/name = &"Sound"
+bus/2/solo = false
+bus/2/mute = false
+bus/2/bypass_fx = false
+bus/2/volume_db = 0.0
+bus/2/send = &"Master"
diff --git a/export_presets.cfg b/export_presets.cfg
index 31cbceb..d7cfab5 100644
--- a/export_presets.cfg
+++ b/export_presets.cfg
@@ -60,6 +60,9 @@ 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}'"
+dotnet/include_scripts_content=true
+dotnet/include_debug_symbols=true
+dotnet/embed_build_outputs=false
[preset.1]
@@ -100,47 +103,12 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
+dotnet/include_scripts_content=true
+dotnet/include_debug_symbols=true
+dotnet/embed_build_outputs=false
[preset.2]
-name="Web"
-platform="Web"
-runnable=false
-dedicated_server=false
-custom_features=""
-export_filter="all_resources"
-include_filter=""
-exclude_filter=""
-export_path="export/web/hellswipers.html"
-encryption_include_filters=""
-encryption_exclude_filters=""
-encrypt_pck=false
-encrypt_directory=false
-
-[preset.2.options]
-
-custom_template/debug=""
-custom_template/release=""
-variant/extensions_support=false
-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/offline_page=""
-progressive_web_app/display=1
-progressive_web_app/orientation=0
-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)
-
-[preset.3]
-
name="Android"
platform="Android"
runnable=true
@@ -155,7 +123,7 @@ encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
-[preset.3.options]
+[preset.2.options]
custom_template/debug=""
custom_template/release=""
@@ -163,9 +131,9 @@ gradle_build/use_gradle_build=false
gradle_build/export_format=0
gradle_build/min_sdk=""
gradle_build/target_sdk=""
-architectures/armeabi-v7a=true
+architectures/armeabi-v7a=false
architectures/arm64-v8a=true
-architectures/x86=true
+architectures/x86=false
architectures/x86_64=true
version/code=1
version/name=""
@@ -178,8 +146,8 @@ package/exclude_from_recents=false
package/show_in_android_tv=false
package/show_in_app_library=true
package/show_as_launcher_app=false
-launcher_icons/main_192x192=""
-launcher_icons/adaptive_foreground_432x432=""
+launcher_icons/main_192x192="res://icon_android_main.png"
+launcher_icons/adaptive_foreground_432x432="res://icon_android_adaptive.png"
launcher_icons/adaptive_background_432x432=""
graphics/opengl_debug=false
xr_features/xr_mode=0
@@ -340,3 +308,6 @@ permissions/write_sms=false
permissions/write_social_stream=false
permissions/write_sync_settings=false
permissions/write_user_dictionary=false
+dotnet/include_scripts_content=true
+dotnet/include_debug_symbols=true
+dotnet/embed_build_outputs=false
diff --git a/game/arrow.tscn b/game/arrow.tscn
new file mode 100644
index 0000000..61aa935
--- /dev/null
+++ b/game/arrow.tscn
@@ -0,0 +1,15 @@
+[gd_scene load_steps=2 format=3 uid="uid://cjc46cgqe1r20"]
+
+[ext_resource type="Script" path="res://src/Game/Arrow.cs" id="1_fcyti"]
+
+[node name="Outline" type="Polygon2D"]
+color = Color(0, 0, 0, 1)
+offset = Vector2(-32, -32)
+antialiased = true
+polygon = PackedVector2Array(0, 20, 0, 44, 20, 44, 20, 64, 32, 64, 64, 32, 32, 0, 20, 0, 20, 20)
+script = ExtResource("1_fcyti")
+
+[node name="Inner" type="Polygon2D" parent="."]
+offset = Vector2(-32, -32)
+antialiased = true
+polygon = PackedVector2Array(4, 24, 4, 40, 24, 40, 24, 60, 30, 60, 58, 32, 30, 4, 24, 4, 24, 24)
diff --git a/game/arrow/arrow.gd b/game/arrow/arrow.gd
deleted file mode 100644
index eb9acfe..0000000
--- a/game/arrow/arrow.gd
+++ /dev/null
@@ -1,33 +0,0 @@
-extends Polygon2D
-class_name Arrow
-
-@onready var inner := $Inner
-@onready var player := $AnimationPlayer
-
-@export_color_no_alpha var normal_color: Color = Color.WHITE
-@export_color_no_alpha var done_color: Color = Color.KHAKI
-
-var dir: Global.DIRS = Global.DIRS.RIGHT :
- get:
- return dir
- set(v):
- match v:
- Global.DIRS.LEFT: rotation = PI
- Global.DIRS.RIGHT: rotation = 0
- Global.DIRS.UP: rotation = 3*PI/2
- Global.DIRS.DOWN: rotation = PI/2
- dir = v
-
-var state: Global.ARROW_STATE = Global.ARROW_STATE.NORMAL :
- get:
- return state
- set(v):
- match v:
- Global.ARROW_STATE.NORMAL:
- if state == Global.ARROW_STATE.DONE:
- player.play('done-error')
- else:
- inner.color = normal_color
- Global.ARROW_STATE.DONE: inner.color = done_color
- Global.ARROW_STATE.ERROR: player.play('error')
- state = v
diff --git a/game/arrow/arrow.tscn b/game/arrow/arrow.tscn
deleted file mode 100644
index 61c6356..0000000
--- a/game/arrow/arrow.tscn
+++ /dev/null
@@ -1,88 +0,0 @@
-[gd_scene load_steps=6 format=3 uid="uid://cjc46cgqe1r20"]
-
-[ext_resource type="Script" path="res://game/arrow/arrow.gd" id="1_35aap"]
-
-[sub_resource type="Animation" id="Animation_pyfum"]
-length = 0.001
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Inner:color")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Color(1, 1, 1, 1)]
-}
-tracks/1/type = "value"
-tracks/1/imported = false
-tracks/1/enabled = true
-tracks/1/path = NodePath(".:modulate")
-tracks/1/interp = 1
-tracks/1/loop_wrap = true
-tracks/1/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Color(1, 1, 1, 1)]
-}
-
-[sub_resource type="Animation" id="Animation_qo54c"]
-resource_name = "done-error"
-length = 0.5
-step = 0.05
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Inner:color")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0, 0.15, 0.3, 0.5),
-"transitions": PackedFloat32Array(1, 1, 1, 1),
-"update": 0,
-"values": [Color(0.941176, 0.901961, 0.54902, 1), Color(0.85098, 0.27451, 0.282353, 1), Color(0.85098, 0.27451, 0.282353, 1), Color(1, 1, 1, 1)]
-}
-
-[sub_resource type="Animation" id="Animation_1cugm"]
-resource_name = "error"
-length = 0.5
-step = 0.05
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Inner:color")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0, 0.15, 0.3, 0.5),
-"transitions": PackedFloat32Array(1, 1, 1, 1),
-"update": 0,
-"values": [Color(1, 1, 1, 1), Color(0.85098, 0.27451, 0.282353, 1), Color(0.85098, 0.27451, 0.282353, 1), Color(1, 1, 1, 1)]
-}
-
-[sub_resource type="AnimationLibrary" id="AnimationLibrary_hujhs"]
-_data = {
-"RESET": SubResource("Animation_pyfum"),
-"done-error": SubResource("Animation_qo54c"),
-"error": SubResource("Animation_1cugm")
-}
-
-[node name="Outline" type="Polygon2D"]
-color = Color(0, 0, 0, 1)
-offset = Vector2(-32, -32)
-antialiased = true
-polygon = PackedVector2Array(0, 20, 0, 44, 20, 44, 20, 64, 32, 64, 64, 32, 32, 0, 20, 0, 20, 20)
-script = ExtResource("1_35aap")
-
-[node name="Inner" type="Polygon2D" parent="."]
-offset = Vector2(-32, -32)
-antialiased = true
-polygon = PackedVector2Array(4, 24, 4, 40, 24, 40, 24, 60, 30, 60, 58, 32, 30, 4, 24, 4, 24, 24)
-
-[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
-libraries = {
-"": SubResource("AnimationLibrary_hujhs")
-}
diff --git a/game/game.gd b/game/game.gd
deleted file mode 100644
index a8e24a5..0000000
--- a/game/game.gd
+++ /dev/null
@@ -1,111 +0,0 @@
-extends Control
-
-signal solved
-signal input(correct: bool)
-
-var InputHandler := preload('res://game/input.gd')
-
-const all_data := preload('res://game/gems/data.gd').data
-const ArrowScene := preload('res://game/arrow/arrow.tscn')
-const total_width := 1920
-const space_between_arrows := 8
-const img_size := 48
-
-@onready var icons := $Icons
-@onready var name_label := $Name
-@onready var arrows_container := $Arrows
-@onready var error_timer := $ErrorTimer
-@onready var player := $AnimationPlayer
-
-var pos := -1
-var arrow_count := 0
-var raw_dirs: Array[Global.DIRS] = []
-var arrows: Array[Arrow] = []
-var in_error := true
-var next_codes = []
-
-func _on_error_timer_timeout() -> void:
- in_error = false
-
-func dir_input(dir: Global.DIRS) -> void:
- if in_error:
- return
-
- if pos >= len(raw_dirs):
- return
-
- if dir == raw_dirs[pos]:
- arrows[pos].state = Global.ARROW_STATE.DONE
- pos += 1
- if pos == arrow_count:
- solved.emit()
- start_new_round()
- input.emit(true)
- else:
- in_error = true
- error_timer.start()
- arrows[pos].state = Global.ARROW_STATE.ERROR
- for a in arrows:
- a.state = Global.ARROW_STATE.NORMAL
- pos = 0
- input.emit(false)
-
-
-func start_new_round() -> void:
- InputHandler.start = null
- var data = next_codes.pop_front()
- next_codes.append(all_data[randi() % all_data.size()])
-
- icons.update(data[1], next_codes)
-
- in_error = true
-
- if pos != -1:
- raw_dirs.clear()
-
- player.play('round-end')
- await player.animation_finished
-
- for n in arrows:
- arrows_container.remove_child(n)
- n.queue_free()
-
- arrows.clear()
-
- pos = 0
- name_label.text = data[0]
- raw_dirs.append_array(data[2])
-
- arrow_count = len(data[2])
- var total_arrow_width := 64 * arrow_count + space_between_arrows * (arrow_count - 1)
- var start_x := (total_width - total_arrow_width) / 2.0
- for d in data[2]:
- var a: Arrow = ArrowScene.instantiate()
- a.set_position(Vector2(start_x, 500))
- a.dir = d
- arrows.append(a)
- arrows_container.add_child(a)
- start_x += 64 + space_between_arrows
-
- player.play('round-start')
- await player.animation_finished
-
- in_error = false
-
-
-func _input(event: InputEvent) -> void:
- var d = InputHandler._input(event)
- if d != null:
- dir_input(d)
-
- if event.is_action_released('escape'):
- get_tree().change_scene_to_packed(load('res://main_menu/main_menu.tscn'))
-
-func _ready() -> void:
- randomize()
- for i in range(8):
- next_codes.append(all_data[randi() % all_data.size()])
- icons.update(null, next_codes)
- start_new_round()
- solved.connect($StatContainer/Solved._on_solved)
- input.connect($StatContainer/Combo._on_input)
diff --git a/game/game.tscn b/game/game.tscn
index b2bc340..ca9d111 100644
--- a/game/game.tscn
+++ b/game/game.tscn
@@ -1,306 +1,12 @@
-[gd_scene load_steps=13 format=3 uid="uid://c4sq21c5gf4tr"]
+[gd_scene load_steps=12 format=3 uid="uid://c4sq21c5gf4tr"]
-[ext_resource type="Script" path="res://game/game.gd" id="1_dkhe3"]
-[ext_resource type="Texture2D" uid="uid://ctuppqhifm5nr" path="res://game/gems/placeholder.png" id="2_1o8ih"]
-[ext_resource type="Script" path="res://game/icons.gd" id="2_rgbt2"]
-
-[sub_resource type="GDScript" id="GDScript_sce7k"]
-script/source = "extends Label
-
-var count = 0
-
-func _on_solved() -> void:
- count += 1
- text = str(count)
-"
-
-[sub_resource type="GDScript" id="GDScript_ngbu4"]
-script/source = "extends Label
-
-var count = 0
-
-func _on_input(correct: bool) -> void:
- if correct:
- count += 1
- else:
- count = 0
- text = str(count)
-"
-
-[sub_resource type="Animation" id="Animation_v1pyg"]
-length = 0.001
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Icon:self_modulate")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Color(1, 1, 1, 1)]
-}
-tracks/1/type = "bezier"
-tracks/1/imported = false
-tracks/1/enabled = true
-tracks/1/path = NodePath("Icon:position:x")
-tracks/1/interp = 1
-tracks/1/loop_wrap = true
-tracks/1/keys = {
-"handle_modes": PackedInt32Array(0),
-"points": PackedFloat32Array(72, -0.25, 0, 0.2, -1),
-"times": PackedFloat32Array(0)
-}
-tracks/2/type = "value"
-tracks/2/imported = false
-tracks/2/enabled = true
-tracks/2/path = NodePath("Icon1:position")
-tracks/2/interp = 1
-tracks/2/loop_wrap = true
-tracks/2/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(264, 136)]
-}
-tracks/3/type = "value"
-tracks/3/imported = false
-tracks/3/enabled = true
-tracks/3/path = NodePath("Icon2:position")
-tracks/3/interp = 1
-tracks/3/loop_wrap = true
-tracks/3/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(456, 136)]
-}
-tracks/4/type = "value"
-tracks/4/imported = false
-tracks/4/enabled = true
-tracks/4/path = NodePath("Icon3:position")
-tracks/4/interp = 1
-tracks/4/loop_wrap = true
-tracks/4/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(648, 136)]
-}
-tracks/5/type = "value"
-tracks/5/imported = false
-tracks/5/enabled = true
-tracks/5/path = NodePath("Icon4:position")
-tracks/5/interp = 1
-tracks/5/loop_wrap = true
-tracks/5/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(840, 136)]
-}
-tracks/6/type = "value"
-tracks/6/imported = false
-tracks/6/enabled = true
-tracks/6/path = NodePath("Icon5:position")
-tracks/6/interp = 1
-tracks/6/loop_wrap = true
-tracks/6/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(1032, 136)]
-}
-tracks/7/type = "value"
-tracks/7/imported = false
-tracks/7/enabled = true
-tracks/7/path = NodePath("Icon6:position")
-tracks/7/interp = 1
-tracks/7/loop_wrap = true
-tracks/7/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(1224, 136)]
-}
-tracks/8/type = "value"
-tracks/8/imported = false
-tracks/8/enabled = true
-tracks/8/path = NodePath("Icon7:position")
-tracks/8/interp = 1
-tracks/8/loop_wrap = true
-tracks/8/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(1416, 136)]
-}
-tracks/9/type = "value"
-tracks/9/imported = false
-tracks/9/enabled = true
-tracks/9/path = NodePath("Icon8:position")
-tracks/9/interp = 1
-tracks/9/loop_wrap = true
-tracks/9/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Vector2(1608, 136)]
-}
-tracks/10/type = "value"
-tracks/10/imported = false
-tracks/10/enabled = true
-tracks/10/path = NodePath("Icon8:self_modulate")
-tracks/10/interp = 1
-tracks/10/loop_wrap = true
-tracks/10/keys = {
-"times": PackedFloat32Array(0),
-"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [Color(1, 1, 1, 0)]
-}
-
-[sub_resource type="Animation" id="Animation_bevbe"]
-resource_name = "round-change"
-length = 0.4
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Icon:self_modulate")
-tracks/0/interp = 1
-tracks/0/loop_wrap = false
-tracks/0/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)]
-}
-tracks/1/type = "bezier"
-tracks/1/imported = false
-tracks/1/enabled = true
-tracks/1/path = NodePath("Icon:position:x")
-tracks/1/interp = 1
-tracks/1/loop_wrap = true
-tracks/1/keys = {
-"handle_modes": PackedInt32Array(0, 0),
-"points": PackedFloat32Array(72, -0.25, 0, 0.2, -1, -520, 0, 0, 0, 0),
-"times": PackedFloat32Array(0, 0.4)
-}
-tracks/2/type = "value"
-tracks/2/imported = false
-tracks/2/enabled = true
-tracks/2/path = NodePath("Icon1:position")
-tracks/2/interp = 2
-tracks/2/loop_wrap = false
-tracks/2/keys = {
-"times": PackedFloat32Array(0.0001, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Vector2(264, 136), Vector2(72, 136)]
-}
-tracks/3/type = "value"
-tracks/3/imported = false
-tracks/3/enabled = true
-tracks/3/path = NodePath("Icon2:position")
-tracks/3/interp = 2
-tracks/3/loop_wrap = false
-tracks/3/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Vector2(456, 136), Vector2(264, 136)]
-}
-tracks/4/type = "value"
-tracks/4/imported = false
-tracks/4/enabled = true
-tracks/4/path = NodePath("Icon3:position")
-tracks/4/interp = 2
-tracks/4/loop_wrap = false
-tracks/4/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Vector2(648, 136), Vector2(456, 136)]
-}
-tracks/5/type = "value"
-tracks/5/imported = false
-tracks/5/enabled = true
-tracks/5/path = NodePath("Icon4:position")
-tracks/5/interp = 2
-tracks/5/loop_wrap = false
-tracks/5/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Vector2(840, 136), Vector2(648, 136)]
-}
-tracks/6/type = "value"
-tracks/6/imported = false
-tracks/6/enabled = true
-tracks/6/path = NodePath("Icon5:position")
-tracks/6/interp = 2
-tracks/6/loop_wrap = false
-tracks/6/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Vector2(1032, 136), Vector2(840, 136)]
-}
-tracks/7/type = "value"
-tracks/7/imported = false
-tracks/7/enabled = true
-tracks/7/path = NodePath("Icon6:position")
-tracks/7/interp = 2
-tracks/7/loop_wrap = false
-tracks/7/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Vector2(1224, 136), Vector2(1032, 136)]
-}
-tracks/8/type = "value"
-tracks/8/imported = false
-tracks/8/enabled = true
-tracks/8/path = NodePath("Icon7:position")
-tracks/8/interp = 2
-tracks/8/loop_wrap = false
-tracks/8/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Vector2(1416, 136), Vector2(1224, 136)]
-}
-tracks/9/type = "value"
-tracks/9/imported = false
-tracks/9/enabled = true
-tracks/9/path = NodePath("Icon8:position")
-tracks/9/interp = 2
-tracks/9/loop_wrap = false
-tracks/9/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Vector2(1608, 136), Vector2(1416, 136)]
-}
-tracks/10/type = "value"
-tracks/10/imported = false
-tracks/10/enabled = true
-tracks/10/path = NodePath("Icon8:self_modulate")
-tracks/10/interp = 1
-tracks/10/loop_wrap = true
-tracks/10/keys = {
-"times": PackedFloat32Array(0, 0.4),
-"transitions": PackedFloat32Array(1, 1),
-"update": 0,
-"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)]
-}
-
-[sub_resource type="AnimationLibrary" id="AnimationLibrary_bt825"]
-_data = {
-"RESET": SubResource("Animation_v1pyg"),
-"round-change": SubResource("Animation_bevbe")
-}
+[ext_resource type="Script" path="res://src/Game/Game.cs" id="1_k7a4x"]
+[ext_resource type="Script" path="res://src/Game/Stats.cs" id="2_u5dw2"]
+[ext_resource type="Script" path="res://src/Game/Icons.cs" id="3_xkfay"]
+[ext_resource type="AudioStream" uid="uid://u23ytxxg1iqg" path="res://sounds/swipe_ok.wav" id="4_2w4vj"]
+[ext_resource type="AudioStream" uid="uid://b4pdua27sq0f7" path="res://music/_music.tres" id="4_arwoj"]
+[ext_resource type="Script" path="res://src/Game/Audio.cs" id="4_xhtam"]
+[ext_resource type="AudioStream" uid="uid://c3dpfownsatsb" path="res://sounds/error.wav" id="5_pklm0"]
[sub_resource type="Animation" id="Animation_2hnmi"]
length = 0.001
@@ -395,6 +101,7 @@ _data = {
[node name="Gem" type="Control"]
layout_mode = 3
+anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 20.0
@@ -403,13 +110,14 @@ offset_right = -20.0
offset_bottom = -20.0
grow_horizontal = 2
grow_vertical = 2
-script = ExtResource("1_dkhe3")
+script = ExtResource("1_k7a4x")
[node name="StatContainer" type="GridContainer" parent="."]
layout_mode = 0
offset_right = 132.0
offset_bottom = 104.0
columns = 2
+script = ExtResource("2_u5dw2")
[node name="SolvedT" type="Label" parent="StatContainer"]
layout_mode = 2
@@ -420,7 +128,6 @@ custom_minimum_size = Vector2(50, 0)
layout_mode = 2
text = "0"
horizontal_alignment = 2
-script = SubResource("GDScript_sce7k")
[node name="ComboT" type="Label" parent="StatContainer"]
layout_mode = 2
@@ -430,62 +137,10 @@ text = "Combo: "
layout_mode = 2
text = "0"
horizontal_alignment = 2
-script = SubResource("GDScript_ngbu4")
[node name="Icons" type="Node2D" parent="."]
-position = Vector2(448, 128)
-script = ExtResource("2_rgbt2")
-
-[node name="AnimationPlayer" type="AnimationPlayer" parent="Icons"]
-libraries = {
-"": SubResource("AnimationLibrary_bt825")
-}
-
-[node name="Icon" type="Sprite2D" parent="Icons"]
-position = Vector2(72, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
-
-[node name="Icon1" type="Sprite2D" parent="Icons"]
-position = Vector2(264, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
-
-[node name="Icon2" type="Sprite2D" parent="Icons"]
-position = Vector2(456, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
-
-[node name="Icon3" type="Sprite2D" parent="Icons"]
-position = Vector2(648, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
-
-[node name="Icon4" type="Sprite2D" parent="Icons"]
-position = Vector2(840, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
-
-[node name="Icon5" type="Sprite2D" parent="Icons"]
-position = Vector2(1032, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
-
-[node name="Icon6" type="Sprite2D" parent="Icons"]
-position = Vector2(1224, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
-
-[node name="Icon7" type="Sprite2D" parent="Icons"]
-position = Vector2(1416, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
-
-[node name="Icon8" type="Sprite2D" parent="Icons"]
-self_modulate = Color(1, 1, 1, 0)
-position = Vector2(1608, 136)
-scale = Vector2(3, 3)
-texture = ExtResource("2_1o8ih")
+position = Vector2(448, 264)
+script = ExtResource("3_xkfay")
[node name="Name" type="Label" parent="."]
layout_mode = 0
@@ -496,14 +151,29 @@ offset_bottom = 434.0
text = "Teseoxfugholxcfyhngioldyfhgoiljxcnfohgibncdxflhjnfgdlkh"
[node name="Arrows" type="Node2D" parent="."]
-
-[node name="ErrorTimer" type="Timer" parent="."]
-wait_time = 0.5
-one_shot = true
+position = Vector2(0, 500)
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_wklcx")
}
-[connection signal="timeout" from="ErrorTimer" to="." method="_on_error_timer_timeout"]
+[node name="Audio" type="Node" parent="."]
+script = ExtResource("4_xhtam")
+
+[node name="MusicPlayer" type="AudioStreamPlayer" parent="Audio"]
+stream = ExtResource("4_arwoj")
+volume_db = -14.0
+autoplay = true
+bus = &"Music"
+
+[node name="OkSound" type="AudioStreamPlayer" parent="Audio"]
+stream = ExtResource("4_2w4vj")
+max_polyphony = 10
+bus = &"Sound"
+
+[node name="ErrorSound" type="AudioStreamPlayer" parent="Audio"]
+stream = ExtResource("5_pklm0")
+volume_db = -8.0
+max_polyphony = 10
+bus = &"Sound"
diff --git a/game/icons.gd b/game/icons.gd
deleted file mode 100644
index 8d2624c..0000000
--- a/game/icons.gd
+++ /dev/null
@@ -1,26 +0,0 @@
-extends Node2D
-
-@onready var player := $AnimationPlayer
-@onready var main_icon := $Icon
-@onready var icons := [
- $Icon1,
- $Icon2,
- $Icon3,
- $Icon4,
- $Icon5,
- $Icon6,
- $Icon7,
- $Icon8
-]
-
-func update(main, queue) -> void:
- if main != null:
- player.play('round-change')
- await player.animation_finished
-
- main_icon.texture = main
-
- for i in range(8):
- icons[i].texture = queue[i][1]
-
- player.play('RESET')
diff --git a/game/input.gd b/game/input.gd
deleted file mode 100644
index 483504a..0000000
--- a/game/input.gd
+++ /dev/null
@@ -1,37 +0,0 @@
-extends Object
-
-static var start = null
-
-static func calc_swipe(end):
- if start == null:
- return null
- var delta = end - start
- var biggest = max(abs(delta.x), abs(delta.y))
- if biggest < 50:
- return null
- if abs(delta.x) > abs(delta.y):
- if delta.x < 0:
- return Global.DIRS.LEFT
- else:
- return Global.DIRS.RIGHT
- else:
- if delta.y < 0:
- return Global.DIRS.UP
- else:
- return Global.DIRS.DOWN
-
-static func _input(event: InputEvent):
- var d = null
- if event.is_action_pressed('left_mouse_button'):
- start = event.get_position()
- if event.is_action_released('left_mouse_button'):
- d = calc_swipe(event.get_position())
- if event.is_action_released('key_up'):
- d = Global.DIRS.UP
- if event.is_action_released('key_down'):
- d = Global.DIRS.DOWN
- if event.is_action_released('key_left'):
- d = Global.DIRS.LEFT
- if event.is_action_released('key_right'):
- d = Global.DIRS.RIGHT
- return d
diff --git a/global.gd b/global.gd
deleted file mode 100644
index bb72a53..0000000
--- a/global.gd
+++ /dev/null
@@ -1,4 +0,0 @@
-extends Node
-
-enum DIRS {LEFT, RIGHT, UP, DOWN}
-enum ARROW_STATE {NORMAL, DONE, ERROR}
diff --git a/icon_android_adaptive.png b/icon_android_adaptive.png
new file mode 100644
index 0000000..63f5f8e
Binary files /dev/null and b/icon_android_adaptive.png differ
diff --git a/icon_android_adaptive.png.import b/icon_android_adaptive.png.import
new file mode 100644
index 0000000..2f2251c
--- /dev/null
+++ b/icon_android_adaptive.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ycsqasqyilmw"
+path="res://.godot/imported/icon_android_adaptive.png-a8e85ea9821a16cc4dd84682a0241110.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon_android_adaptive.png"
+dest_files=["res://.godot/imported/icon_android_adaptive.png-a8e85ea9821a16cc4dd84682a0241110.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/icon_android_main.png b/icon_android_main.png
new file mode 100644
index 0000000..2597623
Binary files /dev/null and b/icon_android_main.png differ
diff --git a/icon_android_main.png.import b/icon_android_main.png.import
new file mode 100644
index 0000000..0e2150d
--- /dev/null
+++ b/icon_android_main.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c20x4nkjgf8bc"
+path="res://.godot/imported/icon_android_main.png-0753afcb85198f5873b967a43b5a701f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon_android_main.png"
+dest_files=["res://.godot/imported/icon_android_main.png-0753afcb85198f5873b967a43b5a701f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/main_menu/main_menu.tscn b/main_menu/main_menu.tscn
index 7e87fca..2e21c11 100644
--- a/main_menu/main_menu.tscn
+++ b/main_menu/main_menu.tscn
@@ -1,19 +1,11 @@
-[gd_scene load_steps=3 format=3 uid="uid://bat14jn36bm8h"]
+[gd_scene load_steps=7 format=3 uid="uid://bat14jn36bm8h"]
-[sub_resource type="GDScript" id="GDScript_iu3pc"]
-script/source = "extends Button
-
-func _pressed() -> void:
- get_tree().change_scene_to_packed(load('res://game/game.tscn'))
-"
-
-[sub_resource type="GDScript" id="GDScript_7qewh"]
-script/source = "extends Button
-
-func _pressed() -> void:
- get_tree().root.propagate_notification(NOTIFICATION_WM_CLOSE_REQUEST)
- get_tree().quit()
-"
+[ext_resource type="Script" path="res://src/MainMenu.cs" id="1_av5cs"]
+[ext_resource type="Texture2D" uid="uid://douclisbiuxji" path="res://main_menu/sound_on.png" id="2_5sfx4"]
+[ext_resource type="Texture2D" uid="uid://c8nr5inhnhliv" path="res://main_menu/sound_off.png" id="3_03fxv"]
+[ext_resource type="Texture2D" uid="uid://dv2cueufmljpv" path="res://main_menu/music_on.png" id="4_7h5nd"]
+[ext_resource type="Texture2D" uid="uid://srex1nvup3xx" path="res://main_menu/music_off.png" id="5_0dja4"]
+[ext_resource type="Script" path="res://src/TextureToggleButton.cs" id="6_bmwx5"]
[node name="Control" type="Control"]
layout_mode = 3
@@ -26,6 +18,7 @@ offset_right = -50.0
offset_bottom = -50.0
grow_horizontal = 2
grow_vertical = 2
+script = ExtResource("1_av5cs")
[node name="StartButton" type="Button" parent="."]
layout_mode = 1
@@ -40,20 +33,145 @@ focus_mode = 0
theme_override_font_sizes/font_size = 128
text = " Play Game "
flat = true
-script = SubResource("GDScript_iu3pc")
[node name="ExitButton" type="Button" parent="."]
layout_mode = 1
anchors_preset = -1
-anchor_left = 0.85
-anchor_top = 0.9
+anchor_left = 0.8
+anchor_top = 0.85
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 0
grow_vertical = 0
focus_mode = 0
-theme_override_colors/font_color = Color(0.8, 0.16, 0.16, 1)
+theme_override_colors/font_color = Color(0.9, 0.09, 0.09, 1)
theme_override_font_sizes/font_size = 48
text = "Exit"
flat = true
-script = SubResource("GDScript_7qewh")
+
+[node name="Settings" type="HBoxContainer" parent="."]
+layout_mode = 1
+anchors_preset = 2
+anchor_top = 1.0
+anchor_bottom = 1.0
+offset_top = -40.0
+offset_right = 40.0
+grow_vertical = 0
+
+[node name="SoundToggle" type="BaseButton" parent="Settings"]
+_import_path = NodePath("")
+unique_name_in_owner = false
+process_mode = 0
+process_priority = 0
+process_physics_priority = 0
+process_thread_group = 0
+editor_description = ""
+visible = true
+modulate = Color(1, 1, 1, 1)
+self_modulate = Color(0.875, 0.875, 0.875, 1)
+show_behind_parent = false
+top_level = false
+clip_children = 0
+light_mask = 1
+visibility_layer = 1
+z_index = 0
+z_as_relative = true
+y_sort_enabled = false
+texture_filter = 0
+texture_repeat = 0
+material = null
+use_parent_material = false
+clip_contents = false
+custom_minimum_size = Vector2(0, 0)
+layout_direction = 0
+layout_mode = 2
+size_flags_horizontal = 1
+size_flags_vertical = 1
+size_flags_stretch_ratio = 1.0
+auto_translate = true
+localize_numeral_system = true
+tooltip_text = ""
+focus_neighbor_left = NodePath("")
+focus_neighbor_top = NodePath("")
+focus_neighbor_right = NodePath("")
+focus_neighbor_bottom = NodePath("")
+focus_next = NodePath("")
+focus_previous = NodePath("")
+focus_mode = 2
+mouse_filter = 0
+mouse_force_pass_scroll_events = true
+mouse_default_cursor_shape = 0
+theme = null
+theme_type_variation = &""
+disabled = false
+toggle_mode = false
+button_pressed = false
+action_mode = 1
+button_mask = 1
+keep_pressed_outside = false
+button_group = null
+shortcut = null
+shortcut_feedback = true
+shortcut_in_tooltip = true
+script = ExtResource("6_bmwx5")
+FalseTexture = ExtResource("2_5sfx4")
+TrueTexture = ExtResource("3_03fxv")
+
+[node name="MusicToggle" type="BaseButton" parent="Settings"]
+_import_path = NodePath("")
+unique_name_in_owner = false
+process_mode = 0
+process_priority = 0
+process_physics_priority = 0
+process_thread_group = 0
+editor_description = ""
+visible = true
+modulate = Color(1, 1, 1, 1)
+self_modulate = Color(0.875, 0.875, 0.875, 1)
+show_behind_parent = false
+top_level = false
+clip_children = 0
+light_mask = 1
+visibility_layer = 1
+z_index = 0
+z_as_relative = true
+y_sort_enabled = false
+texture_filter = 0
+texture_repeat = 0
+material = null
+use_parent_material = false
+clip_contents = false
+custom_minimum_size = Vector2(0, 0)
+layout_direction = 0
+layout_mode = 2
+size_flags_horizontal = 1
+size_flags_vertical = 1
+size_flags_stretch_ratio = 1.0
+auto_translate = true
+localize_numeral_system = true
+tooltip_text = ""
+focus_neighbor_left = NodePath("")
+focus_neighbor_top = NodePath("")
+focus_neighbor_right = NodePath("")
+focus_neighbor_bottom = NodePath("")
+focus_next = NodePath("")
+focus_previous = NodePath("")
+focus_mode = 2
+mouse_filter = 0
+mouse_force_pass_scroll_events = true
+mouse_default_cursor_shape = 0
+theme = null
+theme_type_variation = &""
+disabled = false
+toggle_mode = false
+button_pressed = false
+action_mode = 1
+button_mask = 1
+keep_pressed_outside = false
+button_group = null
+shortcut = null
+shortcut_feedback = true
+shortcut_in_tooltip = true
+script = ExtResource("6_bmwx5")
+FalseTexture = ExtResource("4_7h5nd")
+TrueTexture = ExtResource("5_0dja4")
diff --git a/main_menu/music_off.png b/main_menu/music_off.png
new file mode 100644
index 0000000..1cb733a
Binary files /dev/null and b/main_menu/music_off.png differ
diff --git a/main_menu/music_off.png.import b/main_menu/music_off.png.import
new file mode 100644
index 0000000..65610a4
--- /dev/null
+++ b/main_menu/music_off.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://srex1nvup3xx"
+path="res://.godot/imported/music_off.png-df269b29cf7b9b15af5566f9b7842386.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://main_menu/music_off.png"
+dest_files=["res://.godot/imported/music_off.png-df269b29cf7b9b15af5566f9b7842386.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/main_menu/music_on.png b/main_menu/music_on.png
new file mode 100644
index 0000000..8c5d652
Binary files /dev/null and b/main_menu/music_on.png differ
diff --git a/main_menu/music_on.png.import b/main_menu/music_on.png.import
new file mode 100644
index 0000000..3aa501a
--- /dev/null
+++ b/main_menu/music_on.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dv2cueufmljpv"
+path="res://.godot/imported/music_on.png-85eca01b59a27fc90974c5dc1cc6989a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://main_menu/music_on.png"
+dest_files=["res://.godot/imported/music_on.png-85eca01b59a27fc90974c5dc1cc6989a.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/main_menu/sound_off.png b/main_menu/sound_off.png
new file mode 100644
index 0000000..397b6c9
Binary files /dev/null and b/main_menu/sound_off.png differ
diff --git a/main_menu/sound_off.png.import b/main_menu/sound_off.png.import
new file mode 100644
index 0000000..7ed4f92
--- /dev/null
+++ b/main_menu/sound_off.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c8nr5inhnhliv"
+path="res://.godot/imported/sound_off.png-14145494ed899d3cf624b0f44e93c9dc.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://main_menu/sound_off.png"
+dest_files=["res://.godot/imported/sound_off.png-14145494ed899d3cf624b0f44e93c9dc.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/main_menu/sound_on.png b/main_menu/sound_on.png
new file mode 100644
index 0000000..360d584
Binary files /dev/null and b/main_menu/sound_on.png differ
diff --git a/main_menu/sound_on.png.import b/main_menu/sound_on.png.import
new file mode 100644
index 0000000..8f241e9
--- /dev/null
+++ b/main_menu/sound_on.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://douclisbiuxji"
+path="res://.godot/imported/sound_on.png-937b2ce2011fd25a7d8d80a1b1918374.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://main_menu/sound_on.png"
+dest_files=["res://.godot/imported/sound_on.png-937b2ce2011fd25a7d8d80a1b1918374.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/music/Retro Arcade.mp3 b/music/Retro Arcade.mp3
new file mode 100644
index 0000000..42e509f
Binary files /dev/null and b/music/Retro Arcade.mp3 differ
diff --git a/music/Retro Arcade.mp3.import b/music/Retro Arcade.mp3.import
new file mode 100644
index 0000000..e689c9c
--- /dev/null
+++ b/music/Retro Arcade.mp3.import
@@ -0,0 +1,19 @@
+[remap]
+
+importer="mp3"
+type="AudioStreamMP3"
+uid="uid://c70my28fdjy2a"
+path="res://.godot/imported/Retro Arcade.mp3-c2fb5aecbd1645c267f1f4010361e78c.mp3str"
+
+[deps]
+
+source_file="res://music/Retro Arcade.mp3"
+dest_files=["res://.godot/imported/Retro Arcade.mp3-c2fb5aecbd1645c267f1f4010361e78c.mp3str"]
+
+[params]
+
+loop=false
+loop_offset=0
+bpm=0
+beat_count=0
+bar_beats=4
diff --git a/music/_music.tres b/music/_music.tres
new file mode 100644
index 0000000..c5334f1
--- /dev/null
+++ b/music/_music.tres
@@ -0,0 +1,8 @@
+[gd_resource type="AudioStreamRandomizer" load_steps=2 format=3 uid="uid://b4pdua27sq0f7"]
+
+[ext_resource type="AudioStream" uid="uid://c70my28fdjy2a" path="res://music/Retro Arcade.mp3" id="1_jonx2"]
+
+[resource]
+streams_count = 1
+stream_0/stream = ExtResource("1_jonx2")
+stream_0/weight = 1.0
diff --git a/music/sources.txt b/music/sources.txt
new file mode 100644
index 0000000..c8ae124
--- /dev/null
+++ b/music/sources.txt
@@ -0,0 +1 @@
+Retro Arcade: https://soundcloud.com/beat-mekanik/retro-arcade
diff --git a/game/gems/placeholder.png b/placeholder.png
similarity index 100%
rename from game/gems/placeholder.png
rename to placeholder.png
diff --git a/game/gems/placeholder.png.import b/placeholder.png.import
similarity index 71%
rename from game/gems/placeholder.png.import
rename to placeholder.png.import
index b58947b..a7c7467 100644
--- a/game/gems/placeholder.png.import
+++ b/placeholder.png.import
@@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://ctuppqhifm5nr"
-path="res://.godot/imported/placeholder.png-7df2040f50328a788de3559fa4c98f44.ctex"
+path="res://.godot/imported/placeholder.png-ef21141e6f7fef7ccb4b638348400c3b.ctex"
metadata={
"vram_texture": false
}
[deps]
-source_file="res://game/gems/placeholder.png"
-dest_files=["res://.godot/imported/placeholder.png-7df2040f50328a788de3559fa4c98f44.ctex"]
+source_file="res://placeholder.png"
+dest_files=["res://.godot/imported/placeholder.png-ef21141e6f7fef7ccb4b638348400c3b.ctex"]
[params]
diff --git a/project.godot b/project.godot
index 95c446b..8dacb7e 100644
--- a/project.godot
+++ b/project.godot
@@ -8,21 +8,22 @@
config_version=5
+[CustomResourceRegister]
+
+ScriptsFolder="res://src/"
+ClassPrefix=""
+
[application]
config/name="Hellswipers"
config/version="1.1.0"
run/main_scene="res://main_menu/main_menu.tscn"
-config/features=PackedStringArray("4.2", "Mobile")
+config/features=PackedStringArray("4.2", "C#", "Mobile")
boot_splash/show_image=false
boot_splash/fullsize=false
boot_splash/use_filter=false
config/icon="res://icon.svg"
-[autoload]
-
-Global="*res://global.gd"
-
[display]
window/size/viewport_width=1920
@@ -31,10 +32,13 @@ window/size/mode=3
window/size/borderless=true
window/stretch/mode="canvas_items"
-[editor]
+[dotnet]
-version_control/plugin_name="GitPlugin"
-version_control/autoload_on_startup=true
+project/assembly_name="Hellswipers"
+
+[editor_plugins]
+
+enabled=PackedStringArray()
[file_customization]
@@ -49,11 +53,6 @@ theme/custom_font="res://TitilliumWeb-Bold.ttf"
[input]
-left_mouse_button={
-"deadzone": 0.5,
-"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
-]
-}
key_up={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)
diff --git a/sounds/error.wav b/sounds/error.wav
new file mode 100644
index 0000000..8b593cc
Binary files /dev/null and b/sounds/error.wav differ
diff --git a/sounds/error.wav.import b/sounds/error.wav.import
new file mode 100644
index 0000000..5851818
--- /dev/null
+++ b/sounds/error.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://c3dpfownsatsb"
+path="res://.godot/imported/error.wav-96ee995c279b7ea423bbc5828e047ff6.sample"
+
+[deps]
+
+source_file="res://sounds/error.wav"
+dest_files=["res://.godot/imported/error.wav-96ee995c279b7ea423bbc5828e047ff6.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/sounds/swipe_ok.wav b/sounds/swipe_ok.wav
new file mode 100644
index 0000000..858d03f
Binary files /dev/null and b/sounds/swipe_ok.wav differ
diff --git a/sounds/swipe_ok.wav.import b/sounds/swipe_ok.wav.import
new file mode 100644
index 0000000..abe0878
--- /dev/null
+++ b/sounds/swipe_ok.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://u23ytxxg1iqg"
+path="res://.godot/imported/swipe_ok.wav-db18ef3c501416924852d6b1692ece79.sample"
+
+[deps]
+
+source_file="res://sounds/swipe_ok.wav"
+dest_files=["res://.godot/imported/swipe_ok.wav-db18ef3c501416924852d6b1692ece79.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/src/Game/Arrow.cs b/src/Game/Arrow.cs
new file mode 100644
index 0000000..296fb6b
--- /dev/null
+++ b/src/Game/Arrow.cs
@@ -0,0 +1,44 @@
+using Godot;
+using System;
+
+namespace Hellswipers.Game;
+
+public partial class Arrow : Polygon2D {
+ public enum Dirs { Right, Down, Left, Up }
+
+ private static readonly Color NormalColor = Colors.White;
+ private static readonly Color DoneColor = Colors.Khaki;
+ private static readonly Color ErrorColor = Color.Color8(217, 70, 72);
+
+ private Polygon2D _inner;
+ private bool _done = false;
+ public Dirs CurrentDir { private set; get; }
+
+ public override void _Ready() {
+ _inner = GetNode("Inner");
+ }
+
+ public void SetDir(Dirs dir) {
+ CurrentDir = dir;
+ Rotation = dir switch {
+ Dirs.Right => 0,
+ Dirs.Down => (float)(Math.PI / 2),
+ Dirs.Left => (float)Math.PI,
+ Dirs.Up => (float)(Math.PI * 3 / 2),
+ _ => Rotation
+ };
+ }
+
+ public void Done() {
+ _done = true;
+ _inner.Color = DoneColor;
+ }
+
+ public void Error() {
+ var tween = CreateTween();
+ tween.TweenProperty(_inner, "color", ErrorColor, 0.15);
+ tween.TweenInterval(0.15);
+ tween.TweenProperty(_inner, "color", NormalColor, 0.2);
+ _done = false;
+ }
+}
diff --git a/src/Game/Audio.cs b/src/Game/Audio.cs
new file mode 100644
index 0000000..2293167
--- /dev/null
+++ b/src/Game/Audio.cs
@@ -0,0 +1,16 @@
+using Godot;
+
+namespace Hellswipers.Game;
+
+public partial class Audio : Node {
+ private AudioStreamPlayer _okPlayer;
+ private AudioStreamPlayer _errPlayer;
+
+ public void Ok() => _okPlayer.Play();
+ public void Err() => _errPlayer.Play();
+
+ public override void _Ready() {
+ _okPlayer = GetNode("OkSound");
+ _errPlayer = GetNode("ErrorSound");
+ }
+}
\ No newline at end of file
diff --git a/src/Game/Game.cs b/src/Game/Game.cs
new file mode 100644
index 0000000..7d01450
--- /dev/null
+++ b/src/Game/Game.cs
@@ -0,0 +1,149 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Godot;
+
+namespace Hellswipers.Game;
+
+public partial class Game : Control {
+ private const int TotalWidth = 1920;
+ private const int SpaceBetweenArrows = 8;
+ private const long ErrorLengthMs = 400;
+
+ private PackedScene _arrowScene;
+ private AnimationPlayer _player;
+ private Node2D _arrowsNode;
+ private Label _nameLabel;
+ private Icons _icons;
+
+ private readonly Gem[] _gems = Gem.LoadGems();
+ private readonly Random _rand = new();
+ private readonly Stopwatch _errorWatch = new();
+
+ private readonly Queue _nextGems = new();
+ private readonly List _arrows = new();
+
+ private Gem _current;
+ private bool _disabled = false;
+ private int _pos = -1;
+
+ public delegate void VoidEventHandler();
+ public event VoidEventHandler SwipeOk;
+ public event VoidEventHandler SwipeErr;
+ public event VoidEventHandler Solved;
+
+ private Gem RandomGem() => _gems[_rand.Next(_gems.Length)];
+
+ private async void StartNewRound() {
+ var gem = RandomGem();
+ _icons.Update(gem);
+ _nextGems.Enqueue(gem);
+
+ _current = _nextGems.Dequeue();
+ _disabled = true;
+ var tween = CreateTween();
+ tween.SetParallel();
+ if (_pos != -1) {
+ _arrows.ForEach(v => {
+ var newPos = v.CurrentDir switch {
+ Arrow.Dirs.Right => new Vector2(100, 0),
+ Arrow.Dirs.Down => new Vector2(0, 100),
+ Arrow.Dirs.Left => new Vector2(-100, 0),
+ Arrow.Dirs.Up => new Vector2(0, -100),
+ _ => new Vector2(0, 0)
+ };
+ tween.TweenProperty(v, "position", v.Position + newPos, 0.2);
+ });
+ _player.Play("round-end");
+ await ToSignal(_player, AnimationMixer.SignalName.AnimationFinished);
+
+ _arrows.ForEach(v => {
+ _arrowsNode.RemoveChild(v);
+ v.QueueFree();
+ });
+ _arrows.Clear();
+ tween = CreateTween();
+ tween.SetParallel();
+ }
+
+ _pos = 0;
+ _nameLabel.Text = _current.Name;
+
+ var arrowCount = _current.Dirs.Length;
+ var totalArrowWidth = 64 * arrowCount + SpaceBetweenArrows * (arrowCount - 1);
+ var xPos = (TotalWidth - totalArrowWidth) / 2;
+ foreach (var dir in _current.Dirs) {
+ var arrow = _arrowScene.Instantiate();
+ var startPos = dir switch {
+ Arrow.Dirs.Right => new Vector2(-100, 0),
+ Arrow.Dirs.Down => new Vector2(0, -100),
+ Arrow.Dirs.Left => new Vector2(100, 0),
+ Arrow.Dirs.Up => new Vector2(0, 100),
+ _ => new Vector2(0, 0)
+ };
+ startPos.X += xPos;
+ arrow.Position = startPos;
+ tween.TweenProperty(arrow, "position", new Vector2(xPos, 0), 0.2);
+ arrow.SetDir(dir);
+ _arrows.Add(arrow);
+ _arrowsNode.AddChild(arrow);
+ xPos += 64 + SpaceBetweenArrows;
+ }
+
+ _player.Play("round-start");
+ await ToSignal(_player, AnimationMixer.SignalName.AnimationFinished);
+
+ _disabled = false;
+ }
+
+ private void HandleInput(Arrow.Dirs dir) {
+ if (_disabled) {
+ if (_errorWatch.IsRunning && _errorWatch.ElapsedMilliseconds >= ErrorLengthMs) {
+ _disabled = false;
+ _errorWatch.Stop();
+ } else return;
+ }
+
+ if (_pos >= _current.Dirs.Length) return;
+
+ if (dir == _current.Dirs[_pos]) {
+ _arrows[_pos].Done();
+ _pos++;
+ SwipeOk!.Invoke();
+ if (_pos == _current.Dirs.Length) {
+ Solved!.Invoke();
+ StartNewRound();
+ }
+ } else {
+ _disabled = true;
+ SwipeErr!.Invoke();
+ _errorWatch.Start();
+ _arrows.ForEach(v => v.Error());
+ _pos = 0;
+ }
+ }
+
+ public override void _Ready() {
+ _player = GetNode("AnimationPlayer");
+ _arrowsNode = GetNode("Arrows");
+ _nameLabel = GetNode