Fight rework premature merge #22

Merged
Jonathan merged 16 commits from feature/fight_rework into develop 2025-11-04 10:25:14 +01:00
38 changed files with 1022 additions and 681 deletions
Showing only changes of commit f27dd199b8 - Show all commits
+1
View File
@@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=53eecf85_002Dd821_002D40e8_002Dac97_002Dfdb734542b84/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Instance fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=0B2502BD29F5EC4798EEFD2950AA7E06/Description/@EntryValue">Godot Signal</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=0B2502BD29F5EC4798EEFD2950AA7E06/Text/@EntryValue">[Signal]
public delegate void $SignalName$EventHandler($END$);</s:String>
+12 -1
View File
@@ -19,4 +19,15 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Ff1d69ec2da76ccf9bc8a75c8e0fdca9a7ba1adf8c8c9d5047e2fa5991c02eca_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceLoader_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F9f4e8eb124d11f8219cb513a19bed22b2120ed29f9d6785ba56e3367b48d581_003FResourceLoader_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceLoader_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F9f4e8eb124d11f8219cb513a19bed22b2120ed29f9d6785ba56e3367b48d581_003FResourceLoader_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fc7102cd0ffb8973777e61b1942c3fffac7e14016a511d055c3adf73ff91748_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fc7102cd0ffb8973777e61b1942c3fffac7e14016a511d055c3adf73ff91748_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F76fabf6f8acf4a0099cae0bcf8b218467f10_003F7e_003F28cee476_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGD_005Fconstants_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F4ef0bac6437b6a9567d44f62ae567d854fa7b8513ef7139ef349b49768bc9df_003FGD_005Fconstants_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Ff1d69ec2da76ccf9bc8a75c8e0fdca9a7ba1adf8c8c9d5047e2fa5991c02eca_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceLoader_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F9f4e8eb124d11f8219cb513a19bed22b2120ed29f9d6785ba56e3367b48d581_003FResourceLoader_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASceneTree_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F8d6960554e939a669841b1ece03d27df4ab42f92bb80be3767eaec8cdaccf84b_003FSceneTree_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fc7102cd0ffb8973777e61b1942c3fffac7e14016a511d055c3adf73ff91748_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=bc5a80e4_002D7ba6_002D4f7d_002Db896_002Dc591eec7ab12/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="Tests" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;NUnit3x::A6EF2269-9E64-40D4-BA0A-33CB234E2503::net9.0::BabushkaTest.Tests&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>
+9
View File
@@ -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"
@@ -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"]
@@ -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="."]
+64
View File
@@ -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")
+1 -1
View File
@@ -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")
@@ -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"]
+136
View File
@@ -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"
+41 -25
View File
@@ -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
+2 -2
View File
@@ -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"]
+1
View File
@@ -105,6 +105,7 @@ _data = {
}
[node name="SceneTransition" type="CanvasLayer" node_paths=PackedStringArray("animationPlayer")]
layer = 100
script = ExtResource("1_e0bkc")
animationPlayer = NodePath("SceneFadeAnimation")
@@ -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;
}
}
@@ -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;
Jonathan marked this conversation as resolved Outdated
Outdated
Review

Diese Klasse managed das Layout der Kampfszene, oder? Das Naming hatte mich etwas verwirrt.

Diese Klasse managed das Layout der Kampfszene, oder? Das Naming hatte mich etwas verwirrt.
[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>();
fighterVisual.Initialize(fighter);
parent.AddChild(fighterVisual);
}
}
@@ -0,0 +1 @@
uid://dwsqst8fhhqlc
@@ -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<FightWorld.Fighter> enteringAllyFighters;
public required List<FightWorld.Fighter> 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<FightState>? transitionFromState;
public event Action<FightState, FightState>? transitionState;
public event Action<FightState>? 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<float>())
{
AdvanceToStateInSeconds(FightState.StateCheck, actionTime);
}
else
{
_ = AdvanceToStateWhenDone(FightState.StateCheck, actionTime);
}
break;
default: break;
}
}
#endregion
#region Game Logic
private FightersEnterStaging StageFightersEnter()
{
// ally
var enteringAllyFighters = new List<FightWorld.Fighter>();
//TODO
// enemy
const int totalEnemySpace = 3;
var enemySpaceLeft = totalEnemySpace - HappeningData.enemyGroup.GetEnteredAmount();
var enterEnemyFighters = new List<FightWorld.Fighter>();
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<float, Func<bool>> 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<bool> isDone)
{
while (!isDone())
{
await FightWorld.Instance.ToSignal(FightWorld.Instance.GetTree(), SceneTree.SignalName.ProcessFrame);
}
ChangeState(nextState);
}
#endregion
}
@@ -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");
}
}
@@ -0,0 +1 @@
uid://cnhpnn8o0gybd
@@ -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()
@@ -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();
}
+45
View File
@@ -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());
}
}
@@ -0,0 +1 @@
uid://beuhpltb84pf
+37 -13
View File
@@ -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<Enemy> enemies;
public required List<Fighter> 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<FighterAction> 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;
@@ -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<bool> 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
/// <summary>
/// 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.
/// </summary>
public virtual void ExecuteAction()
{
}
/// <summary>
/// Returns a way to determine, when an action animation is done
/// </summary>
/// <returns>
/// A variant that can be <c>float</c> or <c>Func&lt;bool&gt;</c>.<br/>
/// When the return type is <c>float</c>, the animation will take the return value amount of seconds.<br/>
/// When the return type is <c>Func&lt;bool&gt;</c>, the animation will be done, when the function returns true.
/// </returns>
public abstract Variant<float, Func<bool>> GetAnimationEnd();
/// <summary>
/// Animates the action.
/// </summary>
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<float, Func<bool>> GetAnimationEnd()
{
return 0f;
}
public override FighterActionDetail? NeededDetail()
{
return null;
}
}
}
@@ -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;
}
}
@@ -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
//public override void _Ready()
//{
// UpdateHealthVisual();
// ResetActions();
//}
public void Initialize(FightWorld.Fighter fighter)
{
get => _health;
set
{
_health = value;
if (_health <= 0)
{
_health = 0;
Die();
}
if (_health > maxHealth)
{
_health = maxHealth;
}
}
}
private void Die()
{
_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();
@@ -0,0 +1,7 @@
using System;
namespace Babushka.scripts.CSharp.Common.Fight;
public class NoFightHappeningException() : Exception("No fight happening right now")
{
}
@@ -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;
}
@@ -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<Fighter> _friendlyFighters = new();
private List<Fighter> _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());
}
/**
* <returns>
* <c>true</c> if the state was changed
* </returns>
*/
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;
}
/**
* <returns>
* <c>true</c> if the state was changed
* </returns>
*/
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>();
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;
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -1 +0,0 @@
uid://oe1uypehqvr7
+63
View File
@@ -0,0 +1,63 @@
using System;
using System.Diagnostics;
namespace Babushka.scripts.CSharp.Common.Util;
public class Variant<T1, T2>
{
private Type _type;
private Object _value;
public Type GetVariantType()
{
return _type;
}
public T GetValue<T>()
{
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>(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<T1, T2> v)
{
return v.GetValue<T1>();
}
public static implicit operator T2(Variant<T1, T2> v)
{
return v.GetValue<T2>();
}
public static implicit operator Variant<T1, T2>(T1 t)
{
return new Variant<T1, T2> { _type = typeof(T1), _value = t! };
}
public static implicit operator Variant<T1, T2>(T2 t)
{
return new Variant<T1, T2> { _type = typeof(T2), _value = t! };
}
public bool IsType<T>()
{
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);
}
}
-1
View File
@@ -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;