commit 0a6a2317bf2c4ce7ea29b4d38c23ea3157d0bed8 Author: Gabriel Kaszewski Date: Sat Jan 24 05:59:34 2026 +0100 init diff --git a/max-effort/.editorconfig b/max-effort/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/max-effort/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/max-effort/.gitattributes b/max-effort/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/max-effort/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/max-effort/.gitignore b/max-effort/.gitignore new file mode 100644 index 0000000..0af181c --- /dev/null +++ b/max-effort/.gitignore @@ -0,0 +1,3 @@ +# Godot 4+ specific ignores +.godot/ +/android/ diff --git a/max-effort/MaxEffort.gdextension b/max-effort/MaxEffort.gdextension new file mode 100644 index 0000000..27a274b --- /dev/null +++ b/max-effort/MaxEffort.gdextension @@ -0,0 +1,14 @@ +[configuration] +entry_symbol = "gdext_rust_init" +compatibility_minimum = 4.5 +reloadable = true + +[libraries] +linux.debug.x86_64 = "res://../rust/target/debug/libmax_effort_lib.so" +linux.release.x86_64 = "res://../rust/target/release/libmax_effort_lib.so" +windows.debug.x86_64 = "res://../rust/target/debug/max-effort-lib.dll" +windows.release.x86_64 = "res://../rust/target/release/max-effort-lib.dll" +macos.debug = "res://../rust/target/debug/libmax_effort_lib.dylib" +macos.release = "res://../rust/target/release/libmax_effort_lib.dylib" +macos.debug.arm64 = "res://../rust/target/debug/libmax_effort_lib.dylib" +macos.release.arm64 = "res://../rust/target/release/libmax_effort_lib.dylib" diff --git a/max-effort/MaxEffort.gdextension.uid b/max-effort/MaxEffort.gdextension.uid new file mode 100644 index 0000000..023e9d0 --- /dev/null +++ b/max-effort/MaxEffort.gdextension.uid @@ -0,0 +1 @@ +uid://ddxl1hldnuqrv diff --git a/max-effort/Objects/bench_press.tscn b/max-effort/Objects/bench_press.tscn new file mode 100644 index 0000000..4b32fc7 --- /dev/null +++ b/max-effort/Objects/bench_press.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=5 format=3 uid="uid://dxq2510ywj1hy"] + +[ext_resource type="GameState" uid="uid://2gma8vvisnqo" path="res://Resources/GameState.tres" id="1_tik8c"] +[ext_resource type="PackedScene" uid="uid://dn8y3bgovnh4a" path="res://Objects/bench_press_stickman.tscn" id="2_0c1tm"] +[ext_resource type="Texture2D" uid="uid://dsovna2tmb4o3" path="res://Sprites/bench.png" id="2_ky8t4"] +[ext_resource type="Texture2D" uid="uid://cbgn8aspf7oi0" path="res://Sprites/barbell.png" id="3_ky8t4"] + +[node name="BenchPress" type="Node"] + +[node name="System" type="BenchPressSystem" parent="."] +game_state = ExtResource("1_tik8c") + +[node name="Bench" type="Sprite2D" parent="."] +position = Vector2(11, 1) +scale = Vector2(2.086, 2.086) +texture = ExtResource("2_ky8t4") + +[node name="BenchPressStickman" parent="." instance=ExtResource("2_0c1tm")] + +[node name="Barbell" type="Sprite2D" parent="."] +position = Vector2(22, -5) +scale = Vector2(2.432, 2.432) +texture = ExtResource("3_ky8t4") + +[node name="LiftSyncController" type="LiftSyncController" parent="." node_paths=PackedStringArray("player_anim", "barbell")] +player_anim = NodePath("../BenchPressStickman") +barbell = NodePath("../Barbell") +game_state = ExtResource("1_tik8c") +animation_name = "default" +bar_positions = Array[Vector2]([Vector2(19, -5), Vector2(19, -19), Vector2(21, -36), Vector2(21, -15), Vector2(23, 3), Vector2(22, 11), Vector2(22, -1), Vector2(22, -1)]) diff --git a/max-effort/Objects/bench_press_stickman.tscn b/max-effort/Objects/bench_press_stickman.tscn new file mode 100644 index 0000000..2475c72 --- /dev/null +++ b/max-effort/Objects/bench_press_stickman.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=10 format=3 uid="uid://dn8y3bgovnh4a"] + +[ext_resource type="Texture2D" uid="uid://dci4cuavfc4la" path="res://Sprites/bench_press0.png" id="1_8snp0"] +[ext_resource type="Texture2D" uid="uid://dya801bkqxdpa" path="res://Sprites/bench_press1.png" id="2_ckjrk"] +[ext_resource type="Texture2D" uid="uid://bbxviq4c0pyju" path="res://Sprites/bench_press2.png" id="3_s2d21"] +[ext_resource type="Texture2D" uid="uid://biu7q8mfw62be" path="res://Sprites/bench_press3.png" id="4_e1c5r"] +[ext_resource type="Texture2D" uid="uid://bg06qtcl207do" path="res://Sprites/bench_press4.png" id="5_pwixy"] +[ext_resource type="Texture2D" uid="uid://bkypgv8rfcd8k" path="res://Sprites/bench_press5.png" id="6_6piga"] +[ext_resource type="Texture2D" uid="uid://warnmdoebwht" path="res://Sprites/bench_press6.png" id="7_ex7t0"] +[ext_resource type="Texture2D" uid="uid://yrorih7pbt0q" path="res://Sprites/bench_press7.png" id="8_as8xi"] + +[sub_resource type="SpriteFrames" id="SpriteFrames_edqll"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": ExtResource("1_8snp0") +}, { +"duration": 1.0, +"texture": ExtResource("2_ckjrk") +}, { +"duration": 1.0, +"texture": ExtResource("3_s2d21") +}, { +"duration": 1.0, +"texture": ExtResource("4_e1c5r") +}, { +"duration": 1.0, +"texture": ExtResource("5_pwixy") +}, { +"duration": 1.0, +"texture": ExtResource("6_6piga") +}, { +"duration": 1.0, +"texture": ExtResource("7_ex7t0") +}, { +"duration": 1.0, +"texture": ExtResource("8_as8xi") +}], +"loop": true, +"name": &"default", +"speed": 12.0 +}] + +[node name="BenchPressStickman" type="AnimatedSprite2D"] +sprite_frames = SubResource("SpriteFrames_edqll") +speed_scale = 0.0 diff --git a/max-effort/Objects/deadlift.tscn b/max-effort/Objects/deadlift.tscn new file mode 100644 index 0000000..984418f --- /dev/null +++ b/max-effort/Objects/deadlift.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=3 format=3 uid="uid://dx1k40qfioaas"] + +[ext_resource type="GameState" uid="uid://2gma8vvisnqo" path="res://Resources/GameState.tres" id="1_n6ace"] +[ext_resource type="Texture2D" uid="uid://cbgn8aspf7oi0" path="res://Sprites/barbell.png" id="2_ltxro"] + +[node name="Deadlift" type="Node"] + +[node name="System" type="DeadliftSystem" parent="." node_paths=PackedStringArray("bar_visual")] +bar_height = 7.0 +bar_visual = NodePath("../Barbell") +end_pos = Vector2(0, -30) +game_state = ExtResource("1_n6ace") + +[node name="Barbell" type="Sprite2D" parent="."] +scale = Vector2(2, 2) +texture = ExtResource("2_ltxro") diff --git a/max-effort/Objects/hazard_animated.tscn b/max-effort/Objects/hazard_animated.tscn new file mode 100644 index 0000000..56a9fb1 --- /dev/null +++ b/max-effort/Objects/hazard_animated.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=2 format=3 uid="uid://bqxc62tofqger"] + +[ext_resource type="GameState" uid="uid://2gma8vvisnqo" path="res://Resources/GameState.tres" id="1_strkh"] + +[node name="HazardAnimated" type="HazardController" node_paths=PackedStringArray("anim_sprite", "click_area", "click_shape")] +anim_sprite = NodePath("AnimatedSprite2D") +click_area = NodePath("Area2D") +click_shape = NodePath("Area2D/CollisionShape2D") +game_state = ExtResource("1_strkh") + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] + +[node name="Area2D" type="Area2D" parent="."] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] diff --git a/max-effort/Resources/Day_Day1.tres b/max-effort/Resources/Day_Day1.tres new file mode 100644 index 0000000..5e3aeb8 --- /dev/null +++ b/max-effort/Resources/Day_Day1.tres @@ -0,0 +1,9 @@ +[gd_resource type="DayConfig" load_steps=3 format=3 uid="uid://d30pwvrr7m72j"] + +[ext_resource type="HazardDef" uid="uid://pgmnp6ev1ark" path="res://Resources/Hazard_GymBro.tres" id="1_qov1i"] +[ext_resource type="PackedScene" uid="uid://dxq2510ywj1hy" path="res://Objects/bench_press.tscn" id="2_ilyy2"] + +[resource] +target_weight = 25.0 +mini_game_scene = ExtResource("2_ilyy2") +available_hazards = Array[HazardDef]([ExtResource("1_qov1i")]) diff --git a/max-effort/Resources/Day_Day2.tres b/max-effort/Resources/Day_Day2.tres new file mode 100644 index 0000000..75b8262 --- /dev/null +++ b/max-effort/Resources/Day_Day2.tres @@ -0,0 +1,11 @@ +[gd_resource type="DayConfig" load_steps=3 format=3 uid="uid://b0j1f8h6tioaf"] + +[ext_resource type="HazardDef" uid="uid://pgmnp6ev1ark" path="res://Resources/Hazard_GymBro.tres" id="1_x1txs"] +[ext_resource type="PackedScene" uid="uid://dx1k40qfioaas" path="res://Objects/deadlift.tscn" id="2_x1txs"] + +[resource] +day_number = 1 +day_title = "Day 2" +target_weight = 7.0 +mini_game_scene = ExtResource("2_x1txs") +available_hazards = Array[HazardDef]([ExtResource("1_x1txs")]) diff --git a/max-effort/Resources/GameState.tres b/max-effort/Resources/GameState.tres new file mode 100644 index 0000000..fb88a00 --- /dev/null +++ b/max-effort/Resources/GameState.tres @@ -0,0 +1,3 @@ +[gd_resource type="GameState" format=3 uid="uid://2gma8vvisnqo"] + +[resource] diff --git a/max-effort/Resources/Hazard_GymBro.tres b/max-effort/Resources/Hazard_GymBro.tres new file mode 100644 index 0000000..35abba4 --- /dev/null +++ b/max-effort/Resources/Hazard_GymBro.tres @@ -0,0 +1,72 @@ +[gd_resource type="HazardDef" load_steps=14 format=3 uid="uid://pgmnp6ev1ark"] + +[ext_resource type="Texture2D" uid="uid://c43wo6u2c0d43" path="res://Sprites/chad_walk0.png" id="1_v1id6"] +[ext_resource type="Texture2D" uid="uid://dt5i4j2gvqso" path="res://Sprites/chad_walk1.png" id="2_xcd3t"] +[ext_resource type="Texture2D" uid="uid://by265t6kx8us4" path="res://Sprites/chad_walk2.png" id="3_57x2g"] +[ext_resource type="Texture2D" uid="uid://dway2w8pbk5lp" path="res://Sprites/chad_walk3.png" id="4_s8hf6"] +[ext_resource type="Texture2D" uid="uid://bunfddn1pa8pj" path="res://Sprites/chad_walk4.png" id="5_tdncn"] +[ext_resource type="Texture2D" uid="uid://664m2cxtmmur" path="res://Sprites/chad_wave0.png" id="6_twq7w"] +[ext_resource type="Texture2D" uid="uid://tu8ph6cjdwhv" path="res://Sprites/chad_wave1.png" id="7_jshom"] +[ext_resource type="Texture2D" uid="uid://b28aaketyf0t1" path="res://Sprites/chad_wave2.png" id="8_hejui"] +[ext_resource type="Texture2D" uid="uid://jyr4f2p7jbk8" path="res://Sprites/chad_wave3.png" id="9_envil"] +[ext_resource type="Texture2D" uid="uid://f013utfdsqqe" path="res://Sprites/chad_wave4.png" id="10_tcjtc"] +[ext_resource type="Texture2D" uid="uid://duryxgc54alp5" path="res://Sprites/chad_wave5.png" id="11_i0i8i"] +[ext_resource type="Texture2D" uid="uid://yy2yrm4gq6w4" path="res://Sprites/chad_wave6.png" id="12_seh7d"] + +[sub_resource type="SpriteFrames" id="SpriteFrames_44y3n"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": ExtResource("1_v1id6") +}, { +"duration": 1.0, +"texture": ExtResource("2_xcd3t") +}, { +"duration": 1.0, +"texture": ExtResource("3_57x2g") +}, { +"duration": 1.0, +"texture": ExtResource("4_s8hf6") +}, { +"duration": 1.0, +"texture": ExtResource("5_tdncn") +}], +"loop": true, +"name": &"walking", +"speed": 12.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": ExtResource("6_twq7w") +}, { +"duration": 1.0, +"texture": ExtResource("7_jshom") +}, { +"duration": 1.0, +"texture": ExtResource("8_hejui") +}, { +"duration": 1.0, +"texture": ExtResource("9_envil") +}, { +"duration": 1.0, +"texture": ExtResource("10_tcjtc") +}, { +"duration": 1.0, +"texture": ExtResource("11_i0i8i") +}, { +"duration": 1.0, +"texture": ExtResource("12_seh7d") +}], +"loop": true, +"name": &"waving", +"speed": 12.0 +}] + +[resource] +hazard_type = "GymBro" +display_name = "Chad" +animations = SubResource("SpriteFrames_44y3n") +idle_anim_name = "waving" +walk_anim_name = "walking" +time_to_fail = 3.0 +min_focus_to_spawn = 0.3 diff --git a/max-effort/Resources/SoundBank.tres b/max-effort/Resources/SoundBank.tres new file mode 100644 index 0000000..85d0084 --- /dev/null +++ b/max-effort/Resources/SoundBank.tres @@ -0,0 +1,3 @@ +[gd_resource type="SoundBank" format=3 uid="uid://b8ouri8tqw8vp"] + +[resource] diff --git a/max-effort/Scenes/.idea/.gitignore b/max-effort/Scenes/.idea/.gitignore new file mode 100644 index 0000000..bc420b8 --- /dev/null +++ b/max-effort/Scenes/.idea/.gitignore @@ -0,0 +1,15 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/.idea.Scenes.iml +/modules.xml +/contentModel.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/max-effort/Scenes/.idea/copilot.data.migration.ask2agent.xml b/max-effort/Scenes/.idea/copilot.data.migration.ask2agent.xml new file mode 100644 index 0000000..1f2ea11 --- /dev/null +++ b/max-effort/Scenes/.idea/copilot.data.migration.ask2agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/max-effort/Scenes/.idea/encodings.xml b/max-effort/Scenes/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/max-effort/Scenes/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/max-effort/Scenes/.idea/indexLayout.xml b/max-effort/Scenes/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/max-effort/Scenes/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/max-effort/Scenes/.idea/inspectionProfiles/Project_Default.xml b/max-effort/Scenes/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/max-effort/Scenes/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/max-effort/Scenes/main.tscn b/max-effort/Scenes/main.tscn new file mode 100644 index 0000000..938e13c --- /dev/null +++ b/max-effort/Scenes/main.tscn @@ -0,0 +1,147 @@ +[gd_scene load_steps=11 format=3 uid="uid://xtm08af0e82g"] + +[ext_resource type="GameState" uid="uid://2gma8vvisnqo" path="res://Resources/GameState.tres" id="1_bo1nx"] +[ext_resource type="Shader" uid="uid://dndm4jfifooyk" path="res://Shaders/TunnelVision.gdshader" id="1_jjgbg"] +[ext_resource type="DayConfig" uid="uid://d30pwvrr7m72j" path="res://Resources/Day_Day1.tres" id="2_8gbba"] +[ext_resource type="SoundBank" uid="uid://b8ouri8tqw8vp" path="res://Resources/SoundBank.tres" id="2_21xkr"] +[ext_resource type="HazardDef" uid="uid://pgmnp6ev1ark" path="res://Resources/Hazard_GymBro.tres" id="3_kry3j"] +[ext_resource type="PackedScene" uid="uid://bg4uaukekjbx" path="res://Scenes/main_menu.tscn" id="4_6bp64"] +[ext_resource type="PackedScene" uid="uid://bqxc62tofqger" path="res://Objects/hazard_animated.tscn" id="4_21xkr"] + +[sub_resource type="Curve" id="Curve_bo1nx"] +_data = [Vector2(0, 0), 0.0, 1.4, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="TunnelConfig" id="TunnelConfig_8gbba"] +max_tunnel_intensity = 0.7 +vision_curve = SubResource("Curve_bo1nx") + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_bo1nx"] +shader = ExtResource("1_jjgbg") +shader_parameter/vignette_intensity = 0.0 +shader_parameter/vignette_color = Color(0, 0, 0, 1) + +[node name="Main" type="Node"] + +[node name="Systems" type="Node" parent="."] + +[node name="PlayerInputSystem" type="PlayerInputSystem" parent="Systems"] +game_state = ExtResource("1_bo1nx") + +[node name="TunnelSystem" type="TunnelSystem" parent="Systems" node_paths=PackedStringArray("vignette_overlay")] +game_state = ExtResource("1_bo1nx") +config = SubResource("TunnelConfig_8gbba") +vignette_overlay = NodePath("../../Ui/Vignette") + +[node name="SoundManager" type="SoundManager" parent="Systems"] +bank = ExtResource("2_21xkr") +game_state = ExtResource("1_bo1nx") + +[node name="GameManager" type="GameManager" parent="Systems" node_paths=PackedStringArray("hazard_system", "minigame_container", "win_screen", "lose_screen")] +days = Array[DayConfig]([ExtResource("2_8gbba")]) +game_state = ExtResource("1_bo1nx") +hazard_system = NodePath("../HazardSystem") +minigame_container = NodePath("../../GameContainer") +win_screen = NodePath("../../Ui/Win") +lose_screen = NodePath("../../Ui/Lose") +main_menu_scene = ExtResource("4_6bp64") + +[node name="CameraShakeSystem" type="CameraShakeSystem" parent="Systems" node_paths=PackedStringArray("camera")] +camera = NodePath("../../Camera2D") +game_state = ExtResource("1_bo1nx") +min_focus_for_shake = 0.7 + +[node name="HazardSystem" type="HazardSystem" parent="Systems" node_paths=PackedStringArray("spawn_locations")] +possible_hazards = Array[HazardDef]([ExtResource("3_kry3j")]) +spawn_locations = [NodePath("../../HazardSpots/Right"), NodePath("../../HazardSpots/Left")] +hazard_prefab = ExtResource("4_21xkr") +game_state = ExtResource("1_bo1nx") + +[node name="GameContainer" type="Node" parent="."] + +[node name="HazardSpots" type="Node2D" parent="."] + +[node name="Right" type="Marker2D" parent="HazardSpots"] +position = Vector2(502, 0) + +[node name="Left" type="Marker2D" parent="HazardSpots"] +position = Vector2(-500, 0) + +[node name="Ui" type="CanvasLayer" parent="."] + +[node name="Vignette" type="ColorRect" parent="Ui"] +material = SubResource("ShaderMaterial_bo1nx") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 + +[node name="LiftProgressBar" type="LiftProgressBar" parent="Ui"] +game_state = ExtResource("1_bo1nx") +anchors_preset = 12 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = -27.0 +grow_horizontal = 2 +grow_vertical = 0 + +[node name="Win" type="ColorRect" parent="Ui"] +visible = false +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 1, 0, 1) + +[node name="Label" type="Label" parent="Ui/Win"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -20.0 +offset_top = -11.5 +offset_right = 20.0 +offset_bottom = 11.5 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_font_sizes/font_size = 72 +text = "Light Weight" +horizontal_alignment = 1 +vertical_alignment = 1 +uppercase = true + +[node name="Lose" type="ColorRect" parent="Ui"] +visible = false +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(1, 0, 0, 1) + +[node name="Label" type="Label" parent="Ui/Lose"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -20.0 +offset_top = -11.5 +offset_right = 20.0 +offset_bottom = 11.5 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_font_sizes/font_size = 72 +text = "Failure" +horizontal_alignment = 1 +vertical_alignment = 1 +uppercase = true + +[node name="Camera2D" type="Camera2D" parent="."] diff --git a/max-effort/Scenes/main_menu.tscn b/max-effort/Scenes/main_menu.tscn new file mode 100644 index 0000000..44b5dfc --- /dev/null +++ b/max-effort/Scenes/main_menu.tscn @@ -0,0 +1,62 @@ +[gd_scene load_steps=2 format=3 uid="uid://bg4uaukekjbx"] + +[ext_resource type="PackedScene" uid="uid://xtm08af0e82g" path="res://Scenes/main.tscn" id="1_28flt"] + +[node name="MainMenu" type="MainMenu" node_paths=PackedStringArray("mute_button")] +game_scene = ExtResource("1_28flt") +mute_button = NodePath("VBoxContainer/MuteButton") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="ColorRect" type="ColorRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.14117648, 0.14117648, 0.14117648, 1) + +[node name="Title" type="Label" parent="."] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 67.0 +grow_horizontal = 2 +theme_override_font_sizes/font_size = 48 +text = "max effort" +horizontal_alignment = 1 +vertical_alignment = 1 +uppercase = true + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -20.0 +offset_top = -20.0 +offset_right = 20.0 +offset_bottom = 20.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="PlayButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Play" + +[node name="QuitButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Quit" + +[node name="MuteButton" type="CheckButton" parent="VBoxContainer"] +layout_mode = 2 +text = "Mute" + +[connection signal="pressed" from="VBoxContainer/PlayButton" to="." method="on_play_pressed"] +[connection signal="pressed" from="VBoxContainer/QuitButton" to="." method="on_quit_pressed"] diff --git a/max-effort/Shaders/TunnelVision.gdshader b/max-effort/Shaders/TunnelVision.gdshader new file mode 100644 index 0000000..b1e9f09 --- /dev/null +++ b/max-effort/Shaders/TunnelVision.gdshader @@ -0,0 +1,20 @@ +shader_type canvas_item; + +uniform float vignette_intensity : hint_range(0.0, 1.0) = 0.0; +uniform vec4 vignette_color : source_color = vec4(0.0, 0.0, 0.0, 1.0); + +void fragment() { + vec2 center = vec2(0.5, 0.5); + + float dist = distance(UV, center); + + float radius = 0.8 - (vignette_intensity * 0.7); + + float softness = 0.2; + + float vignette = smoothstep(radius, radius - softness, dist); + + float alpha = 1.0 - vignette; + + COLOR = vec4(vignette_color.rgb, alpha * vignette_intensity * 1.5); +} \ No newline at end of file diff --git a/max-effort/Shaders/TunnelVision.gdshader.uid b/max-effort/Shaders/TunnelVision.gdshader.uid new file mode 100644 index 0000000..ad05119 --- /dev/null +++ b/max-effort/Shaders/TunnelVision.gdshader.uid @@ -0,0 +1 @@ +uid://dndm4jfifooyk diff --git a/max-effort/Sprites/barbell.png b/max-effort/Sprites/barbell.png new file mode 100644 index 0000000..8642f3d Binary files /dev/null and b/max-effort/Sprites/barbell.png differ diff --git a/max-effort/Sprites/barbell.png.import b/max-effort/Sprites/barbell.png.import new file mode 100644 index 0000000..78f0c38 --- /dev/null +++ b/max-effort/Sprites/barbell.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cbgn8aspf7oi0" +path="res://.godot/imported/barbell.png-18c805fdd277089a294c3e4ab4576f9d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/barbell.png" +dest_files=["res://.godot/imported/barbell.png-18c805fdd277089a294c3e4ab4576f9d.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/max-effort/Sprites/bench.png b/max-effort/Sprites/bench.png new file mode 100644 index 0000000..6e3968b Binary files /dev/null and b/max-effort/Sprites/bench.png differ diff --git a/max-effort/Sprites/bench.png.import b/max-effort/Sprites/bench.png.import new file mode 100644 index 0000000..5da80a8 --- /dev/null +++ b/max-effort/Sprites/bench.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dsovna2tmb4o3" +path="res://.godot/imported/bench.png-7eaea02148a24455b27861ad276687ec.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench.png" +dest_files=["res://.godot/imported/bench.png-7eaea02148a24455b27861ad276687ec.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/max-effort/Sprites/bench_press0.png b/max-effort/Sprites/bench_press0.png new file mode 100644 index 0000000..ac6aa71 Binary files /dev/null and b/max-effort/Sprites/bench_press0.png differ diff --git a/max-effort/Sprites/bench_press0.png.import b/max-effort/Sprites/bench_press0.png.import new file mode 100644 index 0000000..e566b07 --- /dev/null +++ b/max-effort/Sprites/bench_press0.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dci4cuavfc4la" +path="res://.godot/imported/bench_press0.png-ba9ac58cf50cb63dff601e4a9d25d02e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench_press0.png" +dest_files=["res://.godot/imported/bench_press0.png-ba9ac58cf50cb63dff601e4a9d25d02e.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/max-effort/Sprites/bench_press1.png b/max-effort/Sprites/bench_press1.png new file mode 100644 index 0000000..2956eb0 Binary files /dev/null and b/max-effort/Sprites/bench_press1.png differ diff --git a/max-effort/Sprites/bench_press1.png.import b/max-effort/Sprites/bench_press1.png.import new file mode 100644 index 0000000..1788ef4 --- /dev/null +++ b/max-effort/Sprites/bench_press1.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dya801bkqxdpa" +path="res://.godot/imported/bench_press1.png-5e3c7fb368ba97d9829feb84755273cb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench_press1.png" +dest_files=["res://.godot/imported/bench_press1.png-5e3c7fb368ba97d9829feb84755273cb.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/max-effort/Sprites/bench_press2.png b/max-effort/Sprites/bench_press2.png new file mode 100644 index 0000000..46be780 Binary files /dev/null and b/max-effort/Sprites/bench_press2.png differ diff --git a/max-effort/Sprites/bench_press2.png.import b/max-effort/Sprites/bench_press2.png.import new file mode 100644 index 0000000..abbf81f --- /dev/null +++ b/max-effort/Sprites/bench_press2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbxviq4c0pyju" +path="res://.godot/imported/bench_press2.png-26912d86e95ea594a6ede3ddf7d888d5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench_press2.png" +dest_files=["res://.godot/imported/bench_press2.png-26912d86e95ea594a6ede3ddf7d888d5.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/max-effort/Sprites/bench_press3.png b/max-effort/Sprites/bench_press3.png new file mode 100644 index 0000000..78adda4 Binary files /dev/null and b/max-effort/Sprites/bench_press3.png differ diff --git a/max-effort/Sprites/bench_press3.png.import b/max-effort/Sprites/bench_press3.png.import new file mode 100644 index 0000000..7527d74 --- /dev/null +++ b/max-effort/Sprites/bench_press3.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://biu7q8mfw62be" +path="res://.godot/imported/bench_press3.png-151702054f4fa5ae7f646f944338650b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench_press3.png" +dest_files=["res://.godot/imported/bench_press3.png-151702054f4fa5ae7f646f944338650b.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/max-effort/Sprites/bench_press4.png b/max-effort/Sprites/bench_press4.png new file mode 100644 index 0000000..023d0d4 Binary files /dev/null and b/max-effort/Sprites/bench_press4.png differ diff --git a/max-effort/Sprites/bench_press4.png.import b/max-effort/Sprites/bench_press4.png.import new file mode 100644 index 0000000..00dc741 --- /dev/null +++ b/max-effort/Sprites/bench_press4.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bg06qtcl207do" +path="res://.godot/imported/bench_press4.png-6bdb5e12c718169046447626c4f714d2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench_press4.png" +dest_files=["res://.godot/imported/bench_press4.png-6bdb5e12c718169046447626c4f714d2.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/max-effort/Sprites/bench_press5.png b/max-effort/Sprites/bench_press5.png new file mode 100644 index 0000000..f1902d1 Binary files /dev/null and b/max-effort/Sprites/bench_press5.png differ diff --git a/max-effort/Sprites/bench_press5.png.import b/max-effort/Sprites/bench_press5.png.import new file mode 100644 index 0000000..423da02 --- /dev/null +++ b/max-effort/Sprites/bench_press5.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bkypgv8rfcd8k" +path="res://.godot/imported/bench_press5.png-14c7049e4522e703552beeb21c54b5d3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench_press5.png" +dest_files=["res://.godot/imported/bench_press5.png-14c7049e4522e703552beeb21c54b5d3.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/max-effort/Sprites/bench_press6.png b/max-effort/Sprites/bench_press6.png new file mode 100644 index 0000000..d08e648 Binary files /dev/null and b/max-effort/Sprites/bench_press6.png differ diff --git a/max-effort/Sprites/bench_press6.png.import b/max-effort/Sprites/bench_press6.png.import new file mode 100644 index 0000000..22a533c --- /dev/null +++ b/max-effort/Sprites/bench_press6.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://warnmdoebwht" +path="res://.godot/imported/bench_press6.png-fbb03a505d8811ac5e307f534e60a936.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench_press6.png" +dest_files=["res://.godot/imported/bench_press6.png-fbb03a505d8811ac5e307f534e60a936.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/max-effort/Sprites/bench_press7.png b/max-effort/Sprites/bench_press7.png new file mode 100644 index 0000000..386c8ce Binary files /dev/null and b/max-effort/Sprites/bench_press7.png differ diff --git a/max-effort/Sprites/bench_press7.png.import b/max-effort/Sprites/bench_press7.png.import new file mode 100644 index 0000000..3260f58 --- /dev/null +++ b/max-effort/Sprites/bench_press7.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://yrorih7pbt0q" +path="res://.godot/imported/bench_press7.png-f40d47f75275caf6823ff7e34d3d17bb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/bench_press7.png" +dest_files=["res://.godot/imported/bench_press7.png-f40d47f75275caf6823ff7e34d3d17bb.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/max-effort/Sprites/chad_walk0.png b/max-effort/Sprites/chad_walk0.png new file mode 100644 index 0000000..99af52f Binary files /dev/null and b/max-effort/Sprites/chad_walk0.png differ diff --git a/max-effort/Sprites/chad_walk0.png.import b/max-effort/Sprites/chad_walk0.png.import new file mode 100644 index 0000000..eb77a19 --- /dev/null +++ b/max-effort/Sprites/chad_walk0.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c43wo6u2c0d43" +path="res://.godot/imported/chad_walk0.png-8e4fc165652b5af437c3106b59f93650.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_walk0.png" +dest_files=["res://.godot/imported/chad_walk0.png-8e4fc165652b5af437c3106b59f93650.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/max-effort/Sprites/chad_walk1.png b/max-effort/Sprites/chad_walk1.png new file mode 100644 index 0000000..64fe665 Binary files /dev/null and b/max-effort/Sprites/chad_walk1.png differ diff --git a/max-effort/Sprites/chad_walk1.png.import b/max-effort/Sprites/chad_walk1.png.import new file mode 100644 index 0000000..3cc3cd3 --- /dev/null +++ b/max-effort/Sprites/chad_walk1.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dt5i4j2gvqso" +path="res://.godot/imported/chad_walk1.png-33816be91d7ff97b4b5f437f937fae6e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_walk1.png" +dest_files=["res://.godot/imported/chad_walk1.png-33816be91d7ff97b4b5f437f937fae6e.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/max-effort/Sprites/chad_walk2.png b/max-effort/Sprites/chad_walk2.png new file mode 100644 index 0000000..5741254 Binary files /dev/null and b/max-effort/Sprites/chad_walk2.png differ diff --git a/max-effort/Sprites/chad_walk2.png.import b/max-effort/Sprites/chad_walk2.png.import new file mode 100644 index 0000000..3e65adf --- /dev/null +++ b/max-effort/Sprites/chad_walk2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://by265t6kx8us4" +path="res://.godot/imported/chad_walk2.png-6275d1149cbf6b3a53f8cc57ae4023c9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_walk2.png" +dest_files=["res://.godot/imported/chad_walk2.png-6275d1149cbf6b3a53f8cc57ae4023c9.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/max-effort/Sprites/chad_walk3.png b/max-effort/Sprites/chad_walk3.png new file mode 100644 index 0000000..af13872 Binary files /dev/null and b/max-effort/Sprites/chad_walk3.png differ diff --git a/max-effort/Sprites/chad_walk3.png.import b/max-effort/Sprites/chad_walk3.png.import new file mode 100644 index 0000000..cb228b1 --- /dev/null +++ b/max-effort/Sprites/chad_walk3.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dway2w8pbk5lp" +path="res://.godot/imported/chad_walk3.png-83f190047fc9396d428eeeadc1ee67bb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_walk3.png" +dest_files=["res://.godot/imported/chad_walk3.png-83f190047fc9396d428eeeadc1ee67bb.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/max-effort/Sprites/chad_walk4.png b/max-effort/Sprites/chad_walk4.png new file mode 100644 index 0000000..5b75302 Binary files /dev/null and b/max-effort/Sprites/chad_walk4.png differ diff --git a/max-effort/Sprites/chad_walk4.png.import b/max-effort/Sprites/chad_walk4.png.import new file mode 100644 index 0000000..b21fed2 --- /dev/null +++ b/max-effort/Sprites/chad_walk4.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bunfddn1pa8pj" +path="res://.godot/imported/chad_walk4.png-e04181ba7df8daa1c7400ecfa9120b36.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_walk4.png" +dest_files=["res://.godot/imported/chad_walk4.png-e04181ba7df8daa1c7400ecfa9120b36.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/max-effort/Sprites/chad_wave0.png b/max-effort/Sprites/chad_wave0.png new file mode 100644 index 0000000..47033a5 Binary files /dev/null and b/max-effort/Sprites/chad_wave0.png differ diff --git a/max-effort/Sprites/chad_wave0.png.import b/max-effort/Sprites/chad_wave0.png.import new file mode 100644 index 0000000..10c63d0 --- /dev/null +++ b/max-effort/Sprites/chad_wave0.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://664m2cxtmmur" +path="res://.godot/imported/chad_wave0.png-7452b570847815d288a291f1ec8574e6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_wave0.png" +dest_files=["res://.godot/imported/chad_wave0.png-7452b570847815d288a291f1ec8574e6.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/max-effort/Sprites/chad_wave1.png b/max-effort/Sprites/chad_wave1.png new file mode 100644 index 0000000..7354989 Binary files /dev/null and b/max-effort/Sprites/chad_wave1.png differ diff --git a/max-effort/Sprites/chad_wave1.png.import b/max-effort/Sprites/chad_wave1.png.import new file mode 100644 index 0000000..4f22b89 --- /dev/null +++ b/max-effort/Sprites/chad_wave1.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tu8ph6cjdwhv" +path="res://.godot/imported/chad_wave1.png-f0592da2a6c2b61ba47c87e39b1a9a35.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_wave1.png" +dest_files=["res://.godot/imported/chad_wave1.png-f0592da2a6c2b61ba47c87e39b1a9a35.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/max-effort/Sprites/chad_wave2.png b/max-effort/Sprites/chad_wave2.png new file mode 100644 index 0000000..8fabd22 Binary files /dev/null and b/max-effort/Sprites/chad_wave2.png differ diff --git a/max-effort/Sprites/chad_wave2.png.import b/max-effort/Sprites/chad_wave2.png.import new file mode 100644 index 0000000..f5d0c10 --- /dev/null +++ b/max-effort/Sprites/chad_wave2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b28aaketyf0t1" +path="res://.godot/imported/chad_wave2.png-2c28d86e420f732e4cc32daf20b49920.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_wave2.png" +dest_files=["res://.godot/imported/chad_wave2.png-2c28d86e420f732e4cc32daf20b49920.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/max-effort/Sprites/chad_wave3.png b/max-effort/Sprites/chad_wave3.png new file mode 100644 index 0000000..eb227dc Binary files /dev/null and b/max-effort/Sprites/chad_wave3.png differ diff --git a/max-effort/Sprites/chad_wave3.png.import b/max-effort/Sprites/chad_wave3.png.import new file mode 100644 index 0000000..2d5cce1 --- /dev/null +++ b/max-effort/Sprites/chad_wave3.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://jyr4f2p7jbk8" +path="res://.godot/imported/chad_wave3.png-c5f30d3e0f297bd9fc2597ab6e730b5a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_wave3.png" +dest_files=["res://.godot/imported/chad_wave3.png-c5f30d3e0f297bd9fc2597ab6e730b5a.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/max-effort/Sprites/chad_wave4.png b/max-effort/Sprites/chad_wave4.png new file mode 100644 index 0000000..58bcd4d Binary files /dev/null and b/max-effort/Sprites/chad_wave4.png differ diff --git a/max-effort/Sprites/chad_wave4.png.import b/max-effort/Sprites/chad_wave4.png.import new file mode 100644 index 0000000..df3686c --- /dev/null +++ b/max-effort/Sprites/chad_wave4.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://f013utfdsqqe" +path="res://.godot/imported/chad_wave4.png-d9dcca2f7e8dd0d27166f8047669505f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_wave4.png" +dest_files=["res://.godot/imported/chad_wave4.png-d9dcca2f7e8dd0d27166f8047669505f.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/max-effort/Sprites/chad_wave5.png b/max-effort/Sprites/chad_wave5.png new file mode 100644 index 0000000..ff841ca Binary files /dev/null and b/max-effort/Sprites/chad_wave5.png differ diff --git a/max-effort/Sprites/chad_wave5.png.import b/max-effort/Sprites/chad_wave5.png.import new file mode 100644 index 0000000..83d2a28 --- /dev/null +++ b/max-effort/Sprites/chad_wave5.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://duryxgc54alp5" +path="res://.godot/imported/chad_wave5.png-aa21a1c7a76438f4a886d5f1b68bbcc5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_wave5.png" +dest_files=["res://.godot/imported/chad_wave5.png-aa21a1c7a76438f4a886d5f1b68bbcc5.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/max-effort/Sprites/chad_wave6.png b/max-effort/Sprites/chad_wave6.png new file mode 100644 index 0000000..a63c2b9 Binary files /dev/null and b/max-effort/Sprites/chad_wave6.png differ diff --git a/max-effort/Sprites/chad_wave6.png.import b/max-effort/Sprites/chad_wave6.png.import new file mode 100644 index 0000000..e9cea02 --- /dev/null +++ b/max-effort/Sprites/chad_wave6.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://yy2yrm4gq6w4" +path="res://.godot/imported/chad_wave6.png-3d42c992783b312c1ab7802034e07a03.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/chad_wave6.png" +dest_files=["res://.godot/imported/chad_wave6.png-3d42c992783b312c1ab7802034e07a03.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/max-effort/Sprites/stick-bench-bend.png b/max-effort/Sprites/stick-bench-bend.png new file mode 100644 index 0000000..56726c6 Binary files /dev/null and b/max-effort/Sprites/stick-bench-bend.png differ diff --git a/max-effort/Sprites/stick-bench-bend.png.import b/max-effort/Sprites/stick-bench-bend.png.import new file mode 100644 index 0000000..15b8ae2 --- /dev/null +++ b/max-effort/Sprites/stick-bench-bend.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://mc8luxtg4rio" +path="res://.godot/imported/stick-bench-bend.png-7c99c74f55cf267d5d337b54b20aa912.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/stick-bench-bend.png" +dest_files=["res://.godot/imported/stick-bench-bend.png-7c99c74f55cf267d5d337b54b20aa912.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/max-effort/Sprites/stick-bench-straight.png b/max-effort/Sprites/stick-bench-straight.png new file mode 100644 index 0000000..18e7778 Binary files /dev/null and b/max-effort/Sprites/stick-bench-straight.png differ diff --git a/max-effort/Sprites/stick-bench-straight.png.import b/max-effort/Sprites/stick-bench-straight.png.import new file mode 100644 index 0000000..dd0679b --- /dev/null +++ b/max-effort/Sprites/stick-bench-straight.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqkxhms26hdx2" +path="res://.godot/imported/stick-bench-straight.png-d6eb50859d8b64f084f45e07fee5f895.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/stick-bench-straight.png" +dest_files=["res://.godot/imported/stick-bench-straight.png-d6eb50859d8b64f084f45e07fee5f895.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/max-effort/icon.svg b/max-effort/icon.svg new file mode 100644 index 0000000..c6bbb7d --- /dev/null +++ b/max-effort/icon.svg @@ -0,0 +1 @@ + diff --git a/max-effort/icon.svg.import b/max-effort/icon.svg.import new file mode 100644 index 0000000..224967c --- /dev/null +++ b/max-effort/icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1exufucxsjrq" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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/max-effort/project.godot b/max-effort/project.godot new file mode 100644 index 0000000..d22a3e9 --- /dev/null +++ b/max-effort/project.godot @@ -0,0 +1,30 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="max-effort" +run/main_scene="uid://bg4uaukekjbx" +config/features=PackedStringArray("4.5", "GL Compatibility") +config/icon="res://icon.svg" + +[input] + +lift_action={ +"deadzone": 0.2, +"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":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null) +] +} + +[rendering] + +renderer/rendering_method="gl_compatibility" +renderer/rendering_method.mobile="gl_compatibility" diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1 @@ +/target diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 0000000..cab65e8 --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,203 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "gdextension-api" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8107360153162c579a6d44503710720b55f6686fec83aa14750a3e60a55274" + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" + +[[package]] +name = "godot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5599d03afd17a511e11d0bf9e06c88d4095a9120f10cf00a74f50b300f53413e" +dependencies = [ + "godot-core", + "godot-macros", +] + +[[package]] +name = "godot-bindings" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38b6e65306c05e3c3f0131ee8dbf7394691e53268d72019007ec20687f2280f" +dependencies = [ + "gdextension-api", +] + +[[package]] +name = "godot-cell" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738efef92fdcf1d92f0ed5a29c6f3cdce58e64029d08928c20e08771e1239c16" + +[[package]] +name = "godot-codegen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b9a59f603f354c54d83fb74071209203d0ebe396b2419acc731c90ebf94680" +dependencies = [ + "godot-bindings", + "heck", + "nanoserde", + "proc-macro2", + "quote", + "regex", +] + +[[package]] +name = "godot-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e80dfb58d2048ae0dca60bec32129dc1f96510f904b992ad170d84e950c33" +dependencies = [ + "glam", + "godot-bindings", + "godot-cell", + "godot-codegen", + "godot-ffi", +] + +[[package]] +name = "godot-ffi" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6237b26c52c5baa6566705a73cd8804ea4ef83a666540939dd5a4e068c242666" +dependencies = [ + "godot-bindings", + "godot-codegen", + "godot-macros", + "libc", +] + +[[package]] +name = "godot-macros" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d696b67ba99ff7d75e07546b04c3a711651d2c9e5851c9225dea3b64f8bb5af6" +dependencies = [ + "godot-bindings", + "proc-macro2", + "quote", + "venial", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "max-effort-lib" +version = "1.0.0" +dependencies = [ + "godot", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "nanoserde" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a36fb3a748a4c9736ed7aeb5f2dfc99665247f1ce306abbddb2bf0ba2ac530a4" +dependencies = [ + "nanoserde-derive", +] + +[[package]] +name = "nanoserde-derive" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a846cbc04412cf509efcd8f3694b114fc700a035fb5a37f21517f9fb019f1ebc" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "venial" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a42528baceab6c7784446df2a10f4185078c39bf73dc614f154353f1a6b1229" +dependencies = [ + "proc-macro2", + "quote", +] diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..5b4c2ed --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "max-effort-lib" +version = "1.0.0" +edition = "2024" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +godot = "0.4.5" diff --git a/rust/src/core/game_state.rs b/rust/src/core/game_state.rs new file mode 100644 index 0000000..d1ae367 --- /dev/null +++ b/rust/src/core/game_state.rs @@ -0,0 +1,161 @@ +use godot::prelude::*; +use std::sync::RwLock; + +use crate::data::hazard_def::HazardType; + +#[derive(Clone, Debug)] +pub enum GameEvent { + HazardSpawned, + HazardResolved, + TraumaApplied(f32), + LiftCompleted(bool), +} + +#[derive(Default)] +pub struct InnerState { + pub current_focus: f32, // 0.0 to 1.0 + pub lift_effort: f32, // 0.0 to 1.0 + pub is_lifting: bool, + pub active_hazards: Vec, + pub lift_progress: f32, // 0.0 to 1.0 + pub visual_height: f32, + pub is_lift_complete: bool, + pub is_lift_failed: bool, + pub camera_trauma: f32, + pub event_queue: Vec, +} + +#[derive(GodotClass)] +#[class(base=Resource)] +pub struct GameState { + pub inner: RwLock, + + base: Base, +} + +#[godot_api] +impl IResource for GameState { + fn init(base: Base) -> Self { + Self { + inner: RwLock::new(InnerState::default()), + base, + } + } +} + +#[godot_api] +impl GameState { + // --- WRITERS (Updated to push events) --- + + #[func] + pub fn apply_effort(&self, delta: f32) { + let mut guard = self.inner.write().unwrap(); + guard.is_lifting = true; + guard.lift_effort += delta; + } + + #[func] + pub fn release_focus(&self) { + let mut guard = self.inner.write().unwrap(); + guard.is_lifting = false; + } + + #[func] + pub fn set_focus_intensity(&self, intensity: f32) { + let mut guard = self.inner.write().unwrap(); + guard.current_focus = intensity; + } + + #[func] + pub fn set_lift_state(&self, progress: f32, visual_height: f32) { + let mut guard = self.inner.write().unwrap(); + guard.lift_progress = progress; + guard.visual_height = visual_height; + } + + #[func] + pub fn set_complete(&self, complete: bool) { + let mut guard = self.inner.write().unwrap(); + if complete { + guard.is_lift_complete = true; + } else { + guard.is_lift_failed = true; + } + + guard.event_queue.push(GameEvent::LiftCompleted(complete)); + } + + #[func] + pub fn add_trauma(&self, amount: f32) { + let mut guard = self.inner.write().unwrap(); + guard.camera_trauma = (guard.camera_trauma + amount).clamp(0.0, 1.0); + guard.event_queue.push(GameEvent::TraumaApplied(amount)); + } + + #[func] + pub fn add_active_hazard(&self, type_: HazardType) { + let mut guard = self.inner.write().unwrap(); + guard.active_hazards.push(type_); + guard.event_queue.push(GameEvent::HazardSpawned); + } + + #[func] + pub fn remove_active_hazard(&self, type_: HazardType) { + let mut guard = self.inner.write().unwrap(); + if let Some(index) = guard.active_hazards.iter().position(|t| *t == type_) { + guard.active_hazards.remove(index); + guard.event_queue.push(GameEvent::HazardResolved); + } + } + + // --- READERS --- + + #[func] + pub fn consume_effort(&self) -> f32 { + let mut guard = self.inner.write().unwrap(); + let effort = guard.lift_effort; + guard.lift_effort = 0.0; + effort + } + + #[func] + pub fn get_active_hazard_count(&self) -> i32 { + self.inner.read().unwrap().active_hazards.len() as i32 + } + + #[func] + pub fn get_focus(&self) -> f32 { + self.inner.read().unwrap().current_focus + } + + #[func] + pub fn consume_trauma(&self, decay: f32) -> f32 { + let mut guard = self.inner.write().unwrap(); + let t = guard.camera_trauma; + guard.camera_trauma = (t - decay).max(0.0); + t + } + + pub fn pop_events(&self) -> Vec { + let mut guard = self.inner.write().unwrap(); + let events = guard.event_queue.clone(); + guard.event_queue.clear(); + events + } + + pub fn get_lift_progress(&self) -> f32 { + self.inner.read().unwrap().lift_progress + } + + pub fn get_is_lifting(&self) -> bool { + self.inner.read().unwrap().is_lifting + } + + pub fn get_is_lift_complete(&self) -> bool { + self.inner.read().unwrap().is_lift_complete + } + + pub fn get_is_lift_failed(&self) -> bool { + self.inner.read().unwrap().is_lift_failed + } +} diff --git a/rust/src/core/mod.rs b/rust/src/core/mod.rs new file mode 100644 index 0000000..3e51989 --- /dev/null +++ b/rust/src/core/mod.rs @@ -0,0 +1 @@ +pub mod game_state; diff --git a/rust/src/data/day_config.rs b/rust/src/data/day_config.rs new file mode 100644 index 0000000..28c6ceb --- /dev/null +++ b/rust/src/data/day_config.rs @@ -0,0 +1,37 @@ +use godot::prelude::*; + +use crate::data::hazard_def::HazardDef; + +#[derive(GodotClass)] +#[class(base=Resource)] +pub struct DayConfig { + #[export] + pub day_number: i32, + #[export] + pub day_title: GString, + #[export] + pub target_weight: f32, + #[export] + pub gravity: f32, + #[export] + pub mini_game_scene: Option>, + #[export] + pub available_hazards: Array>, + + base: Base, +} + +#[godot_api] +impl IResource for DayConfig { + fn init(base: Base) -> Self { + Self { + day_number: 0, + day_title: "Day 1".into(), + target_weight: 100.0, + gravity: 2.0, + mini_game_scene: None, + available_hazards: Array::new(), + base, + } + } +} diff --git a/rust/src/data/hazard_def.rs b/rust/src/data/hazard_def.rs new file mode 100644 index 0000000..faf5229 --- /dev/null +++ b/rust/src/data/hazard_def.rs @@ -0,0 +1,55 @@ +use godot::{classes::SpriteFrames, prelude::*}; + +#[derive(GodotConvert, Export, Var, Default, Clone, PartialEq, Eq, Debug)] +#[godot(via=GString)] +pub enum HazardType { + #[default] + None, + GymBro, + LoosePlate, + PhoneDistraction, + Manager, +} + +#[derive(GodotClass)] +#[class(base=Resource)] +pub struct HazardDef { + #[export] + pub hazard_type: HazardType, + #[export] + pub display_name: GString, + #[export] + pub animations: Option>, + #[export] + pub idle_anim_name: GString, + #[export] + pub walk_anim_name: GString, + #[export] + pub time_to_fail: f32, + #[export] + pub spawn_weight: f32, + #[export] + pub min_focus_to_spawn: f32, + #[export] + pub clicks_to_resolve: i32, + + base: Base, +} + +#[godot_api] +impl IResource for HazardDef { + fn init(base: Base) -> Self { + Self { + hazard_type: HazardType::None, + display_name: "Unnamed Hazard".into(), + animations: None, + idle_anim_name: "idle".into(), + walk_anim_name: "walk".into(), + time_to_fail: 5.0, + spawn_weight: 1.0, + min_focus_to_spawn: 0.0, + clicks_to_resolve: 1, + base, + } + } +} diff --git a/rust/src/data/mod.rs b/rust/src/data/mod.rs new file mode 100644 index 0000000..fbedc00 --- /dev/null +++ b/rust/src/data/mod.rs @@ -0,0 +1,4 @@ +pub mod day_config; +pub mod hazard_def; +pub mod sound_bank; +pub mod tunnel_config; diff --git a/rust/src/data/sound_bank.rs b/rust/src/data/sound_bank.rs new file mode 100644 index 0000000..aab5de9 --- /dev/null +++ b/rust/src/data/sound_bank.rs @@ -0,0 +1,48 @@ +use godot::{classes::AudioStream, prelude::*}; + +#[derive(GodotClass)] +#[class(base=Resource)] +pub struct SoundBank { + #[export] + pub strain_loop: Option>, + #[export] + pub effort_exhale: Option>, + #[export] + pub win_stinger: Option>, + #[export] + pub fail_stinger: Option>, + #[export] + pub heartbeat_loop: Option>, + #[export] + pub hazard_spawn: Option>, + #[export] + pub hazard_resolve: Option>, + #[export] + pub camera_trauma: Option>, + + #[export] + pub menu_music: Option>, + #[export] + pub game_music: Option>, + + base: Base, +} + +#[godot_api] +impl IResource for SoundBank { + fn init(base: Base) -> Self { + Self { + strain_loop: None, + effort_exhale: None, + win_stinger: None, + fail_stinger: None, + heartbeat_loop: None, + hazard_spawn: None, + hazard_resolve: None, + camera_trauma: None, + menu_music: None, + game_music: None, + base, + } + } +} diff --git a/rust/src/data/tunnel_config.rs b/rust/src/data/tunnel_config.rs new file mode 100644 index 0000000..f433d9b --- /dev/null +++ b/rust/src/data/tunnel_config.rs @@ -0,0 +1,29 @@ +use godot::{classes::Curve, prelude::*}; + +#[derive(GodotClass)] +#[class(base=Resource)] +pub struct TunnelConfig { + #[export] + pub vision_narrow_rate: f32, + #[export] + pub vision_recover_rate: f32, + #[export] + pub max_tunnel_intensity: f32, + #[export] + pub vision_curve: Option>, + + base: Base, +} + +#[godot_api] +impl IResource for TunnelConfig { + fn init(base: Base) -> Self { + Self { + vision_narrow_rate: 0.5, + vision_recover_rate: 2.0, + max_tunnel_intensity: 0.95, + vision_curve: None, + base, + } + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 0000000..70a7e7f --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,12 @@ +use godot::prelude::*; + +mod core; +mod data; +mod systems; +mod ui; +mod visuals; + +struct MaxEffort; + +#[gdextension] +unsafe impl ExtensionLibrary for MaxEffort {} diff --git a/rust/src/systems/bench_press_system.rs b/rust/src/systems/bench_press_system.rs new file mode 100644 index 0000000..c673a2d --- /dev/null +++ b/rust/src/systems/bench_press_system.rs @@ -0,0 +1,70 @@ +use crate::core::game_state::GameState; +use godot::prelude::*; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct BenchPressSystem { + #[export] + power_per_click: f32, + #[export] + gravity: f32, + #[export] + target_value: f32, + + #[export] + game_state: Option>, + + current_progress: f32, + is_lift_complete: bool, + + base: Base, +} + +#[godot_api] +impl INode for BenchPressSystem { + fn init(base: Base) -> Self { + Self { + power_per_click: 5.0, + gravity: 2.0, + target_value: 100.0, + game_state: None, + current_progress: 0.0, + is_lift_complete: false, + base, + } + } + + fn process(&mut self, delta: f64) { + if self.is_lift_complete { + return; + } + + let Some(state) = &self.game_state else { + return; + }; + let dt = delta as f32; + + let state_bind = state.bind(); + let effort = state_bind.consume_effort(); + let hazard_count = state_bind.get_active_hazard_count(); + drop(state_bind); + + if self.current_progress > 0.0 { + self.current_progress -= self.gravity * dt; + self.current_progress = self.current_progress.max(0.0); + } + + if hazard_count == 0 { + self.current_progress += self.power_per_click * effort; + } + + if self.current_progress >= self.target_value { + self.is_lift_complete = true; + state.bind().set_complete(true); + } + + let ratio = self.current_progress / self.target_value; + + state.bind().set_lift_state(ratio, ratio); + } +} diff --git a/rust/src/systems/camera_shake_system.rs b/rust/src/systems/camera_shake_system.rs new file mode 100644 index 0000000..806c9c7 --- /dev/null +++ b/rust/src/systems/camera_shake_system.rs @@ -0,0 +1,86 @@ +use crate::core::game_state::GameState; +use godot::{ + classes::{Camera2D, RandomNumberGenerator}, + prelude::*, +}; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct CameraShakeSystem { + #[export] + camera: Option>, + + #[export] + game_state: Option>, + + #[export] + decay_rate: f32, + #[export] + max_offset: f32, + #[export] + max_roll: f32, + #[export] + min_focus_for_shake: f32, + + trauma: f32, + rng: Gd, + + base: Base, +} + +#[godot_api] +impl INode for CameraShakeSystem { + fn init(base: Base) -> Self { + Self { + camera: None, + game_state: None, + decay_rate: 0.8, + max_offset: 20.0, + max_roll: 0.1, + trauma: 0.0, + min_focus_for_shake: 0.1, + rng: RandomNumberGenerator::new_gd(), + base, + } + } + + fn process(&mut self, delta: f64) { + let Some(camera) = &mut self.camera else { + godot_error!("CameraShakeSystem: No camera assigned"); + return; + }; + let Some(state) = &self.game_state else { + godot_error!("CameraShakeSystem: No game state assigned"); + return; + }; + + let dt = delta as f32; + + let focus = state.bind().get_focus(); + + if focus > self.min_focus_for_shake { + state.bind().add_trauma(1.5 * dt); + } + + let new_trauma = state.bind().consume_trauma(self.decay_rate * dt); + self.trauma = new_trauma; + + if self.trauma > 0.0 { + let shake = self.trauma * self.trauma; + + let offset_x = self.max_offset * shake * self.rng.randf_range(-1.0, 1.0); + let offset_y = self.max_offset * shake * self.rng.randf_range(-1.0, 1.0); + let rotation = self.max_roll * shake * self.rng.randf_range(-1.0, 1.0); + + camera.set_offset(Vector2::new(offset_x, offset_y)); + camera.set_rotation(rotation); + } else { + if camera.get_offset() != Vector2::ZERO { + let curr_off = camera.get_offset(); + let curr_rot = camera.get_rotation(); + camera.set_offset(curr_off.lerp(Vector2::ZERO, dt * 5.0)); + camera.set_rotation(curr_rot.lerp(0.0, dt * 5.0)); + } + } + } +} diff --git a/rust/src/systems/deadlift_system.rs b/rust/src/systems/deadlift_system.rs new file mode 100644 index 0000000..d401843 --- /dev/null +++ b/rust/src/systems/deadlift_system.rs @@ -0,0 +1,105 @@ +use crate::core::game_state::GameState; +use godot::prelude::*; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct DeadliftSystem { + #[export] + power_per_click: f32, + #[export] + gravity: f32, + #[export] + target_value: f32, + + #[export] + bar_height: f32, + #[export] + hold_zone_threshold: f32, + #[export] + bar_visual: Option>, + #[export] + start_pos: Vector2, + #[export] + end_pos: Vector2, + + #[export] + game_state: Option>, + + current_bar_height: f32, + hold_timer: f32, + is_lift_complete: bool, + + base: Base, +} + +#[godot_api] +impl INode for DeadliftSystem { + fn init(base: Base) -> Self { + Self { + power_per_click: 5.0, + gravity: 2.0, + target_value: 5.0, + + bar_height: 100.0, + hold_zone_threshold: 0.8, + bar_visual: None, + start_pos: Vector2::ZERO, + end_pos: Vector2::ZERO, + + game_state: None, + + current_bar_height: 0.0, + hold_timer: 0.0, + is_lift_complete: false, + base, + } + } + + fn process(&mut self, delta: f64) { + if self.is_lift_complete { + return; + } + + let Some(state) = &self.game_state else { + return; + }; + let dt = delta as f32; + + let state_bind = state.bind(); + let effort = state_bind.consume_effort(); + let hazard_count = state_bind.get_active_hazard_count(); + drop(state_bind); + + if self.current_bar_height > 0.0 { + self.current_bar_height -= self.gravity * dt; + self.current_bar_height = self.current_bar_height.max(0.0); + } + + if hazard_count == 0 { + self.current_bar_height += self.power_per_click * effort; + self.current_bar_height = self.current_bar_height.min(self.bar_height); + } + + let visual_ratio = self.current_bar_height / self.bar_height; + + if visual_ratio >= self.hold_zone_threshold && hazard_count == 0 { + self.hold_timer += dt; + + state.bind().add_trauma(0.15 * dt); + } + + if let Some(visual) = &mut self.bar_visual { + let new_pos = self.start_pos.lerp(self.end_pos, visual_ratio); + visual.set_position(new_pos); + } + + let progress = self.hold_timer / self.target_value; + state.bind().set_lift_state(progress, visual_ratio); + + if self.hold_timer >= self.target_value { + self.is_lift_complete = true; + state.bind().add_trauma(1.0); + state.bind().set_complete(true); + } + } +} diff --git a/rust/src/systems/game_manager.rs b/rust/src/systems/game_manager.rs new file mode 100644 index 0000000..ae364ac --- /dev/null +++ b/rust/src/systems/game_manager.rs @@ -0,0 +1,207 @@ +use crate::{ + core::game_state::GameState, data::day_config::DayConfig, systems::hazard_system::HazardSystem, +}; +use godot::{ + classes::{Control, Label}, + prelude::*, +}; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct GameManager { + #[export] + days: Array>, + + #[export] + game_state: Option>, + + #[export] + hazard_system: Option>, + #[export] + minigame_container: Option>, + + #[export] + win_screen: Option>, + #[export] + lose_screen: Option>, + #[export] + game_complete_screen: Option>, + + #[export] + day_label: Option>, + #[export] + main_menu_scene: Option>, + + current_day_index: i32, + current_mini_game: Option>, + + level_ended: bool, + + base: Base, +} + +#[godot_api] +impl INode for GameManager { + fn init(base: Base) -> Self { + Self { + days: Array::new(), + game_state: None, + hazard_system: None, + minigame_container: None, + win_screen: None, + lose_screen: None, + game_complete_screen: None, + day_label: None, + main_menu_scene: None, + current_day_index: 0, + current_mini_game: None, + level_ended: false, + base, + } + } + + fn ready(&mut self) { + let idx = self.current_day_index; + self.base_mut() + .call_deferred("start_day", &[idx.to_variant()]); + } + + fn process(&mut self, _delta: f64) { + if self.level_ended { + return; + } + + let (won, lost) = if let Some(state) = &self.game_state { + let bind = state.bind(); + (bind.get_is_lift_complete(), bind.get_is_lift_failed()) + } else { + (false, false) + }; + + if won { + self.handle_win(); + self.level_ended = true; + } else if lost { + self.handle_loss(); + self.level_ended = true; + } + } +} + +#[godot_api] +impl GameManager { + #[func] + fn start_day(&mut self, index: i32) { + self.level_ended = false; + + if let Some(state) = &self.game_state { + let bind = state.bind(); + + if let Ok(mut inner) = bind.inner.write() { + inner.is_lift_complete = false; + inner.is_lift_failed = false; + + inner.lift_progress = 0.0; + inner.visual_height = 0.0; + inner.lift_effort = 0.0; + inner.active_hazards.clear(); + } + } + + if index >= self.days.len() as i32 { + self.cleanup_level(); + if let Some(s) = &mut self.game_complete_screen { + s.set_visible(true); + } + return; + } + + self.cleanup_level(); + + let config = self.days.get(index as usize).expect("Invalid Day Index"); + let config_bind = config.bind(); + + if let Some(prefab) = &config_bind.mini_game_scene { + if let Some(instance) = prefab.instantiate() { + if let Some(container) = &mut self.minigame_container { + container.add_child(&instance.clone()); + } + + if let Some(mut system) = instance.get_node_or_null("System") { + system.set("target_value", &config_bind.target_weight.to_variant()); + system.set("gravity", &config_bind.gravity.to_variant()); + + if let Some(state) = &self.game_state { + system.set("game_state", &state.to_variant()); + } + } + self.current_mini_game = Some(instance); + } + } + + if let Some(hs) = &mut self.hazard_system { + hs.bind_mut() + .set_available_hazards(config_bind.available_hazards.clone()); + } + + if let Some(l) = &mut self.day_label { + l.set_text(&config_bind.day_title); + } + if let Some(s) = &mut self.win_screen { + s.set_visible(false); + } + if let Some(s) = &mut self.lose_screen { + s.set_visible(false); + } + } + + fn cleanup_level(&mut self) { + if let Some(game) = &mut self.current_mini_game { + game.queue_free(); + self.current_mini_game = None; + } + if let Some(hs) = &mut self.hazard_system { + hs.bind_mut().clear_hazards(); + } + } + + fn handle_win(&mut self) { + if let Some(s) = &mut self.win_screen { + s.set_visible(true); + } + } + + fn handle_loss(&mut self) { + if let Some(s) = &mut self.lose_screen { + s.set_visible(true); + } + } + + #[func] + pub fn on_next_day_pressed(&mut self) { + self.current_day_index += 1; + let idx = self.current_day_index; + self.base_mut() + .call_deferred("start_day", &[idx.to_variant()]); + } + + #[func] + pub fn on_retry_pressed(&mut self) { + let idx = self.current_day_index; + self.base_mut() + .call_deferred("start_day", &[idx.to_variant()]); + } + + #[func] + pub fn on_menu_pressed(&mut self) { + if let Some(menu) = &self.main_menu_scene { + let menu_ref = menu.clone(); + self.base() + .get_tree() + .unwrap() + .change_scene_to_packed(&menu_ref); + } else { + self.base().get_tree().unwrap().quit(); + } + } +} diff --git a/rust/src/systems/hazard_controller.rs b/rust/src/systems/hazard_controller.rs new file mode 100644 index 0000000..8109de9 --- /dev/null +++ b/rust/src/systems/hazard_controller.rs @@ -0,0 +1,209 @@ +use godot::{ + classes::{ + AnimatedSprite2D, Area2D, CollisionShape2D, InputEvent, InputEventMouseButton, Label, + RectangleShape2D, + }, + global::MouseButton, + prelude::*, +}; + +use crate::{core::game_state::GameState, data::hazard_def::HazardDef}; + +#[derive(GodotClass)] +#[class(base=Node2D)] +pub struct HazardController { + #[export] + anim_sprite: Option>, + #[export] + click_area: Option>, + #[export] + click_shape: Option>, + #[export] + name_label: Option>, + + #[export] + game_state: Option>, + + data: Option>, + time_active: f32, + is_resolved: bool, + current_health: i32, + + base: Base, +} + +#[godot_api] +impl INode2D for HazardController { + fn init(base: Base) -> Self { + Self { + anim_sprite: None, + click_area: None, + click_shape: None, + name_label: None, + game_state: None, + data: None, + time_active: 0.0, + is_resolved: false, + current_health: 1, + base, + } + } + + fn ready(&mut self) { + if let Some(mut area) = self.click_area.clone() { + let callable = self.base_mut().callable("on_input_event"); + area.connect("input_event", &callable); + } + } + + fn process(&mut self, delta: f64) { + if self.is_resolved { + return; + } + + let Some(data) = &self.data.clone() else { + return; + }; + let data_bind = data.bind(); + + self.time_active += delta as f32; + + if self.time_active >= data_bind.time_to_fail { + if let Some(state) = &self.game_state { + state.bind().set_complete(false); + } + self.base_mut().queue_free(); + } + } +} + +#[godot_api] +impl HazardController { + #[func] + pub fn initialize(&mut self, data: Gd) { + let data_bind = data.bind(); + self.current_health = data_bind.clicks_to_resolve; + + if let Some(sprite) = &mut self.anim_sprite { + if let Some(frames) = &data_bind.animations { + sprite.set_sprite_frames(frames); + + let anim_name = StringName::from(&data_bind.idle_anim_name); + + if let Some(texture) = frames.get_frame_texture(&anim_name, 0) { + if let Some(shape) = &mut self.click_shape { + let mut rect = RectangleShape2D::new_gd(); + rect.set_size(texture.get_size()); + shape.set_shape(&rect.upcast::()); + } + } + + sprite.play_ex().name(&anim_name).done(); + } + } + + if let Some(label) = &mut self.name_label { + label.set_text(&data_bind.display_name); + } + + self.base_mut().set_scale(Vector2::ZERO); + + let node = self.base().clone(); + + if let Some(mut tween) = self.base_mut().create_tween() { + tween + .set_trans(godot::classes::tween::TransitionType::BACK) + .unwrap() + .set_ease(godot::classes::tween::EaseType::OUT); + + tween.tween_property( + &node.upcast::(), + "scale", + &Vector2::ONE.to_variant(), + 0.4, + ); + } + + drop(data_bind); + self.data = Some(data); + } + + #[func] + fn on_input_event(&mut self, _viewport: Gd, event: Gd, _shape_idx: i64) { + if self.is_resolved { + return; + } + + if let Ok(mouse_event) = event.try_cast::() { + if mouse_event.is_pressed() && mouse_event.get_button_index() == MouseButton::LEFT { + self.take_damage(); + } + } + } + + fn take_damage(&mut self) { + self.current_health -= 1; + + if let Some(sprite) = &mut self.anim_sprite { + sprite.set_modulate(Color::RED); + } + + let node = self.base().clone(); + let sprite_opt = self.anim_sprite.clone(); + + if let Some(mut tween) = self.base_mut().create_tween() { + tween.tween_property( + &node.clone().upcast::(), + "scale", + &Vector2::new(1.2, 0.8).to_variant(), + 0.05, + ); + tween.tween_property( + &node.clone().upcast::(), + "scale", + &Vector2::ONE.to_variant(), + 0.05, + ); + + // Flash Red + if let Some(sprite) = sprite_opt { + if let Some(mut parallel) = tween.parallel() { + parallel.tween_property( + &sprite.upcast::(), + "modulate", + &Color::WHITE.to_variant(), + 0.1, + ); + } + } + } + + if self.current_health <= 0 { + self.resolve(); + } + } + + fn resolve(&mut self) { + self.is_resolved = true; + + if let Some(data) = &self.data { + let hazard_type = data.bind().hazard_type.clone(); + + if let Some(state) = &self.game_state { + state.bind().remove_active_hazard(hazard_type); + } + } + + let node = self.base().clone(); + + if let Some(mut tween) = self.base_mut().create_tween() { + tween.tween_property( + &node.clone().upcast::(), + "scale", + &Vector2::ZERO.to_variant(), + 0.2, + ); + tween.tween_callback(&node.callable("queue_free")); + } + } +} diff --git a/rust/src/systems/hazard_system.rs b/rust/src/systems/hazard_system.rs new file mode 100644 index 0000000..c986562 --- /dev/null +++ b/rust/src/systems/hazard_system.rs @@ -0,0 +1,144 @@ +use godot::{classes::RandomNumberGenerator, prelude::*}; + +use crate::{ + core::game_state::GameState, data::hazard_def::HazardDef, + systems::hazard_controller::HazardController, +}; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct HazardSystem { + #[export] + possible_hazards: Array>, + #[export] + spawn_locations: Array>, + #[export] + hazard_prefab: Option>, + #[export] + check_interval: f32, + + #[export] + game_state: Option>, + + timer: f32, + rng: Gd, + + base: Base, +} + +#[godot_api] +impl INode for HazardSystem { + fn init(base: Base) -> Self { + Self { + possible_hazards: Array::new(), + spawn_locations: Array::new(), + hazard_prefab: None, + check_interval: 1.0, + game_state: None, + timer: 0.0, + rng: RandomNumberGenerator::new_gd(), + base, + } + } + + fn process(&mut self, delta: f64) { + self.timer += delta as f32; + if self.timer >= self.check_interval { + self.timer = 0.0; + self.try_spawn_hazard(); + } + } +} + +#[godot_api] +impl HazardSystem { + #[func] + pub fn clear_hazards(&mut self) { + for location in self.spawn_locations.iter_shared() { + for mut child in location.get_children().iter_shared() { + child.queue_free(); + } + } + self.timer = 0.0; + } + + #[func] + pub fn set_available_hazards(&mut self, hazards: Array>) { + self.possible_hazards = hazards; + } + + fn try_spawn_hazard(&mut self) { + let Some(state) = &self.game_state else { + return; + }; + + let current_focus = state.bind().get_focus(); + + if current_focus < 0.2 { + return; + } + + let spawn_chance = current_focus * 0.5; + if self.rng.randf() < spawn_chance { + self.spawn_random_hazard(current_focus); + } + } + + fn spawn_random_hazard(&mut self, current_focus: f32) { + if self.possible_hazards.is_empty() + || self.spawn_locations.is_empty() + || self.hazard_prefab.is_none() + { + return; + } + + let empty_locations: Vec> = self + .spawn_locations + .iter_shared() + .filter(|loc| loc.get_child_count() == 0) + .collect(); + + if empty_locations.is_empty() { + return; + } + + let loc_idx = self.rng.randi() as usize % empty_locations.len(); + let mut target_loc = empty_locations[loc_idx].clone(); + + let valid_hazards: Vec> = self + .possible_hazards + .iter_shared() + .filter(|h| h.bind().min_focus_to_spawn <= current_focus) + .collect(); + + if valid_hazards.is_empty() { + return; + } + + let haz_idx = self.rng.randi() as usize % valid_hazards.len(); + let selected_hazard = valid_hazards[haz_idx].clone(); + let hazard_type = selected_hazard.bind().hazard_type.clone(); + + if let Some(prefab) = &self.hazard_prefab { + if let Some(instance) = prefab.instantiate() { + if let Ok(mut hazard_node) = instance.try_cast::() { + hazard_node + .clone() + .upcast::() + .set_position(Vector2::ZERO); + + target_loc.add_child(&hazard_node.clone().upcast::()); + + hazard_node.bind_mut().initialize(selected_hazard); + + if let Some(state) = &self.game_state { + hazard_node.bind_mut().set_game_state(Some(state.clone())); + state.bind().add_active_hazard(hazard_type); + } + } else { + godot_print!("Error: Hazard Prefab root is not a HazardController!"); + } + } + } + } +} diff --git a/rust/src/systems/mod.rs b/rust/src/systems/mod.rs new file mode 100644 index 0000000..2df866a --- /dev/null +++ b/rust/src/systems/mod.rs @@ -0,0 +1,9 @@ +pub mod bench_press_system; +pub mod camera_shake_system; +pub mod deadlift_system; +pub mod game_manager; +pub mod hazard_controller; +pub mod hazard_system; +pub mod player_input_system; +pub mod sound_manager; +pub mod tunnel_system; diff --git a/rust/src/systems/player_input_system.rs b/rust/src/systems/player_input_system.rs new file mode 100644 index 0000000..fd7ac0d --- /dev/null +++ b/rust/src/systems/player_input_system.rs @@ -0,0 +1,40 @@ +use godot::{classes::Input, prelude::*}; + +use crate::core::game_state::GameState; + +const LIFT_ACTION: &str = "lift_action"; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct PlayerInputSystem { + #[export] + game_state: Option>, + base: Base, +} + +#[godot_api] +impl INode for PlayerInputSystem { + fn init(base: Base) -> Self { + Self { + game_state: None, + base, + } + } + + fn process(&mut self, delta: f64) { + let Some(state) = &self.game_state else { + return; + }; + let state_bind = state.bind(); + + let input = Input::singleton(); + + if input.is_action_pressed(LIFT_ACTION) { + state_bind.apply_effort(delta as f32); + } + + if input.is_action_just_released(LIFT_ACTION) { + state_bind.release_focus(); + } + } +} diff --git a/rust/src/systems/sound_manager.rs b/rust/src/systems/sound_manager.rs new file mode 100644 index 0000000..b9beaa5 --- /dev/null +++ b/rust/src/systems/sound_manager.rs @@ -0,0 +1,213 @@ +use crate::{ + core::game_state::{GameEvent, GameState}, + data::sound_bank::SoundBank, +}; +use godot::{ + classes::{AudioStream, AudioStreamPlayer}, + prelude::*, +}; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct SoundManager { + #[export] + bank: Option>, + #[export] + game_state: Option>, + + #[export] + pool_size: i32, + + sfx_pool: Vec>, + strain_player: Option>, + heartbeat_player: Option>, + music_player: Option>, + + was_lifting: bool, + + base: Base, +} + +#[godot_api] +impl INode for SoundManager { + fn init(base: Base) -> Self { + Self { + bank: None, + game_state: None, + pool_size: 8, + sfx_pool: Vec::new(), + strain_player: None, + heartbeat_player: None, + music_player: None, + was_lifting: false, + base, + } + } + + fn ready(&mut self) { + self.initialize_pool(); + + // FIX: Clone bank to release borrow on self + if let Some(bank) = self.bank.clone() { + if let Some(music) = &bank.bind().game_music { + self.play_music(music.clone()); + } + } + } + + fn process(&mut self, _delta: f64) { + let Some(state) = self.game_state.clone() else { + return; + }; + + let events = state.bind().pop_events(); + + for event in events { + match event { + GameEvent::HazardSpawned => self.play_bank_sfx(|b| b.hazard_spawn.clone()), + GameEvent::HazardResolved => self.play_bank_sfx(|b| b.hazard_resolve.clone()), + GameEvent::LiftCompleted(success) => { + self.stop_strain(); + if success { + self.play_bank_sfx(|b| b.win_stinger.clone()); + } else { + self.play_bank_sfx(|b| b.fail_stinger.clone()); + } + } + GameEvent::TraumaApplied(amount) => { + if amount > 0.5 { + self.play_bank_sfx(|b| b.camera_trauma.clone()); + } + } + } + } + + let is_lifting = state.bind().get_is_lifting(); + let progress = state.bind().get_lift_progress(); + let focus = state.bind().get_focus(); + + if is_lifting != self.was_lifting { + if is_lifting { + self.play_strain_loop(); + } else { + self.stop_strain(); + self.play_bank_sfx(|b| b.effort_exhale.clone()); + } + self.was_lifting = is_lifting; + } + + if is_lifting { + self.update_strain_pitch(progress); + } + + self.update_heartbeat(focus); + } +} + +impl SoundManager { + fn initialize_pool(&mut self) { + for _ in 0..self.pool_size { + let mut p = AudioStreamPlayer::new_alloc(); + p.set_bus("Sfx"); + self.base_mut().add_child(&p.clone().upcast::()); + self.sfx_pool.push(p); + } + + let mut strain = AudioStreamPlayer::new_alloc(); + strain.set_bus("Sfx"); + self.base_mut().add_child(&strain.clone().upcast::()); + self.strain_player = Some(strain); + + let mut hb = AudioStreamPlayer::new_alloc(); + hb.set_bus("Sfx"); + self.base_mut().add_child(&hb.clone().upcast::()); + self.heartbeat_player = Some(hb); + + let mut mus = AudioStreamPlayer::new_alloc(); + mus.set_bus("Music"); + self.base_mut().add_child(&mus.clone().upcast::()); + self.music_player = Some(mus); + + if let Some(bank) = self.bank.clone() { + let bank_bind = bank.bind(); + if let Some(clip) = &bank_bind.heartbeat_loop { + if let Some(hb_player) = &mut self.heartbeat_player { + hb_player.set_stream(&clip.clone()); + hb_player.set_volume_db(-80.0); + hb_player.play(); + } + } + } + } + + fn play_music(&mut self, clip: Gd) { + if let Some(p) = &mut self.music_player { + p.set_stream(&clip); + p.play(); + } + } + + fn play_bank_sfx(&mut self, selector: F) + where + F: FnOnce(&SoundBank) -> Option>, + { + let clip = self.bank.as_ref().and_then(|b| selector(&b.bind())); + + if let Some(c) = clip { + self.play_sfx(c); + } + } + + fn play_sfx(&mut self, clip: Gd) { + for p in &mut self.sfx_pool { + if !p.is_playing() { + p.set_stream(&clip); + p.set_pitch_scale(1.0); + p.play(); + return; + } + } + if let Some(p) = self.sfx_pool.first_mut() { + p.set_stream(&clip); + p.play(); + } + } + + fn play_strain_loop(&mut self) { + if let Some(bank) = self.bank.clone() { + if let Some(clip) = &bank.bind().strain_loop { + if let Some(p) = &mut self.strain_player { + p.set_stream(&clip.clone()); + p.play(); + } + } + } + } + + fn stop_strain(&mut self) { + if let Some(p) = &mut self.strain_player { + p.stop(); + } + } + + fn update_strain_pitch(&mut self, progress: f32) { + if let Some(p) = &mut self.strain_player { + let pitch = 1.0 + (progress * 0.3); + p.set_pitch_scale(pitch); + } + } + + fn update_heartbeat(&mut self, focus: f32) { + if let Some(p) = &mut self.heartbeat_player { + if focus < 0.1 { + p.set_volume_db(-80.0); + } else { + let t = (focus - 0.1) / 0.9; + let vol = -30.0 + (t * (5.0 - (-30.0))); + let pitch = 1.0 + (t * 0.4); + p.set_volume_db(vol); + p.set_pitch_scale(pitch); + } + } + } +} diff --git a/rust/src/systems/tunnel_system.rs b/rust/src/systems/tunnel_system.rs new file mode 100644 index 0000000..cbf97e0 --- /dev/null +++ b/rust/src/systems/tunnel_system.rs @@ -0,0 +1,82 @@ +use godot::{ + classes::{ColorRect, ShaderMaterial}, + prelude::*, +}; + +use crate::{core::game_state::GameState, data::tunnel_config::TunnelConfig}; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct TunnelSystem { + #[export] + game_state: Option>, + #[export] + config: Option>, + #[export] + vignette_overlay: Option>, + + base: Base, +} + +#[godot_api] +impl INode for TunnelSystem { + fn init(base: Base) -> Self { + Self { + game_state: None, + config: None, + vignette_overlay: None, + base, + } + } + + fn process(&mut self, delta: f64) { + let Some(state) = &self.game_state else { + return; + }; + let Some(config) = &self.config else { + return; + }; + + let state_bind = state.bind(); + let is_lifting = state_bind.get_is_lifting(); + let current_focus = state_bind.get_focus(); + + drop(state_bind); + + let config_bind = config.bind(); + let dt = delta as f32; + + let mut new_focus = current_focus; + + if is_lifting { + new_focus += config_bind.vision_narrow_rate * dt; + } else { + new_focus -= config_bind.vision_recover_rate * dt; + } + + new_focus = new_focus.clamp(0.0, 1.0); + + let max_intensity = config_bind.max_tunnel_intensity; + + let visual_raw = if let Some(curve) = &config_bind.vision_curve { + curve.sample(new_focus) + } else { + new_focus + }; + + let visual_value = visual_raw * max_intensity; + + if let Some(overlay) = &mut self.vignette_overlay { + if let Some(material) = overlay + .get_material() + .and_then(|m| Some(m.try_cast::())) + { + if let Ok(mut mat) = material { + mat.set_shader_parameter("vignette_intensity", &visual_value.to_variant()); + } + } + } + + state.bind().set_focus_intensity(new_focus); + } +} diff --git a/rust/src/ui/lift_progress_bar.rs b/rust/src/ui/lift_progress_bar.rs new file mode 100644 index 0000000..081a57b --- /dev/null +++ b/rust/src/ui/lift_progress_bar.rs @@ -0,0 +1,37 @@ +use crate::core::game_state::GameState; +use godot::{ + classes::{IProgressBar, ProgressBar}, + prelude::*, +}; + +#[derive(GodotClass)] +#[class(base=ProgressBar)] +pub struct LiftProgressBar { + #[export] + game_state: Option>, + + base: Base, +} + +#[godot_api] +impl IProgressBar for LiftProgressBar { + fn init(base: Base) -> Self { + Self { + game_state: None, + base, + } + } + + fn ready(&mut self) { + self.base_mut().set_min(0.0); + self.base_mut().set_max(1.0); + self.base_mut().set_value(0.0); + } + + fn process(&mut self, _delta: f64) { + if let Some(state) = &self.game_state { + let progress = state.bind().get_lift_progress(); + self.base_mut().set_value(progress as f64); + } + } +} diff --git a/rust/src/ui/main_menu.rs b/rust/src/ui/main_menu.rs new file mode 100644 index 0000000..f93b617 --- /dev/null +++ b/rust/src/ui/main_menu.rs @@ -0,0 +1,59 @@ +use godot::{ + classes::{AudioServer, CheckButton, Control, IControl}, + prelude::*, +}; + +#[derive(GodotClass)] +#[class(base=Control)] +pub struct MainMenu { + #[export] + game_scene: Option>, + + #[export] + mute_button: Option>, + + base: Base, +} + +#[godot_api] +impl IControl for MainMenu { + fn init(base: Base) -> Self { + Self { + game_scene: None, + mute_button: None, + base, + } + } + + fn ready(&mut self) { + let mut audio_server = AudioServer::singleton(); + let master_bus = audio_server.get_bus_index("Master"); + audio_server.set_bus_mute(master_bus, false); + } +} + +#[godot_api] +impl MainMenu { + #[func] + fn on_play_pressed(&mut self) { + if let Some(scene) = &self.game_scene { + if let Some(mut tree) = self.base().get_tree() { + tree.change_scene_to_packed(&scene.clone()); + } + } + } + + #[func] + fn on_quit_pressed(&mut self) { + if let Some(mut tree) = self.base().get_tree() { + tree.quit(); + } + } + + #[func] + fn on_mute_toggled(&mut self, toggled_on: bool) { + let mut audio_server = AudioServer::singleton(); + let master_bus = audio_server.get_bus_index("Master"); + audio_server.set_bus_mute(master_bus, toggled_on); + } +} diff --git a/rust/src/ui/mod.rs b/rust/src/ui/mod.rs new file mode 100644 index 0000000..f4e5d9f --- /dev/null +++ b/rust/src/ui/mod.rs @@ -0,0 +1,2 @@ +pub mod lift_progress_bar; +pub mod main_menu; diff --git a/rust/src/visuals/lift_sync_controller.rs b/rust/src/visuals/lift_sync_controller.rs new file mode 100644 index 0000000..f2cb613 --- /dev/null +++ b/rust/src/visuals/lift_sync_controller.rs @@ -0,0 +1,107 @@ +use crate::core::game_state::GameState; +use godot::{ + classes::{AnimatedSprite2D, Sprite2D}, + prelude::*, +}; + +#[derive(GodotClass)] +#[class(base=Node)] +pub struct LiftSyncController { + #[export] + player_anim: Option>, + #[export] + barbell: Option>, + #[export] + game_state: Option>, + + #[export] + animation_name: GString, + #[export] + bar_positions: Array, + #[export] + simulate_reps: bool, + #[export] + rep_speed: f32, + + current_rep_progress: f32, + + base: Base, +} + +#[godot_api] +impl INode for LiftSyncController { + fn init(base: Base) -> Self { + Self { + player_anim: None, + barbell: None, + game_state: None, + animation_name: "lift".into(), + bar_positions: Array::new(), + simulate_reps: true, + rep_speed: 2.0, + current_rep_progress: 0.0, + base, + } + } + + fn process(&mut self, delta: f64) { + let Some(state) = &self.game_state else { + godot_error!("LiftSyncController: No game state assigned"); + return; + }; + + let state_bind = state.bind(); + let is_lifting = state_bind.get_is_lifting(); + + let visual_height = state_bind.inner.read().unwrap().visual_height; + drop(state_bind); + + let dt = delta as f32; + + if self.simulate_reps { + if is_lifting { + self.current_rep_progress += self.rep_speed * dt; + } else { + if self.current_rep_progress > 0.0 { + self.current_rep_progress -= self.rep_speed * dt; + self.current_rep_progress = self.current_rep_progress.max(0.0); + } + } + + let ping_pong_val = + godot::global::pingpong(self.current_rep_progress as f64, 1.0) as f32; + self.update_visuals(ping_pong_val); + } else { + self.update_visuals(visual_height); + } + } +} + +impl LiftSyncController { + fn update_visuals(&mut self, normalized_height: f32) { + if self.player_anim.is_none() || self.barbell.is_none() || self.bar_positions.is_empty() { + godot_error!("LiftSyncController: Missing visuals or bar positions"); + return; + } + + let total_frames = self.bar_positions.len() as i32; + let frame_index_f = normalized_height * (total_frames as f32 - 0.01); + let frame_index = (frame_index_f.floor() as i32).clamp(0, total_frames - 1); + + if let Some(anim) = &mut self.player_anim { + anim.set_frame(frame_index); + + let current_anim = anim.get_animation(); + if current_anim != StringName::from(&self.animation_name) { + let anim_name_sn = StringName::from(&self.animation_name); + anim.play_ex().name(&anim_name_sn).done(); + } + } + + if let Some(bar) = &mut self.barbell { + if let Some(pos) = self.bar_positions.get(frame_index as usize) { + bar.set_position(pos); + } + } + } +} diff --git a/rust/src/visuals/mod.rs b/rust/src/visuals/mod.rs new file mode 100644 index 0000000..3c8575e --- /dev/null +++ b/rust/src/visuals/mod.rs @@ -0,0 +1 @@ +pub mod lift_sync_controller;