diff --git a/Babushka.sln.DotSettings b/Babushka.sln.DotSettings index ed91201..a4c6213 100644 --- a/Babushka.sln.DotSettings +++ b/Babushka.sln.DotSettings @@ -1,4 +1,5 @@  + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Instance fields (not private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /></Policy> Godot Signal [Signal] public delegate void $SignalName$EventHandler($END$); diff --git a/Babushka.sln.DotSettings.user b/Babushka.sln.DotSettings.user index 274a05f..770ca7c 100644 --- a/Babushka.sln.DotSettings.user +++ b/Babushka.sln.DotSettings.user @@ -19,4 +19,15 @@ ForceIncluded ForceIncluded ForceIncluded - ForceIncluded \ No newline at end of file + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + <SessionState ContinuousTestingMode="0" IsActive="True" Name="Tests" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <TestAncestor> + <TestId>NUnit3x::A6EF2269-9E64-40D4-BA0A-33CB234E2503::net9.0::BabushkaTest.Tests</TestId> + </TestAncestor> +</SessionState> diff --git a/prefabs/fight/fight_scene_switcher.tscn b/prefabs/fight/fight_scene_switcher.tscn new file mode 100644 index 0000000..7a89541 --- /dev/null +++ b/prefabs/fight/fight_scene_switcher.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://bcld43daavmrn"] + +[ext_resource type="Script" uid="uid://cql8mt5jsmcdl" path="res://scripts/CSharp/Common/Fight/FightSceneSwitcher.cs" id="1_5dt1r"] + +[node name="FightSceneSwitcher" type="Node" node_paths=PackedStringArray("sceneRoot")] +script = ExtResource("1_5dt1r") +sceneRoot = NodePath("") +fightRoomScenePath = "res://scenes/Babushka_scene_fight_world_room.tscn" +fightHappeningScene = "res://scenes/Babushka_scene_fight_happening.tscn" diff --git a/prefabs/fightOld/fighters/enemy_blob_fighter.tscn b/prefabs/fight/fighters/enemy_blob_fighter.tscn similarity index 91% rename from prefabs/fightOld/fighters/enemy_blob_fighter.tscn rename to prefabs/fight/fighters/enemy_blob_fighter.tscn index 23f6c9e..bab5781 100644 --- a/prefabs/fightOld/fighters/enemy_blob_fighter.tscn +++ b/prefabs/fight/fighters/enemy_blob_fighter.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=10 format=3 uid="uid://bp64p6y72j71w"] [ext_resource type="Texture2D" uid="uid://ccrnmx6bd842k" path="res://art/characters/farm fäulnis blobs.png" id="1_vem8k"] -[ext_resource type="Script" uid="uid://by88f32fou7lh" path="res://scripts/CSharp/Common/FightOld/Fighter.cs" id="2_4w1ab"] +[ext_resource type="Script" path="res://scripts/CSharp/Common/FightOld/Fighter.cs" id="2_4w1ab"] [ext_resource type="Texture2D" uid="uid://qlfwuakhe57t" path="res://art/ui/UI/attack_select_wheel.png" id="3_v4f83"] [ext_resource type="AudioStream" uid="uid://x7cc5woop5ec" path="res://audio/sfx/Battle/Enemies/SFX_Slime_Hit_V2_03.wav" id="5_v4f83"] [ext_resource type="Texture2D" uid="uid://bn56p0ytuo060" path="res://art/ui/UI/AttackButton.png" id="5_vbkts"] @@ -19,6 +19,7 @@ script = ExtResource("2_4w1ab") name = "Blob" maxHealth = 20 attackStrength = 10 +maxActions = null _attackButtons = NodePath("FightButtons") _targetButtons = NodePath("TargetButtons") _targetMarker = NodePath("TargetButtons/TargetMarker") @@ -95,9 +96,6 @@ stream = ExtResource("6_vbkts") [node name="AttackAudio" type="AudioStreamPlayer" parent="."] stream = ExtResource("6_oykh8") -[connection signal="Attacking" from="." to="AttackAudio" method="play" binds= [0.0]] -[connection signal="DamageTaken" from="." to="HitAudio" method="play" binds= [0.0]] -[connection signal="Dying" from="." to="DieAudio" method="play" binds= [0.0]] [connection signal="input_event" from="TargetButtons/Area2D" to="." method="TargetMouseEvent"] [connection signal="mouse_entered" from="TargetButtons/Area2D" to="." method="StartHoverTarget"] [connection signal="mouse_exited" from="TargetButtons/Area2D" to="." method="EndHoverTarget"] diff --git a/prefabs/fightOld/fighters/enemy_mavkha_fighter.tscn b/prefabs/fight/fighters/enemy_mavkha_fighter.tscn similarity index 88% rename from prefabs/fightOld/fighters/enemy_mavkha_fighter.tscn rename to prefabs/fight/fighters/enemy_mavkha_fighter.tscn index 6c78582..d68c61d 100644 --- a/prefabs/fightOld/fighters/enemy_mavkha_fighter.tscn +++ b/prefabs/fight/fighters/enemy_mavkha_fighter.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=10 format=3 uid="uid://cr66tpdr5rma5"] -[ext_resource type="Script" uid="uid://by88f32fou7lh" path="res://scripts/CSharp/Common/FightOld/Fighter.cs" id="1_t6th8"] +[ext_resource type="Script" uid="uid://by88f32fou7lh" path="res://scripts/CSharp/Common/Fight/FighterVisual.cs" id="1_t6th8"] [ext_resource type="Texture2D" uid="uid://bexymddkb6l0o" path="res://art/characters/Mavka/mavkha.png" id="2_shg7p"] [ext_resource type="Texture2D" uid="uid://qlfwuakhe57t" path="res://art/ui/UI/attack_select_wheel.png" id="3_nkuei"] [ext_resource type="Texture2D" uid="uid://bn56p0ytuo060" path="res://art/ui/UI/AttackButton.png" id="4_u3hw3"] @@ -14,16 +14,8 @@ radius = 388.063 [sub_resource type="CircleShape2D" id="CircleShape2D_s74nc"] radius = 173.44 -[node name="EnemyMavkhaFighter" type="Node2D" node_paths=PackedStringArray("_attackButtons", "_targetButtons", "_targetMarker", "_healthText", "_visualSprite")] +[node name="EnemyMavkhaFighter" type="Node2D"] script = ExtResource("1_t6th8") -name = "Mavkha" -maxHealth = 40 -attackStrength = 10 -_attackButtons = NodePath("FightButtons") -_targetButtons = NodePath("TargetButtons") -_targetMarker = NodePath("TargetButtons/TargetMarker") -_healthText = NodePath("HealthShow") -_visualSprite = NodePath("Visual") [node name="Visual" type="Node2D" parent="."] diff --git a/prefabs/fight/fighters/vesna_fighter.tscn b/prefabs/fight/fighters/vesna_fighter.tscn new file mode 100644 index 0000000..35bfa8f --- /dev/null +++ b/prefabs/fight/fighters/vesna_fighter.tscn @@ -0,0 +1,64 @@ +[gd_scene load_steps=7 format=3 uid="uid://cpanatqdjjpa3"] + +[ext_resource type="Script" path="res://scripts/CSharp/Common/FightOld/Fighter.cs" id="1_f3j2x"] +[ext_resource type="Texture2D" uid="uid://om2axn1vfa5o" path="res://art/animation/Vesna2D/Vesna Anims Sequences/S01-Idle/0001.png" id="2_2ud32"] +[ext_resource type="Texture2D" uid="uid://qlfwuakhe57t" path="res://art/ui/UI/attack_select_wheel.png" id="3_80knd"] +[ext_resource type="AudioStream" uid="uid://ch4c1wh4ghxyo" path="res://audio/sfx/Battle/Vesna/SFX_Battle_Vesna_Defense_08.wav" id="5_4r2vf"] +[ext_resource type="AudioStream" uid="uid://ccionrfr6e3lb" path="res://audio/sfx/Battle/Vesna/SFX_Battle_Vesna_Attack_04.wav" id="6_u1ayv"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_0tqnl"] +radius = 291.58 + +[node name="VesnaFighter" type="Node2D" node_paths=PackedStringArray("_attackButtons", "_targetButtons", "_targetMarker", "_healthText", "_visualSprite")] +script = ExtResource("1_f3j2x") +name = "Vesna" +maxHealth = 100 +attackStrength = 10 +maxActions = null +_attackButtons = NodePath("") +_targetButtons = NodePath("TargetButtons") +_targetMarker = NodePath("TargetButtons/TargetMarker") +_healthText = NodePath("HealthShow") +_visualSprite = NodePath("Sprite2D") + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("2_2ud32") +offset = Vector2(43, -379) + +[node name="TargetButtons" type="Node2D" parent="."] +visible = false + +[node name="TargetMarker" type="Sprite2D" parent="TargetButtons"] +visible = false +z_index = 200 +position = Vector2(8, -122) +scale = Vector2(4.245, 4.245) +texture = ExtResource("3_80knd") + +[node name="Area2D" type="Area2D" parent="TargetButtons"] +position = Vector2(3, -76) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="TargetButtons/Area2D"] +shape = SubResource("CircleShape2D_0tqnl") + +[node name="HealthShow" type="Label" parent="."] +z_index = 200 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -197.0 +offset_top = -947.0 +offset_right = 207.0 +offset_bottom = -801.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_font_sizes/font_size = 106 +text = "100/100" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="HitAudio" type="AudioStreamPlayer" parent="."] +stream = ExtResource("5_4r2vf") + +[node name="AttackAudio" type="AudioStreamPlayer" parent="."] +stream = ExtResource("6_u1ayv") diff --git a/prefabs/fightOld/fight_manager_autoload.tscn b/prefabs/fightOld/fight_manager_autoload.tscn index a7d72f2..6f6385b 100644 --- a/prefabs/fightOld/fight_manager_autoload.tscn +++ b/prefabs/fightOld/fight_manager_autoload.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://cnjsepvaqdbyq"] [ext_resource type="Script" uid="uid://j5ge24rk25wm" path="res://scripts/CSharp/Common/FightOld/FightManager.cs" id="1_8p7ev"] -[ext_resource type="PackedScene" uid="uid://cpanatqdjjpa3" path="res://prefabs/fightOld/fighters/vesna_fighter.tscn" id="2_ak1vo"] +[ext_resource type="PackedScene" uid="uid://cpanatqdjjpa3" path="res://prefabs/fight/fighters/vesna_fighter.tscn" id="2_ak1vo"] [node name="FightManagerAutoload" type="Node"] script = ExtResource("1_8p7ev") diff --git a/prefabs/fightOld/fighters/vesna_fighter.tscn b/prefabs/fightOld/fighters/vesna_fighter.tscn deleted file mode 100644 index 841ac03..0000000 --- a/prefabs/fightOld/fighters/vesna_fighter.tscn +++ /dev/null @@ -1,123 +0,0 @@ -[gd_scene load_steps=11 format=3 uid="uid://cpanatqdjjpa3"] - -[ext_resource type="Script" uid="uid://by88f32fou7lh" path="res://scripts/CSharp/Common/FightOld/Fighter.cs" id="1_f3j2x"] -[ext_resource type="Texture2D" uid="uid://om2axn1vfa5o" path="res://art/animation/Vesna2D/Vesna Anims Sequences/S01-Idle/0001.png" id="2_2ud32"] -[ext_resource type="Texture2D" uid="uid://qlfwuakhe57t" path="res://art/ui/UI/attack_select_wheel.png" id="3_80knd"] -[ext_resource type="AudioStream" uid="uid://ch4c1wh4ghxyo" path="res://audio/sfx/Battle/Vesna/SFX_Battle_Vesna_Defense_08.wav" id="5_4r2vf"] -[ext_resource type="Texture2D" uid="uid://6h85o7fj7gmu" path="res://art/animation/Vesna3D/vesna-more-tools.png" id="5_l04qi"] -[ext_resource type="Texture2D" uid="uid://crak7ton4lab0" path="res://art/ui/UI/EmptyFightButton.png" id="5_rjjub"] -[ext_resource type="Texture2D" uid="uid://c3wht0nakaki1" path="res://art/ui/UI/icons/icon-fruit-tomatoe.png" id="6_l04qi"] -[ext_resource type="AudioStream" uid="uid://ccionrfr6e3lb" path="res://audio/sfx/Battle/Vesna/SFX_Battle_Vesna_Attack_04.wav" id="6_u1ayv"] - -[sub_resource type="CircleShape2D" id="CircleShape2D_0tqnl"] -radius = 291.58 - -[sub_resource type="CircleShape2D" id="CircleShape2D_4r2vf"] -radius = 173.44 - -[node name="VesnaFighter" type="Node2D" node_paths=PackedStringArray("_attackButtons", "_targetButtons", "_targetMarker", "_healthText", "_visualSprite")] -script = ExtResource("1_f3j2x") -name = "Vesna" -maxHealth = 100 -attackStrength = 10 -_attackButtons = NodePath("FightButtons") -_targetButtons = NodePath("TargetButtons") -_targetMarker = NodePath("TargetButtons/TargetMarker") -_healthText = NodePath("HealthShow") -_visualSprite = NodePath("Sprite2D") - -[node name="Sprite2D" type="Sprite2D" parent="."] -texture = ExtResource("2_2ud32") -offset = Vector2(43, -379) - -[node name="TargetButtons" type="Node2D" parent="."] -visible = false - -[node name="TargetMarker" type="Sprite2D" parent="TargetButtons"] -visible = false -z_index = 200 -position = Vector2(8, -122) -scale = Vector2(4.245, 4.245) -texture = ExtResource("3_80knd") - -[node name="Area2D" type="Area2D" parent="TargetButtons"] -position = Vector2(3, -76) - -[node name="CollisionShape2D" type="CollisionShape2D" parent="TargetButtons/Area2D"] -shape = SubResource("CircleShape2D_0tqnl") - -[node name="FightButtons" type="Node2D" parent="."] -position = Vector2(3, -714) - -[node name="CircleBackground" type="Sprite2D" parent="FightButtons"] -z_index = 200 -scale = Vector2(4.245, 4.245) -texture = ExtResource("3_80knd") - -[node name="AttackButton" type="Node2D" parent="FightButtons"] -position = Vector2(0, -536) - -[node name="ButtonBackground" type="Sprite2D" parent="FightButtons/AttackButton"] -z_index = 200 -scale = Vector2(2.48, 2.48) -texture = ExtResource("5_rjjub") - -[node name="Sprite2D" type="Sprite2D" parent="FightButtons/AttackButton/ButtonBackground"] -position = Vector2(6.04839, -10.0806) -rotation = -1.0088 -scale = Vector2(0.249373, 0.25079) -texture = ExtResource("5_l04qi") -region_enabled = true -region_rect = Rect2(291.897, 15.8974, 272.82, 479.385) - -[node name="Area2D" type="Area2D" parent="FightButtons/AttackButton"] -collision_layer = 16 - -[node name="CollisionShape2D" type="CollisionShape2D" parent="FightButtons/AttackButton/Area2D"] -shape = SubResource("CircleShape2D_4r2vf") - -[node name="HealButton" type="Node2D" parent="FightButtons"] -position = Vector2(427, -334) - -[node name="ButtonBackground" type="Sprite2D" parent="FightButtons/HealButton"] -z_index = 200 -scale = Vector2(2.48, 2.48) -texture = ExtResource("5_rjjub") - -[node name="Sprite2D" type="Sprite2D" parent="FightButtons/HealButton/ButtonBackground"] -position = Vector2(4.83871, 0) -scale = Vector2(0.279343, 0.279343) -texture = ExtResource("6_l04qi") - -[node name="Area2D" type="Area2D" parent="FightButtons/HealButton"] -collision_layer = 16 - -[node name="CollisionShape2D" type="CollisionShape2D" parent="FightButtons/HealButton/Area2D"] -shape = SubResource("CircleShape2D_4r2vf") - -[node name="HealthShow" type="Label" parent="."] -z_index = 200 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = -197.0 -offset_top = -947.0 -offset_right = 207.0 -offset_bottom = -801.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_font_sizes/font_size = 106 -text = "100/100" -horizontal_alignment = 1 -vertical_alignment = 1 - -[node name="HitAudio" type="AudioStreamPlayer" parent="."] -stream = ExtResource("5_4r2vf") - -[node name="AttackAudio" type="AudioStreamPlayer" parent="."] -stream = ExtResource("6_u1ayv") - -[connection signal="Attacking" from="." to="AttackAudio" method="play" binds= [0.0]] -[connection signal="DamageTaken" from="." to="HitAudio" method="play" binds= [0.0]] -[connection signal="input_event" from="FightButtons/AttackButton/Area2D" to="." method="AttackMouseEvent"] -[connection signal="input_event" from="FightButtons/HealButton/Area2D" to="." method="HealMouseEvent"] diff --git a/scenes/Babushka_scene_fight_happening.tscn b/scenes/Babushka_scene_fight_happening.tscn new file mode 100644 index 0000000..7aa492f --- /dev/null +++ b/scenes/Babushka_scene_fight_happening.tscn @@ -0,0 +1,136 @@ +[gd_scene load_steps=4 format=3 uid="uid://cjshlwk8ajpnp"] + +[ext_resource type="Script" uid="uid://cnhpnn8o0gybd" path="res://scripts/CSharp/Common/Fight/FightHappeningSceneSetup.cs" id="1_fiutj"] +[ext_resource type="Script" uid="uid://dwsqst8fhhqlc" path="res://scripts/CSharp/Common/Fight/FighterEntryVisual.cs" id="2_lu4y4"] +[ext_resource type="PackedScene" uid="uid://bcld43daavmrn" path="res://prefabs/fight/fight_scene_switcher.tscn" id="2_phrlx"] + +[node name="BabushkaSceneFightHappening" type="Node2D"] + +[node name="Camera2D" type="Camera2D" parent="."] + +[node name="FightSetup" type="Node2D" parent="."] +script = ExtResource("1_fiutj") + +[node name="FightVisuals" type="Node2D" parent="."] +position = Vector2(0, 259) +script = ExtResource("2_lu4y4") + +[node name="AllyFighters" type="Node2D" parent="FightVisuals"] + +[node name="EnemyFighters" type="Node2D" parent="FightVisuals"] + +[node name="EnvironmentVisuals" type="Node2D" parent="."] + +[node name="FightSceneSwitcher" parent="." instance=ExtResource("2_phrlx")] + +[node name="ActionSelect" type="CanvasLayer" parent="."] + +[node name="BottomPanel" type="Control" parent="ActionSelect"] +custom_minimum_size = Vector2(0, 200) +layout_mode = 3 +anchors_preset = 12 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 0 +size_flags_vertical = 8 + +[node name="background" type="ColorRect" parent="ActionSelect/BottomPanel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(1, 1, 1, 0.27451) + +[node name="VBoxContainer" type="VBoxContainer" parent="ActionSelect/BottomPanel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="MarginContainer" type="MarginContainer" parent="ActionSelect/BottomPanel/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/margin_left = 200 +theme_override_constants/margin_right = 200 + +[node name="HBoxContainer" type="HBoxContainer" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer"] +layout_mode = 2 +alignment = 1 + +[node name="MarginContainer" type="MarginContainer" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="AttackButton" type="Button" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer"] +layout_mode = 2 +theme_override_font_sizes/font_size = 41 +text = "Attack" + +[node name="MarginContainer2" type="MarginContainer" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="Summon Button" type="Button" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2"] +layout_mode = 2 +theme_override_font_sizes/font_size = 41 +text = "Summon" + +[node name="MarginContainer3" type="MarginContainer" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="Talk Button" type="Button" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3"] +layout_mode = 2 +theme_override_font_sizes/font_size = 41 +text = "Talk" + +[node name="MarginContainer4" type="MarginContainer" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="Flee Button" type="Button" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer4"] +layout_mode = 2 +theme_override_font_sizes/font_size = 41 +text = "Flee" + +[node name="MarginContainer2" type="MarginContainer" parent="ActionSelect/BottomPanel/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/margin_left = 200 +theme_override_constants/margin_right = 200 + +[node name="MarginContainer" type="MarginContainer" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer2"] +layout_mode = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="Label" type="Label" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer2/MarginContainer"] +layout_mode = 2 +size_flags_vertical = 1 +theme_override_colors/font_color = Color(0, 0, 0, 1) +theme_override_font_sizes/font_size = 41 +text = "This text explains the currently hovered button" diff --git a/scenes/Babushka_scene_fight_world_room.tscn b/scenes/Babushka_scene_fight_world_room.tscn index f041d8f..9dc77c7 100644 --- a/scenes/Babushka_scene_fight_world_room.tscn +++ b/scenes/Babushka_scene_fight_world_room.tscn @@ -38,8 +38,8 @@ [ext_resource type="Texture2D" uid="uid://bely5cfbf2x52" path="res://art/nature/baum märz 2025/umgeknackst.png" id="36_vwtyh"] [ext_resource type="Script" uid="uid://bryibv73x5iwr" path="res://scripts/CSharp/Common/Fight/NextRoomTrigger.cs" id="37_3y3c4"] [ext_resource type="Script" uid="uid://dpkx2gbg7b5xh" path="res://scripts/CSharp/Common/Fight/PathSetup.cs" id="37_elhbh"] -[ext_resource type="Script" uid="uid://dbu8afaiohpdh" path="res://scripts/CSharp/Common/Fight/FightSceneSetup.cs" id="37_hqa4k"] -[ext_resource type="Script" uid="uid://cql8mt5jsmcdl" path="res://scripts/CSharp/Common/Fight/FightSceneSwitcher.cs" id="38_ir2xa"] +[ext_resource type="Script" path="res://scripts/CSharp/Common/Fight/FightSceneSetup.cs" id="37_hqa4k"] +[ext_resource type="PackedScene" uid="uid://bcld43daavmrn" path="res://prefabs/fight/fight_scene_switcher.tscn" id="40_elhbh"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_ruj2u"] shader = ExtResource("16_0fard") @@ -89,15 +89,15 @@ noise = SubResource("FastNoiseLite_wgikv") [sub_resource type="ShaderMaterial" id="ShaderMaterial_yvxfs"] shader = ExtResource("27_txtka") -shader_parameter/speed = 1.0 -shader_parameter/minStrength = 0.05 -shader_parameter/maxStrength = 0.187 -shader_parameter/strengthScale = 100.0 -shader_parameter/interval = 3.5 -shader_parameter/detail = 2.095 +shader_parameter/speed = 0.4 +shader_parameter/minStrength = 0.101 +shader_parameter/maxStrength = 0.392 +shader_parameter/strengthScale = 270.22 +shader_parameter/interval = 36.75 +shader_parameter/detail = 3.68 shader_parameter/distortion = 1.0 -shader_parameter/heightOffset = 0.51 -shader_parameter/offset = 1.0 +shader_parameter/heightOffset = 0.49 +shader_parameter/offset = 0.2 [sub_resource type="RectangleShape2D" id="RectangleShape2D_ir2xa"] size = Vector2(608, 1256) @@ -729,6 +729,34 @@ position = Vector2(3888, 2688) scale = Vector2(16, 5.48) texture = SubResource("NoiseTexture2D_pjpt5") +[node name="ParalaxForeground" type="ParallaxBackground" parent="."] +layer = 1 + +[node name="fg1" type="ParallaxLayer" parent="ParalaxForeground"] +position = Vector2(-897, -245) +motion_scale = Vector2(1.2, 1.2) +motion_mirroring = Vector2(8192, 0) + +[node name="TreeA4" type="Sprite2D" parent="ParalaxForeground/fg1"] +z_index = 120 +material = SubResource("ShaderMaterial_yvxfs") +position = Vector2(9188, 5991) +scale = Vector2(3.26718, 4.50965) +texture = ExtResource("35_g3bna") +region_enabled = true +region_rect = Rect2(0, 0, 1405.76, 1244) + +[node name="TreeA5" type="Sprite2D" parent="ParalaxForeground/fg1"] +modulate = Color(0.865081, 0.854544, 0.930309, 1) +z_index = 120 +material = SubResource("ShaderMaterial_yvxfs") +position = Vector2(14366, 5831) +scale = Vector2(3.26718, 4.50965) +texture = ExtResource("35_g3bna") +flip_h = true +region_enabled = true +region_rect = Rect2(0, 0, 1405.76, 1244) + [node name="YSorted" type="Node2D" parent="."] z_index = 1 y_sort_enabled = true @@ -1846,15 +1874,6 @@ texture = ExtResource("35_g3bna") region_enabled = true region_rect = Rect2(0, 0, 1405.76, 1244) -[node name="TreeA4" type="Sprite2D" parent="YSorted/ForestVisuals/Static/greenery/trees"] -z_index = 120 -material = SubResource("ShaderMaterial_yvxfs") -position = Vector2(23840, 5685) -scale = Vector2(3.26718, 4.50965) -texture = ExtResource("35_g3bna") -region_enabled = true -region_rect = Rect2(0, 0, 1405.76, 1244) - [node name="TreeA2" type="Sprite2D" parent="YSorted/ForestVisuals/Static/greenery/trees"] z_index = -1 material = SubResource("ShaderMaterial_yvxfs") @@ -2009,7 +2028,7 @@ scale = Vector2(1, 1) z_index = 100 y_sort_enabled = true material = SubResource("ShaderMaterial_yvxfs") -position = Vector2(411, 868) +position = Vector2(304, 1029) rotation = 3.14159 scale = Vector2(5.54387, -3.80466) texture = ExtResource("19_edja8") @@ -2099,7 +2118,7 @@ scale = Vector2(1, 1) z_index = 100 y_sort_enabled = true material = SubResource("ShaderMaterial_yvxfs") -position = Vector2(653, -450) +position = Vector2(559, -459) rotation = 3.14159 scale = Vector2(5.54387, -3.80466) texture = ExtResource("19_edja8") @@ -2122,11 +2141,8 @@ unique_name_in_owner = true script = ExtResource("37_hqa4k") debugLabel = NodePath("../Debug Label") -[node name="FightSceneSwitcher" type="Node" parent="." node_paths=PackedStringArray("sceneRoot")] +[node name="FightSceneSwitcher" parent="." instance=ExtResource("40_elhbh")] unique_name_in_owner = true -script = ExtResource("38_ir2xa") -sceneRoot = NodePath("..") -fightRoomScenePath = "res://scenes/Babushka_scene_fight_world_room.tscn" [node name="Debug Label" type="Label" parent="."] offset_left = 10485.0 diff --git a/scenes/Babushka_scene_forest_fight_1_2d.tscn b/scenes/Babushka_scene_forest_fight_1_2d.tscn index 860d079..ba1e6b3 100644 --- a/scenes/Babushka_scene_forest_fight_1_2d.tscn +++ b/scenes/Babushka_scene_forest_fight_1_2d.tscn @@ -26,10 +26,10 @@ [ext_resource type="Shader" uid="uid://xnky830dtfsn" path="res://shader/repeat_texture.gdshader" id="25_sgom5"] [ext_resource type="Script" uid="uid://di0xxwfw43m0i" path="res://scripts/CSharp/Common/FightOld/FightStarter.cs" id="26_gg38r"] [ext_resource type="PackedScene" uid="uid://hk8ahyp6dgl6" path="res://prefabs/fightOld/fight_base_scene.tscn" id="27_55b52"] -[ext_resource type="PackedScene" uid="uid://bp64p6y72j71w" path="res://prefabs/fightOld/fighters/enemy_blob_fighter.tscn" id="27_hfhye"] +[ext_resource type="PackedScene" uid="uid://bp64p6y72j71w" path="res://prefabs/fight/fighters/enemy_blob_fighter.tscn" id="27_hfhye"] [ext_resource type="PackedScene" uid="uid://c25udixd5m6l0" path="res://prefabs/characters/Player2D.tscn" id="29_3jjxs"] [ext_resource type="PackedScene" uid="uid://ddpl8cbck7e6s" path="res://prefabs/characters/Chugar.tscn" id="29_26tkn"] -[ext_resource type="PackedScene" uid="uid://cr66tpdr5rma5" path="res://prefabs/fightOld/fighters/enemy_mavkha_fighter.tscn" id="29_hfhye"] +[ext_resource type="PackedScene" uid="uid://cr66tpdr5rma5" path="res://prefabs/fight/fighters/enemy_mavkha_fighter.tscn" id="29_hfhye"] [ext_resource type="Resource" uid="uid://dlcmqfjvgphqu" path="res://resources/items/rake.tres" id="30_l10vl"] [ext_resource type="Resource" uid="uid://cndd64batns31" path="res://resources/items/wateringcan.tres" id="31_c2gvt"] [ext_resource type="Texture2D" uid="uid://dyueumlr5ltvr" path="res://art/nature/baum märz 2025/megaeichel megaast.png" id="37_gg38r"] diff --git a/scenes/SceneTransition.tscn b/scenes/SceneTransition.tscn index 6073ff3..226f888 100644 --- a/scenes/SceneTransition.tscn +++ b/scenes/SceneTransition.tscn @@ -105,6 +105,7 @@ _data = { } [node name="SceneTransition" type="CanvasLayer" node_paths=PackedStringArray("animationPlayer")] +layer = 100 script = ExtResource("1_e0bkc") animationPlayer = NodePath("SceneFadeAnimation") diff --git a/scripts/CSharp/Common/Camera/CameraController.cs b/scripts/CSharp/Common/Camera/CameraController.cs index 4a590b3..661e65c 100644 --- a/scripts/CSharp/Common/Camera/CameraController.cs +++ b/scripts/CSharp/Common/Camera/CameraController.cs @@ -18,10 +18,13 @@ public partial class CameraController : Camera2D [Export] private Node2D _followNode; - public FightInstance? fightToShow; + public FightHappening? fightToShow; + public override void _Process(double delta) { - this.GlobalPosition = fightToShow?.camPositionNode.GlobalPosition ?? _followNode.GlobalPosition; + this.GlobalPosition = /*fightToShow?.camPositionNode.GlobalPosition ??*/ _followNode.GlobalPosition; + } + } diff --git a/scripts/CSharp/Common/Fight/AllFightersVisual.cs b/scripts/CSharp/Common/Fight/AllFightersVisual.cs new file mode 100644 index 0000000..e99b836 --- /dev/null +++ b/scripts/CSharp/Common/Fight/AllFightersVisual.cs @@ -0,0 +1,34 @@ +using Godot; +using System; +using Babushka.scripts.CSharp.Common.Fight; + +public partial class AllFightersVisual : Node +{ + [Export] private Node2D _allyFighters; + [Export] private Node2D _enemyFighters; + + [Export] private PackedScene _blobFighterVisual; + [Export] private PackedScene _bigBlobFighterVisual; + [Export] private PackedScene _mavkaFighterVisual; + [Export] private PackedScene _yourMomFighterVisual; + [Export] private PackedScene _vesnaFighterVisual; + + public void EnterFighter(FightWorld.Fighter fighter, bool isEnemy) + { + var parent = isEnemy ? _enemyFighters : _allyFighters; + + var packedScene = fighter.type switch + { + FightWorld.Fighter.Type.Blob => _blobFighterVisual, + FightWorld.Fighter.Type.BigBlob => _bigBlobFighterVisual, + FightWorld.Fighter.Type.Mavka => _mavkaFighterVisual, + FightWorld.Fighter.Type.YourMom => _yourMomFighterVisual, + FightWorld.Fighter.Type.Vesna => _vesnaFighterVisual, + _ => throw new ArgumentOutOfRangeException() + }; + + var fighterVisual = packedScene.Instantiate(); + fighterVisual.Initialize(fighter); + parent.AddChild(fighterVisual); + } +} diff --git a/scripts/CSharp/Common/Fight/AllFightersVisual.cs.uid b/scripts/CSharp/Common/Fight/AllFightersVisual.cs.uid new file mode 100644 index 0000000..acfca36 --- /dev/null +++ b/scripts/CSharp/Common/Fight/AllFightersVisual.cs.uid @@ -0,0 +1 @@ +uid://dwsqst8fhhqlc diff --git a/scripts/CSharp/Common/Fight/FightHappening.cs b/scripts/CSharp/Common/Fight/FightHappening.cs new file mode 100644 index 0000000..3910ea0 --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappening.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.ExceptionServices; +using System.Threading.Tasks; +using Babushka.scripts.CSharp.Common.Util; +using Godot; + +namespace Babushka.scripts.CSharp.Common.Fight; + +public class FightHappening +{ + /* + To get a visual overview of the FightHappening state machine, refer to the graph on miro: + https://miro.com/app/board/uXjVK8YEprM=/?moveToWidget=3458764640805655262&cot=14 + */ + + #region Internal Types + + public enum FightState + { + None, + FightStartAnim, + FightersEnter, + FightersEnterAnim, + NextFighter, + StateCheck, + InputActionSelect, + ActionCheckDetails, + InputActionDetail, + ActionExecute, + ActionAnim, + EnemyActionSelect, + PlayerWin, + EnemyWin, + } + + private class FightersEnterStaging + { + public required List enteringAllyFighters; + public required List enteringEnemyFighters; + + public bool HasAnyToExecute() + { + return enteringAllyFighters.Count != 0 || enteringEnemyFighters.Count != 0; + } + } + + #endregion + + #region Settings + + private const float StartAnimationTime = 1; + private const float FightersEnterAnimationTime = 1; + + #endregion + + #region ShortCuts + + private static FightWorld.FightHappeningData HappeningData => + FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException(); + + private static FightWorld.Fighter CurrentFighter => HappeningData.fighterStack.Current; + + #endregion + + #region Events + + public event Action? transitionFromState; + public event Action? transitionState; + public event Action? transitionToState; + + #endregion + + #region Staging + + private FightersEnterStaging? _fightersEnterStaging; + private FighterAction? _actionStaging; + + #endregion + + #region Public Methods + + public void StartFight() + { + RequireState(FightState.None); + ChangeState(FightState.FightStartAnim); + } + + #endregion + + #region State Machine + + private void ChangeState(FightState nextState) + { + TransitionFromState(); + var lastState = HappeningData.fightState; + HappeningData.fightState = nextState; + TransitionFromToState(nextState, lastState); + TransitionToState(nextState); + } + + private void TransitionFromState() + { + // fixed behaviour + switch (HappeningData.fightState) + { + default: break; + } + + // notify everyone else + transitionFromState?.Invoke(HappeningData.fightState); + } + + private void TransitionFromToState(FightState nextState, FightState lastState) + { + transitionState?.Invoke(lastState, nextState); + } + + private void TransitionToState(FightState nextState) + { + // notify everyone else + transitionToState?.Invoke(nextState); + + // fixed behaviour + switch (HappeningData.fightState) + { + case FightState.FightStartAnim: + AdvanceToStateInSeconds(FightState.FightersEnter, StartAnimationTime); + break; + case FightState.FightersEnter: + _fightersEnterStaging = StageFightersEnter(); + if (_fightersEnterStaging.HasAnyToExecute()) + { + ExecuteFightersEnter(); + ChangeState(FightState.FightersEnterAnim); + } + else + { + ChangeState(FightState.NextFighter); + } + + break; + case FightState.FightersEnterAnim: + AdvanceToStateInSeconds(FightState.NextFighter, FightersEnterAnimationTime); + break; + case FightState.NextFighter: + ExecuteNextFighter(); + ChangeState(FightState.StateCheck); + break; + case FightState.StateCheck: + // restest action staging + _actionStaging = null; + + if ( /*TODO: are all allys dead*/ false) + { + ChangeState(FightState.EnemyWin); + } + else if (HappeningData.enemyGroup.AreAllDead()) + { + ChangeState(FightState.PlayerWin); + } + else if (CurrentFighter.actionsLeft <= 0) + { + ChangeState(FightState.FightersEnter); + } + else if (CurrentFighter.isEnemy) + { + ChangeState(FightState.EnemyActionSelect); + } + else + { + ChangeState(FightState.InputActionSelect); + } + + break; + case FightState.InputActionSelect: + // wait for player input + break; + case FightState.ActionCheckDetails: + if (ActionAbort()) + ChangeState(FightState.InputActionSelect); + else if (ActionNeededDetail() != null) + ChangeState(FightState.InputActionDetail); + else + ChangeState(FightState.ActionExecute); + break; + case FightState.InputActionDetail: + // wait for player input + break; + case FightState.EnemyActionSelect: + _actionStaging = CurrentFighter.AutoSelectAction(); + ChangeState(FightState.ActionExecute); + break; + case FightState.ActionExecute: + ExecuteAction(); + ChangeState(FightState.ActionAnim); + break; + case FightState.ActionAnim: + var actionTime = GetActionAnimationEnd(); + if (actionTime.IsType()) + { + AdvanceToStateInSeconds(FightState.StateCheck, actionTime); + } + else + { + _ = AdvanceToStateWhenDone(FightState.StateCheck, actionTime); + } + + break; + default: break; + } + } + + #endregion + + #region Game Logic + + private FightersEnterStaging StageFightersEnter() + { + // ally + var enteringAllyFighters = new List(); + //TODO + + // enemy + const int totalEnemySpace = 3; + var enemySpaceLeft = totalEnemySpace - HappeningData.enemyGroup.GetEnteredAmount(); + var enterEnemyFighters = new List(); + + for (var i = 0; i < enemySpaceLeft; i++) + { + if (HappeningData.enemyGroup.TryGetFirstUnenteredFighter(out var fighter)) + { + enterEnemyFighters.Add(fighter); + } + } + + return new FightersEnterStaging + { + enteringAllyFighters = enteringAllyFighters, + enteringEnemyFighters = enterEnemyFighters + }; + } + + private void ExecuteFightersEnter() + { + Debug.Assert(_fightersEnterStaging != null); + foreach (var fighter in _fightersEnterStaging.enteringAllyFighters) + { + fighter.entered = true; + HappeningData.fighterStack.AddAsLast(fighter); + } + + foreach (var fighter in _fightersEnterStaging.enteringEnemyFighters) + { + fighter.entered = true; + HappeningData.fighterStack.AddAsLast(fighter); + } + } + + private void ExecuteNextFighter() + { + HappeningData.fighterStack.Next(); + } + + private void ExecuteAction() + { + Debug.Assert(_actionStaging != null); + _actionStaging.ExecuteAction(); + } + + private Variant> GetActionAnimationEnd() + { + Debug.Assert(_actionStaging != null); + return _actionStaging.GetAnimationEnd(); + } + + private bool ActionAbort() + { + Debug.Assert(_actionStaging != null); + return _actionStaging.MarkedForAbort(); + } + + private FighterAction.FighterActionDetail? ActionNeededDetail() + { + Debug.Assert(_actionStaging != null); + return _actionStaging.NeededDetail(); + } + + #endregion // Game Logic + + #region Utility + + private void RequireState(params FightState[] states) + { + if (states.Contains(HappeningData.fightState)) + return; + + throw new Exception( + $"Can not call this Method while in state {HappeningData.fightState}. Only available in {string.Join(" ,", states)}"); + } + + private void AdvanceToStateInSeconds(FightState nextState, float seconds) + { + FightWorld.Instance.GetTree().CreateTimer(seconds).Timeout += () => ChangeState(nextState); + } + + private async Task AdvanceToStateWhenDone(FightState nextState, Func isDone) + { + while (!isDone()) + { + await FightWorld.Instance.ToSignal(FightWorld.Instance.GetTree(), SceneTree.SignalName.ProcessFrame); + } + + ChangeState(nextState); + } + + #endregion +} \ No newline at end of file diff --git a/scripts/CSharp/Common/FightOld/FightInstance.cs.uid b/scripts/CSharp/Common/Fight/FightHappening.cs.uid similarity index 100% rename from scripts/CSharp/Common/FightOld/FightInstance.cs.uid rename to scripts/CSharp/Common/Fight/FightHappening.cs.uid diff --git a/scripts/CSharp/Common/Fight/FightHappeningSceneSetup.cs b/scripts/CSharp/Common/Fight/FightHappeningSceneSetup.cs new file mode 100644 index 0000000..293806e --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappeningSceneSetup.cs @@ -0,0 +1,15 @@ +using Godot; +using System; +using System.Diagnostics; +using Babushka.scripts.CSharp.Common.Fight; + +public partial class FightHappeningSceneSetup : Node2D +{ + public override void _Ready() + { + var fightHappening = FightWorld.Instance.fightHappeningData; + Debug.Assert(fightHappening != null, "Fight happening scene loaded, without a fight happening"); + + + } +} diff --git a/scripts/CSharp/Common/Fight/FightHappeningSceneSetup.cs.uid b/scripts/CSharp/Common/Fight/FightHappeningSceneSetup.cs.uid new file mode 100644 index 0000000..1ac025e --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappeningSceneSetup.cs.uid @@ -0,0 +1 @@ +uid://cnhpnn8o0gybd diff --git a/scripts/CSharp/Common/Fight/FightSceneSetup.cs b/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs similarity index 92% rename from scripts/CSharp/Common/Fight/FightSceneSetup.cs rename to scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs index 7e46e20..3df9eec 100644 --- a/scripts/CSharp/Common/Fight/FightSceneSetup.cs +++ b/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs @@ -2,7 +2,7 @@ using Godot; namespace Babushka.scripts.CSharp.Common.Fight; -public partial class FightSceneSetup : Node +public partial class FightRoomSceneSetup : Node { [Export] private Label debugLabel; public override void _Ready() diff --git a/scripts/CSharp/Common/Fight/FightSceneSetup.cs.uid b/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs.uid similarity index 100% rename from scripts/CSharp/Common/Fight/FightSceneSetup.cs.uid rename to scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs.uid diff --git a/scripts/CSharp/Common/Fight/FightSceneSwitcher.cs b/scripts/CSharp/Common/Fight/FightSceneSwitcher.cs index a6fdcb2..5b31b1c 100644 --- a/scripts/CSharp/Common/Fight/FightSceneSwitcher.cs +++ b/scripts/CSharp/Common/Fight/FightSceneSwitcher.cs @@ -9,15 +9,15 @@ public partial class FightSceneSwitcher : Node { [Export] private Node sceneRoot; [Export] private string fightRoomScenePath; - [Export] private string fightingGroupScene; + [Export] private string fightHappeningScene; private void LoadNext() { var nextRoom = FightWorld.Instance.currentRoom; Debug.Assert(nextRoom != null, "nextRoom!=null"); - var nextEnemyGroup = FightWorld.Instance.inFightWith; - SceneTransitionThreaded.Instance.ChangeSceneToFile(nextEnemyGroup != null - ? fightingGroupScene + var nextFightHappening = FightWorld.Instance.fightHappeningData; + SceneTransitionThreaded.Instance.ChangeSceneToFile(nextFightHappening != null + ? fightHappeningScene : fightRoomScenePath); UnloadAfterDelay(); } diff --git a/scripts/CSharp/Common/Fight/FightUtils.cs b/scripts/CSharp/Common/Fight/FightUtils.cs new file mode 100644 index 0000000..25fc961 --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightUtils.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Babushka.scripts.CSharp.Common.Fight; + +public static class FightUtils +{ + public static int GetEnteredAmount(this FightWorld.EnemyGroup self) + { + return self.enemies.Count(e => e.IsAlive() && e.entered); + } + + public static bool TryGetFirstUnenteredFighter(this FightWorld.EnemyGroup self, out FightWorld.Fighter fighter) + { + foreach (var f in self.enemies.Where(e=>!e.entered && e.IsAlive())) + { + fighter = f; + return true; + } + + fighter = null!; + return false; + } + + public static bool IsAlive(this FightWorld.Fighter self) + { + return self.GetHealth() >= 0; + } + + public static bool IsDead(this FightWorld.Fighter self) + { + return !self.IsAlive(); + } + + public static int GetHealth(this FightWorld.Fighter self) + { + return self.health ?? self.maxHealth; + } + + public static bool AreAllDead(this FightWorld.EnemyGroup self) + { + return self.enemies.All(e => e.IsDead()); + } + +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FightUtils.cs.uid b/scripts/CSharp/Common/Fight/FightUtils.cs.uid new file mode 100644 index 0000000..87c1ce4 --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightUtils.cs.uid @@ -0,0 +1 @@ +uid://beuhpltb84pf diff --git a/scripts/CSharp/Common/Fight/FightWorld.cs b/scripts/CSharp/Common/Fight/FightWorld.cs index cf1ff9f..b27c6d4 100644 --- a/scripts/CSharp/Common/Fight/FightWorld.cs +++ b/scripts/CSharp/Common/Fight/FightWorld.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Babushka.scripts.CSharp.Common.Util; using Godot; namespace Babushka.scripts.CSharp.Common.Fight; @@ -18,21 +19,39 @@ public partial class FightWorld : Node public class EnemyGroup { - public required List enemies; + public required List enemies; } - public class Enemy + public class FightHappeningData + { + public FightHappening.FightState fightState = FightHappening.FightState.None; + public FighterStack fighterStack = new(); + public required EnemyGroup enemyGroup; + } + + public class Fighter { public enum Type { Blob, BigBlob, Mavka, - YourMom + YourMom, + Vesna } public required Type type; - public required int? health = null; // null => initialize to full health on spawn + public required int maxHealth; + public required bool isEnemy; + public required List availableActions; + public int? health = null; // null => initialize to full health on spawn + public bool entered = false; + public int actionsLeft; + + public FighterAction AutoSelectAction() + { + return availableActions.Random() ?? new FighterAction.Skip(); + } } #region AutoLoad ( Contains _EnterTree() ) @@ -46,10 +65,10 @@ public partial class FightWorld : Node } #endregion - + public World? world = null; public Room? currentRoom = null; - public EnemyGroup? inFightWith = null; + public FightHappeningData? fightHappeningData = null; public void MyEnterTree() { @@ -135,22 +154,27 @@ public partial class FightWorld : Node return enemyGroup; } - private Enemy GenerateSingleEnemy() + private Fighter GenerateSingleEnemy() { var typeRoll = GD.RandRange(0, 99); var type = typeRoll switch { - < 50 => Enemy.Type.Blob, - < 75 => Enemy.Type.BigBlob, - < 90 => Enemy.Type.Mavka, - _ => Enemy.Type.YourMom + < 50 => Fighter.Type.Blob, + < 75 => Fighter.Type.BigBlob, + < 90 => Fighter.Type.Mavka, + _ => Fighter.Type.YourMom }; - var enemy = new Enemy + var enemy = new Fighter { type = type, - health = null + health = null, + isEnemy = true, + maxHealth = 12, + availableActions = [ + new FighterAction.Skip() + ] }; return enemy; diff --git a/scripts/CSharp/Common/Fight/FighterAction.cs b/scripts/CSharp/Common/Fight/FighterAction.cs new file mode 100644 index 0000000..b18ed6b --- /dev/null +++ b/scripts/CSharp/Common/Fight/FighterAction.cs @@ -0,0 +1,80 @@ +using System; +using System.Threading.Tasks; +using Babushka.scripts.CSharp.Common.Util; +using Godot; + +namespace Babushka.scripts.CSharp.Common.Fight; + +public abstract class FighterAction +{ + public class TargetSelection + { + // ReSharper disable once MemberHidesStaticFromOuterClass + public static readonly TargetSelection Skip = new() { skipTargetSelection = () => true }; + public Func skipTargetSelection = () => false; + } + + public abstract class FighterActionDetail + { + public abstract bool DetailComplete(); + } + + private bool _abort = false; + + #region Shortcuts + + protected static FightWorld.FightHappeningData HappeningData => + FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException(); + + #endregion + + /// + /// Executes the data modification for the action. This must happen instantly and not via a coroutines or callbacks. + /// To get a multiple hit effect for one action, use appropriate Visual Manipulation functions in AnimateAction. + /// + public virtual void ExecuteAction() + { + } + + /// + /// Returns a way to determine, when an action animation is done + /// + /// + /// A variant that can be float or Func<bool>.
+ /// When the return type is float, the animation will take the return value amount of seconds.
+ /// When the return type is Func<bool>, the animation will be done, when the function returns true. + ///
+ public abstract Variant> GetAnimationEnd(); + + /// + /// Animates the action. + /// + public virtual async Task AnimateAction() + { + } + + public void MarkAbort() + { + _abort = true; + } + + public bool MarkedForAbort() + { + return _abort; + } + + public abstract FighterActionDetail? NeededDetail(); + + public class Skip : FighterAction + { + public override Variant> GetAnimationEnd() + { + return 0f; + } + + public override FighterActionDetail? NeededDetail() + { + return null; + } + } +} diff --git a/scripts/CSharp/Common/Fight/FighterStack.cs b/scripts/CSharp/Common/Fight/FighterStack.cs new file mode 100644 index 0000000..aceb67e --- /dev/null +++ b/scripts/CSharp/Common/Fight/FighterStack.cs @@ -0,0 +1,95 @@ +using System.Collections.Generic; +using Godot.NativeInterop; + +namespace Babushka.scripts.CSharp.Common.Fight; + +public class FighterStack +{ + private class Node + { + public Node next; + public FightWorld.Fighter fighter; + } + + private Node? currentNode; + + public FightWorld.Fighter Current => currentNode.fighter; + + public void Next() + { + currentNode = currentNode.next; + } + + public FightWorld.Fighter PeekNext() + { + return currentNode.next.fighter; + } + + public void AddAsLast(FightWorld.Fighter value) + { + // if first node + if (currentNode == null) + { + currentNode = new Node { fighter = value }; + currentNode.next = currentNode; + return; + } + + var newNode = new Node { fighter = value, next = currentNode }; + var node = currentNode; + while (node.next != currentNode) + { + node = node.next; + } + + node.next = newNode; + } + + public void AddAsNext(FightWorld.Fighter value) + { + // if first node + if (currentNode == null) + { + AddAsLast(value); + return; + } + + var newNode = new Node { fighter = value, next = currentNode.next }; + currentNode.next = newNode; + } + + public bool Remove(FightWorld.Fighter value) + { + if (currentNode == null) return false; + + // if only one node + if (currentNode.next == currentNode) + { + if (currentNode.fighter == value) + { + currentNode = null; + return true; + } + + return false; + } + + var node = currentNode; + do + { + // next is the fighter to remove + if (node.next.fighter == value) + { + // if removing current, keep current + // it will be implicitly deleted on the next Next() call + + node.next = node.next.next; + return true; + } + + node = node.next; + } while (node != currentNode); + + return false; + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/FightOld/Fighter.cs b/scripts/CSharp/Common/Fight/FighterVisual.cs similarity index 71% rename from scripts/CSharp/Common/FightOld/Fighter.cs rename to scripts/CSharp/Common/Fight/FighterVisual.cs index 31afcf4..c092191 100644 --- a/scripts/CSharp/Common/FightOld/Fighter.cs +++ b/scripts/CSharp/Common/Fight/FighterVisual.cs @@ -1,12 +1,13 @@ using Godot; namespace Babushka.scripts.CSharp.Common.Fight; -public partial class Fighter : Node2D +public partial class FighterVisual : Node2D { - [Export] public string name; - [Export] public int maxHealth; - [Export] public int attackStrength; - [Export] public int maxActions = 1; + //[Export] public string name; + //[Export] public int maxHealth; + //[Export] public int attackStrength; + //[Export] public int maxActions = 1; + [Export] public FightWorld.Fighter.Type type; [ExportCategory("References")] [Export] private Node2D _attackButtons; @@ -21,45 +22,29 @@ public partial class Fighter : Node2D [Signal] public delegate void HealedEventHandler(); - private int _health; - private int _actions; + private FightWorld.Fighter _boundFighter; + //private void Die() + //{ + // _visualSprite.Scale = new Vector2(1, 0.3f); + // EmitSignalDying(); + //} - public FightInstance fightInstance; - public int Health - { - get => _health; - set - { - _health = value; - if (_health <= 0) - { - _health = 0; - Die(); - } - if (_health > maxHealth) - { - _health = maxHealth; - } - } - } + //public override void _Ready() + //{ + // UpdateHealthVisual(); + // ResetActions(); + //} - private void Die() + public void Initialize(FightWorld.Fighter fighter) { - _visualSprite.Scale = new Vector2(1, 0.3f); - EmitSignalDying(); - } - - public override void _Ready() - { - Health = maxHealth; + _boundFighter = fighter; UpdateHealthVisual(); - ResetActions(); } public void Attack() { - fightInstance.SelectAttack(this); + //FightHappening.SelectAttack(this); } public void HideAttackButton() @@ -102,17 +87,17 @@ public partial class Fighter : Node2D private void ClickedAttack() { - fightInstance.SelectAttack(this); + //FightHappening.SelectAttack(this); } private void ClickedHeal() { - fightInstance.SelectHeal(this); + //FightHappening.SelectHeal(this); } private void ClickedTarget() { - fightInstance.SelectTargetAndAttack(this); + //FightHappening.SelectTargetAndAttack(this); } public void StartHoverTarget() @@ -127,7 +112,18 @@ public partial class Fighter : Node2D public void UpdateHealthVisual() { - _healthText.Text = $"{Health}/{maxHealth}"; + _healthText.Text = $"{_boundFighter.health}"; + } + + public bool IsDead() + { + //return Health <= 0; + return true; + } + + public void ResetActions() + { + //_actions = maxActions; } public void AttackAnimation(FightAttack attack) @@ -150,26 +146,6 @@ public partial class Fighter : Node2D .SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out); } - public bool IsDead() - { - return Health <= 0; - } - - public void ResetActions() - { - _actions = maxActions; - } - - public bool HasActionsLeft() - { - return _actions > 0; - } - - public void DecrementActions() - { - _actions--; - } - public void HealAnimation() { EmitSignalHealed(); diff --git a/scripts/CSharp/Common/FightOld/Fighter.cs.uid b/scripts/CSharp/Common/Fight/FighterVisual.cs.uid similarity index 100% rename from scripts/CSharp/Common/FightOld/Fighter.cs.uid rename to scripts/CSharp/Common/Fight/FighterVisual.cs.uid diff --git a/scripts/CSharp/Common/Fight/NoFightHappeningException.cs b/scripts/CSharp/Common/Fight/NoFightHappeningException.cs new file mode 100644 index 0000000..12587dd --- /dev/null +++ b/scripts/CSharp/Common/Fight/NoFightHappeningException.cs @@ -0,0 +1,7 @@ +using System; + +namespace Babushka.scripts.CSharp.Common.Fight; + +public class NoFightHappeningException() : Exception("No fight happening right now") +{ +} \ No newline at end of file diff --git a/scripts/CSharp/Common/FightOld/FightAttack.cs b/scripts/CSharp/Common/FightOld/FightAttack.cs index 0c1248f..0397486 100644 --- a/scripts/CSharp/Common/FightOld/FightAttack.cs +++ b/scripts/CSharp/Common/FightOld/FightAttack.cs @@ -4,6 +4,6 @@ public class FightAttack { public int damage; public bool needsSelectedTarget; - public Fighter? target; - public Fighter attacker; + public FighterVisual? target; + public FighterVisual attacker; } \ No newline at end of file diff --git a/scripts/CSharp/Common/FightOld/FightInstance.cs b/scripts/CSharp/Common/FightOld/FightInstance.cs deleted file mode 100644 index 28d608f..0000000 --- a/scripts/CSharp/Common/FightOld/FightInstance.cs +++ /dev/null @@ -1,351 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Babushka.scripts.CSharp.Common.Camera; -using Babushka.scripts.CSharp.Common.Util; -using Godot; -namespace Babushka.scripts.CSharp.Common.Fight; - -public partial class FightInstance : Node2D //TODO: remake -{ - [Export(PropertyHint.ArrayType)] private Node2D[] _friendlyFightSpots; - [Export(PropertyHint.ArrayType)] private Node2D[] _enemyFightSpots; - [Export] public Node2D camPositionNode; - [Export] private FightStateManager _fightStateManager; - [Export] private Label _fightEndText; - - - [Signal] - public delegate void FightStartedEventHandler(); - - [Signal] - public delegate void FightEndedEventHandler(); - - private List _friendlyFighters = new(); - private List _enemyFighters = new(); - - private FightAttack? _stagedAttack = null; - - public override void _Ready() - { - //_fightStateManager.CurrentFightState = FightStateManager.FightState.FightStartAnim; - _fightStateManager.ExitingTransition += from => - { - switch (from) - { - case FightStateManager.FightState.None: - CaptureCamera(); - Show(); - EmitSignalFightStarted(); - break; - case FightStateManager.FightState.Input: - HideAttackButtons(); - break; - case FightStateManager.FightState.InputTargetSelect: - HideTargetButtons(); - break; - case FightStateManager.FightState.FriendAttackAnim: - _stagedAttack = null; - break; - case FightStateManager.FightState.PlayerWinAnim: - case FightStateManager.FightState.EnemyWinAnim: - _fightEndText.Text = ""; - break; - } - }; - - _fightStateManager.EnteringTransition += to => - { - switch (to) - { - case FightStateManager.FightState.None: - EmitSignalFightEnded(); - CleanUp(); - Hide(); - ReleaseCamera(); - break; - case FightStateManager.FightState.Input: - if (CheckWinAndSetState()) - break; - if (CheckFriendlyActionsLeftAndSetState()) - break; - ShowAttackButtons(); - break; - case FightStateManager.FightState.InputTargetSelect: - ShowTargetButtons(); - break; - case FightStateManager.FightState.FriendAttackAnim: - ExecuteAttack(); - GetTree().CreateTimer(1).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.Input; - break; - case FightStateManager.FightState.Enemy: - if (CheckWinAndSetState()) - break; - if (CheckEnemyActionsLeftAndSetState()) - break; - DecideEnemyAttack(); - _fightStateManager.CurrentFightState = FightStateManager.FightState.EnemyAttackAnim; - break; - case FightStateManager.FightState.EnemyAttackAnim: - ExecuteAttack(); - GetTree().CreateTimer(1).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.Enemy; - break; - case FightStateManager.FightState.PlayerWinAnim: - _fightEndText.Text = "You Win!"; - GetTree().CreateTimer(1.5).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.None; - break; - case FightStateManager.FightState.EnemyWinAnim: - _fightEndText.Text = "You Died :("; - GetTree().CreateTimer(3).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.None; - break; - case FightStateManager.FightState.ChangeSideToEnemy: - ResetEnemyActions(); - _fightStateManager.CurrentFightState = FightStateManager.FightState.Enemy; - break; - case FightStateManager.FightState.ChangeSideToFriendly: - ResetFriendlyActions(); - _fightStateManager.CurrentFightState = FightStateManager.FightState.Input; - break; - case FightStateManager.FightState.Heal: - Heal(); - GetTree().CreateTimer(1).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.Input; - break; - } - }; - } - private void Heal() - { - // TODO: make heal staging system - _friendlyFighters.Where(f => !f.IsDead()).ForEach(f => - { - f.Health += 50; - f.HealAnimation(); - f.DecrementActions(); - }); - UpdateHealthVisual(); - } - private void ResetEnemyActions() - { - _enemyFighters.ForEach(f => f.ResetActions()); - } - - private void ResetFriendlyActions() - { - _friendlyFighters.ForEach(f => f.ResetActions()); - } - - /** - * - * true if the state was changed - * - */ - private bool CheckFriendlyActionsLeftAndSetState() - { - var hasActionsLeft = _friendlyFighters.Where(f => !f.IsDead()).Any(f => f.HasActionsLeft()); - if (hasActionsLeft) - { - return false; - } // else - _fightStateManager.CurrentFightState = FightStateManager.FightState.ChangeSideToEnemy; - return true; - } - - /** - * - * true if the state was changed - * - */ - private bool CheckEnemyActionsLeftAndSetState() - { - var hasActionsLeft = _enemyFighters.Where(f => !f.IsDead()).Any(f => f.HasActionsLeft()); - if (hasActionsLeft) - { - return false; - } // else - _fightStateManager.CurrentFightState = FightStateManager.FightState.ChangeSideToFriendly; - return true; - } - - private void CleanUp() - { - _enemyFighters.ForEach(f => f.QueueFree()); - _friendlyFighters.ForEach(f => f.QueueFree()); - _enemyFighters = new(); - _friendlyFighters = new(); - } - private void DecideEnemyAttack() - { - var availableEnemyFighters = - _enemyFighters - .Where(f => !f.IsDead()) - .Where(f=>f.HasActionsLeft()) - .ToList(); - var aliveFriendlyFighters = - _friendlyFighters - .Where(f => !f.IsDead()) - .ToList(); - - if (availableEnemyFighters.Count <= 0) - throw new InvalidOperationException("No enemy fighters available for attack."); - - if (aliveFriendlyFighters.Count <= 0) - throw new InvalidOperationException("No friendly fighters available to target."); - - var fighter = availableEnemyFighters.Random(); - var target = aliveFriendlyFighters.Random(); - - _stagedAttack = new FightAttack - { - attacker = fighter!, - needsSelectedTarget = true, - damage = fighter!.attackStrength, - target = target! - }; - } - - private void ExecuteAttack() - { - if (_stagedAttack == null) - throw new InvalidOperationException("No staged attack to execute."); - - if (!_stagedAttack.needsSelectedTarget) - throw new NotImplementedException("Non-targeted attacks are not implemented yet."); - - if (_stagedAttack.needsSelectedTarget && _stagedAttack.target == null) - throw new InvalidOperationException("No target selected for the staged attack."); - - _stagedAttack.target!.Health -= _stagedAttack.damage; - _stagedAttack.attacker.DecrementActions(); - _stagedAttack.attacker.AttackAnimation(_stagedAttack); - - UpdateHealthVisual(); - } - - private void UpdateHealthVisual() - { - _friendlyFighters - .Concat(_enemyFighters) - .ForEach(f => f.UpdateHealthVisual()); - } - - private void ReleaseCamera() - { - CameraController.Instance.fightToShow = null; - } - - private void CaptureCamera() - { - CameraController.Instance.fightToShow = this; - } - - public void Start(FightParty fightParty, PackedScene?[] enemies) - { - if (_fightStateManager.IsRunning()) - { - GD.PushWarning("Can not start a running fight"); - return; - } - - if (fightParty.vesna) - { - InstantiateFighter(_friendlyFightSpots[1], FightManager.Instance.fightingVesnaScene); - } - - for (var i = 0; i < Math.Min(_enemyFightSpots.Length, enemies.Length); i++) - { - var enemy = enemies[i]; - if (enemy == null) - continue; - - InstantiateFighter(_enemyFightSpots[i], enemy, true); - } - - _fightStateManager.ToStartAnim(); - } - - private void InstantiateFighter(Node2D parent, PackedScene fighterScene, bool isEnemy = false) - { - var fighter = fighterScene.Instantiate(); - fighter.fightInstance = this; - parent.AddChild(fighter); - - if (isEnemy) - { - _enemyFighters.Add(fighter); - } - else - { - _friendlyFighters.Add(fighter); - } - } - - public void SelectAttack(Fighter fighter) - { - _stagedAttack = new FightAttack - { - attacker = fighter, - damage = fighter.attackStrength, - needsSelectedTarget = true - }; - - if (_stagedAttack.needsSelectedTarget) - { - _fightStateManager.CurrentFightState = FightStateManager.FightState.InputTargetSelect; - } - else - { - _fightStateManager.CurrentFightState = FightStateManager.FightState.FriendAttackAnim; - } - } - - private void HideAttackButtons() - { - _friendlyFighters.ForEach(f => f.HideAttackButton()); - } - - private void ShowAttackButtons() - { - _friendlyFighters.ForEach(f => f.ShowAttackButton()); - } - - private void HideTargetButtons() - { - _enemyFighters.ForEach(f => f.HideTargetButtons()); - } - - private void ShowTargetButtons() - { - _enemyFighters.Where(f => !f.IsDead()).ForEach(f => f.ShowTargetButtons()); - } - - public void SelectTargetAndAttack(Fighter fighter) - { - if (_stagedAttack == null) - throw new InvalidOperationException("No staged attack to select target for."); - - _stagedAttack.target = fighter; - - _fightStateManager.CurrentFightState = FightStateManager.FightState.FriendAttackAnim; - } - - public void SelectHeal(Fighter fighter) - { - _fightStateManager.CurrentFightState = FightStateManager.FightState.Heal; - } - - public bool CheckWinAndSetState() - { - if (_enemyFighters.All(f => f.IsDead())) - { - _fightStateManager.CurrentFightState = FightStateManager.FightState.PlayerWinAnim; - return true; - } - if (_friendlyFighters.All(f => f.IsDead())) - { - _fightStateManager.CurrentFightState = FightStateManager.FightState.EnemyWinAnim; - return true; - } - return false; - } -} - diff --git a/scripts/CSharp/Common/FightOld/FightManager.cs b/scripts/CSharp/Common/FightOld/FightManager.cs index ef0652c..8376864 100644 --- a/scripts/CSharp/Common/FightOld/FightManager.cs +++ b/scripts/CSharp/Common/FightOld/FightManager.cs @@ -19,10 +19,10 @@ public partial class FightManager : Node public FightParty fightParty = new(); - public void StartFight(PackedScene[] enemies, FightInstance instance) + public void StartFight(PackedScene[] enemies, FightHappening happening) { GD.Print("Starting Fight"); - instance.Start(fightParty, enemies); + //happening.Start(fightParty, enemies); } } diff --git a/scripts/CSharp/Common/FightOld/FightStarter.cs b/scripts/CSharp/Common/FightOld/FightStarter.cs index 0fd6ae8..780aef0 100644 --- a/scripts/CSharp/Common/FightOld/FightStarter.cs +++ b/scripts/CSharp/Common/FightOld/FightStarter.cs @@ -4,7 +4,7 @@ namespace Babushka.scripts.CSharp.Common.Fight; public partial class FightStarter : Node { [Export(PropertyHint.ArrayType)] private PackedScene[] enemies; - [Export] private FightInstance _fightInstance; + //[Export] private FightHappening _fightHappening; [Export] private bool _once = true; private bool hasBeenStarted = false; @@ -14,6 +14,6 @@ public partial class FightStarter : Node return; hasBeenStarted = true; - FightManager.Instance.StartFight(enemies, _fightInstance); + //FightManager.Instance.StartFight(enemies, _fightHappening); } } diff --git a/scripts/CSharp/Common/FightOld/FightStateManager.cs b/scripts/CSharp/Common/FightOld/FightStateManager.cs deleted file mode 100644 index 5ea800f..0000000 --- a/scripts/CSharp/Common/FightOld/FightStateManager.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Godot; -namespace Babushka.scripts.CSharp.Common.Fight; - -public partial class FightStateManager : Node -{ - [Signal] - public delegate void ExitingTransitionEventHandler(FightState exitingState); - - [Signal] - public delegate void EnteringTransitionEventHandler(FightState enteringState); - - public enum FightState - { - None, - FightStartAnim, - Input, - InputTargetSelect, - FriendAttackAnim, - Enemy, - EnemyAttackAnim, - PlayerWinAnim, - EnemyWinAnim, - ChangeSideToEnemy, - ChangeSideToFriendly, - Heal, - } - - private FightState _fightStateBacking = FightState.None; - - public FightState CurrentFightState - { - set => Transition(_fightStateBacking, value); - get => _fightStateBacking; - } - - private void Transition(FightState from, FightState to) - { - if(from == to) - return; - - GD.Print($"Transitioning from {from} to {to}"); - ExitTransition(from); - _fightStateBacking = to; - EnterTransition(to); - } - - private void ExitTransition(FightState from) - { - EmitSignalExitingTransition(from); - } - - private void EnterTransition(FightState to) - { - EmitSignalEnteringTransition(to); - switch (to) - { - case FightState.FightStartAnim: - EnterFightStartAnim(); - break; - } - } - private void EnterFightStartAnim() - { - GetTree().CreateTimer(1).Timeout += () => CurrentFightState = FightState.Input; - } - - public void ToStartAnim() - { - CurrentFightState = FightState.FightStartAnim; - } - - public bool IsRunning() - { - return CurrentFightState != FightState.None; - } -} diff --git a/scripts/CSharp/Common/FightOld/FightStateManager.cs.uid b/scripts/CSharp/Common/FightOld/FightStateManager.cs.uid deleted file mode 100644 index 1527d8c..0000000 --- a/scripts/CSharp/Common/FightOld/FightStateManager.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://oe1uypehqvr7 diff --git a/scripts/CSharp/Common/Util/Variant.cs b/scripts/CSharp/Common/Util/Variant.cs new file mode 100644 index 0000000..7ef303b --- /dev/null +++ b/scripts/CSharp/Common/Util/Variant.cs @@ -0,0 +1,63 @@ +using System; +using System.Diagnostics; + +namespace Babushka.scripts.CSharp.Common.Util; + +public class Variant +{ + private Type _type; + private Object _value; + + public Type GetVariantType() + { + return _type; + } + + public T GetValue() + { + if (_type != typeof(T)) + throw new ArgumentOutOfRangeException( + $"The Variant does not store a {typeof(T)}. The current type is {_type}"); + + return (T)_value; + } + + public void SetValue(T value) + { + if (typeof(T1) != typeof(T) && typeof(T2) != typeof(T)) + throw new ArgumentOutOfRangeException( + $"The Variant does not support type {typeof(T)}. Supported types are {typeof(T1)} and {typeof(T2)}"); + + _type = typeof(T); + _value = value!; + } + + public static implicit operator T1(Variant v) + { + return v.GetValue(); + } + + public static implicit operator T2(Variant v) + { + return v.GetValue(); + } + + public static implicit operator Variant(T1 t) + { + return new Variant { _type = typeof(T1), _value = t! }; + } + + public static implicit operator Variant(T2 t) + { + return new Variant { _type = typeof(T2), _value = t! }; + } + + public bool IsType() + { + if (typeof(T1) != typeof(T) && typeof(T2) != typeof(T)) + throw new ArgumentOutOfRangeException( + $"The Variant does not support type {typeof(T)}. Supported types are {typeof(T1)} and {typeof(T2)}"); + + return _type == typeof(T); + } +} \ No newline at end of file diff --git a/shader/swaying_plant.gdshader b/shader/swaying_plant.gdshader index 01c04ce..42a0f76 100644 --- a/shader/swaying_plant.gdshader +++ b/shader/swaying_plant.gdshader @@ -26,7 +26,6 @@ uniform float heightOffset : hint_range(0.0, 1.0); // With the offset value, you can if you want different moves for each asset. Just put a random value (1, 2, 3) in the editor. Don't forget to mark the material as unique if you use this uniform float offset = 0; - float getWind(vec2 vertex, vec2 uv, float time){ float diff = pow(maxStrength - minStrength, 2.0); float strength = clamp(minStrength + diff + sin(time / interval) * diff, minStrength, maxStrength) * strengthScale;