Made fight fightable
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<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/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArea3D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F8a54226fa2e1c9371a8091f24cfd744aef11fe6869527dc23b9b837623a29b9_003FArea3D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArray_00601_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe37dc1faf08a4d5ea030ad59bdf77522523400_003Fa3_003Fe272a3a7_003FArray_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAudioStreamPlayer2D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F848324b1c23114c3f5e8bbb5a42c4ade394c59a7a7a133a66b76581ca571_003FAudioStreamPlayer2D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABabushka_002Escripts_002ECSharp_002ECommon_002EFarming_002EVesnaBehaviour2D_005FScriptMethods_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FLocal_003FTemp_003FSourceGeneratedDocuments_003F9509A9D00FD8A232B5E86A84_003FGodot_002ESourceGenerators_003FGodot_002ESourceGenerators_002EScriptMethodsGenerator_003FBabushka_002Escripts_002ECSharp_002ECommon_002EFarming_002EVesnaBehaviour2D_005FScriptMethods_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABabushka_002Escripts_002ECSharp_002ECommon_002EFarming_002EVesnaBehaviour2D_005FScriptProperties_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FLocal_003FTemp_003FSourceGeneratedDocuments_003F9509A9D00FD8A232B5E86A84_003FGodot_002ESourceGenerators_003FGodot_002ESourceGenerators_002EScriptPropertiesGenerator_003FBabushka_002Escripts_002ECSharp_002ECommon_002EFarming_002EVesnaBehaviour2D_005FScriptProperties_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
@@ -7,15 +8,19 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABabushka_002Escripts_002ECSharp_002ECommon_002EFarming_002EVesnaBehaviour2D_005FScriptProperties_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F4298b0f293f987511fc1b7956ee691fd778f8378_003FBabushka_002Escripts_002ECSharp_002ECommon_002EFarming_002EVesnaBehaviour2D_005FScriptProperties_002Egenerated_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABabushka_002Escripts_002ECSharp_002ECommon_002EQuest_002EQuestListItemUi_005FScriptMethods_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F48fad7e7f3c9e292b3fdbddf9d363f0d1752aa_003FBabushka_002Escripts_002ECSharp_002ECommon_002EQuest_002EQuestListItemUi_005FScriptMethods_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABabushka_002Escripts_002ECSharp_002ECommon_002EQuest_002EQuestManager_005FScriptSignals_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FLocal_003FTemp_003FSourceGeneratedDocuments_003F9509A9D00FD8A232B5E86A84_003FGodot_002ESourceGenerators_003FGodot_002ESourceGenerators_002EScriptSignalsGenerator_003FBabushka_002Escripts_002ECSharp_002ECommon_002EQuest_002EQuestManager_005FScriptSignals_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACanvasItem_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fef7b819b226fab796d1dfe66d415dd7510bcac87675020ddb8f03a828e763_003FCanvasItem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACastHelpers_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F3c92637ae2e83da0a63791071c41eae291d594156062866d8621b7ed7245c_003FCastHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACastHelpers_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd111abf504bf42b5968a609b168fd093b2e200_003Fbb_003F1c116fcd_003FCastHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACharacterBody2D_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fbba0bbd7a98ee58286e9484fbe86e01afff6232283f6efd3556eb7116453_003FCharacterBody2D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACount_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Ffe5a7cee5a1771b89077bd73292de84439b4f816799e2ad6c2615c6ff5bd748e_003FCount_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fjonathan_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe37dc1faf08a4d5ea030ad59bdf77522523400_003Fd4_003Fbd338aeb_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<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_003ANullable_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F5acc345db3c207bc9d886a36ff14867ef8d65557432172c2a42f19aeac04d1b_003FNullable_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_003AShape2D_002Ecs_002Fl_003AC_0021_003FUsers_003FJonathan_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F3671dbbd9b17cdf2bf9075b468b6bd7e3ab13fc3be7a116484085d3b6cc9fe_003FShape2D_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"><SessionState ContinuousTestingMode="0" IsActive="True" Name="Tests" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||
<TestAncestor>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://0vm3jb1hnkkb"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://7jsxokx67gpq" path="res://prefabs/fight/fighterVisuals/vesna_fighter_visual.tscn" id="1_80xdf"]
|
||||
[ext_resource type="Texture2D" uid="uid://ccrnmx6bd842k" path="res://art/characters/farm fäulnis blobs.png" id="2_ba6tr"]
|
||||
|
||||
[sub_resource type="AtlasTexture" id="AtlasTexture_ane0o"]
|
||||
atlas = ExtResource("2_ba6tr")
|
||||
region = Rect2(1133.19, 93.65, 460.526, 347.391)
|
||||
|
||||
[node name="BlobFighterVisual" instance=ExtResource("1_80xdf")]
|
||||
|
||||
[node name="Sprite2D" parent="Visuals" index="0"]
|
||||
position = Vector2(23, -96)
|
||||
scale = Vector2(0.547474, 0.547474)
|
||||
texture = SubResource("AtlasTexture_ane0o")
|
||||
|
||||
[node name="ChacacterSizeIndicator" parent="Visuals" index="1"]
|
||||
visible = true
|
||||
@@ -0,0 +1,58 @@
|
||||
[gd_scene load_steps=8 format=3 uid="uid://7jsxokx67gpq"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://by88f32fou7lh" path="res://scripts/CSharp/Common/Fight/FighterVisual.cs" id="1_hai27"]
|
||||
[ext_resource type="Texture2D" uid="uid://f7htcxiwvuup" path="res://art/animation/vesna/Side/S01-Idle/0001.png" id="2_6l7g5"]
|
||||
[ext_resource type="Script" uid="uid://boprnfciqgixf" path="res://scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs" id="3_wil2y"]
|
||||
[ext_resource type="Texture2D" uid="uid://qlfwuakhe57t" path="res://art/ui/UI/attack_select_wheel.png" id="4_8ldlc"]
|
||||
|
||||
[sub_resource type="AtlasTexture" id="AtlasTexture_wil2y"]
|
||||
atlas = ExtResource("2_6l7g5")
|
||||
region = Rect2(60.818, 51.0213, 660.226, 945.537)
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_6l7g5"]
|
||||
size = Vector2(250, 401)
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_6l7g5"]
|
||||
radius = 173.0
|
||||
height = 588.0
|
||||
|
||||
[node name="VesnaFighterVisual" type="Node2D" node_paths=PackedStringArray("_visualParent", "_targetSelectionParent")]
|
||||
script = ExtResource("1_hai27")
|
||||
_visualParent = NodePath("Visuals")
|
||||
_targetSelectionParent = NodePath("TargetSelection")
|
||||
|
||||
[node name="Visuals" type="Node2D" parent="."]
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="Visuals"]
|
||||
position = Vector2(-31, -199)
|
||||
scale = Vector2(0.451719, 0.451719)
|
||||
texture = SubResource("AtlasTexture_wil2y")
|
||||
|
||||
[node name="ChacacterSizeIndicator" type="CollisionShape2D" parent="Visuals"]
|
||||
editor_description = "This is a reference to the space, a normal sized humanoid character should occupy"
|
||||
visible = false
|
||||
position = Vector2(0, -200.5)
|
||||
shape = SubResource("RectangleShape2D_6l7g5")
|
||||
|
||||
[node name="TargetSelection" type="Node2D" parent="."]
|
||||
process_mode = 4
|
||||
visible = false
|
||||
|
||||
[node name="Click" type="Area2D" parent="TargetSelection"]
|
||||
script = ExtResource("3_wil2y")
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="TargetSelection/Click"]
|
||||
position = Vector2(-3, -195)
|
||||
shape = SubResource("CapsuleShape2D_6l7g5")
|
||||
|
||||
[node name="HoverIndicator" type="Node2D" parent="TargetSelection"]
|
||||
visible = false
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="TargetSelection/HoverIndicator"]
|
||||
position = Vector2(-3, -227)
|
||||
scale = Vector2(1.65625, 1.65625)
|
||||
texture = ExtResource("4_8ldlc")
|
||||
|
||||
[connection signal="TargetSelected" from="TargetSelection/Click" to="." method="ClickedTarget"]
|
||||
[connection signal="mouse_entered" from="TargetSelection/Click" to="TargetSelection/HoverIndicator" method="show"]
|
||||
[connection signal="mouse_exited" from="TargetSelection/Click" to="TargetSelection/HoverIndicator" method="hide"]
|
||||
@@ -0,0 +1,41 @@
|
||||
[gd_scene load_steps=8 format=3 uid="uid://qfdiudt3vpai"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://lequnojtar76" path="res://scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs" id="1_t3mrx"]
|
||||
[ext_resource type="Texture2D" uid="uid://ccrnmx6bd842k" path="res://art/characters/farm fäulnis blobs.png" id="2_6ftwg"]
|
||||
[ext_resource type="Texture2D" uid="uid://bexymddkb6l0o" path="res://art/characters/Mavka/mavkha.png" id="3_xi5g8"]
|
||||
[ext_resource type="PackedScene" uid="uid://cqc72e4hq6bcd" path="res://prefabs/interactions/interaction_area_2d.tscn" id="4_xi5g8"]
|
||||
|
||||
[sub_resource type="AtlasTexture" id="AtlasTexture_c8fs8"]
|
||||
atlas = ExtResource("2_6ftwg")
|
||||
region = Rect2(1747.17, 156.157, 311.249, 280.596)
|
||||
|
||||
[sub_resource type="AtlasTexture" id="AtlasTexture_kbgcx"]
|
||||
atlas = ExtResource("3_xi5g8")
|
||||
region = Rect2(774.378, 151.512, 1097.48, 1412.67)
|
||||
|
||||
[sub_resource type="AtlasTexture" id="AtlasTexture_6fvcb"]
|
||||
atlas = ExtResource("2_6ftwg")
|
||||
region = Rect2(1149.47, 92.492, 445.652, 353.692)
|
||||
|
||||
[node name="RoamingEnemyGroup" type="Node2D"]
|
||||
script = ExtResource("1_t3mrx")
|
||||
|
||||
[node name="Visuals" type="Node2D" parent="."]
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="Visuals"]
|
||||
position = Vector2(99, -222)
|
||||
texture = SubResource("AtlasTexture_c8fs8")
|
||||
|
||||
[node name="Sprite2D3" type="Sprite2D" parent="Visuals"]
|
||||
position = Vector2(-108, -337)
|
||||
scale = Vector2(0.43, 0.43)
|
||||
texture = SubResource("AtlasTexture_kbgcx")
|
||||
|
||||
[node name="Sprite2D2" type="Sprite2D" parent="Visuals"]
|
||||
position = Vector2(-41, -109)
|
||||
texture = SubResource("AtlasTexture_6fvcb")
|
||||
|
||||
[node name="InteractionArea" parent="." node_paths=PackedStringArray("_spriteToOutline") instance=ExtResource("4_xi5g8")]
|
||||
_spriteToOutline = [NodePath("../Visuals/Sprite2D"), NodePath("../Visuals/Sprite2D3"), NodePath("../Visuals/Sprite2D2")]
|
||||
|
||||
[connection signal="Interacted" from="InteractionArea" to="." method="StartFight"]
|
||||
@@ -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/fight/fighters/vesna_fighter.tscn" id="2_ak1vo"]
|
||||
[ext_resource type="PackedScene" uid="uid://cpanatqdjjpa3" path="res://prefabs/fightOld/fighters/vesna_fighter.tscn" id="2_ak1vo"]
|
||||
|
||||
[node name="FightManagerAutoload" type="Node"]
|
||||
script = ExtResource("1_8p7ev")
|
||||
|
||||
@@ -28,7 +28,6 @@ buses/default_bus_layout="uid://b6dwkmkyb0axk"
|
||||
SceneTransition="*res://scenes/SceneTransition.tscn"
|
||||
Dialogic="*res://addons/dialogic/Core/DialogicGameHandler.gd"
|
||||
InventoryManager="*res://scripts/CSharp/Common/Inventory/InventoryManager.cs"
|
||||
FightManagerAutoload="*res://prefabs/fightOld/fight_manager_autoload.tscn"
|
||||
InputService="*res://scripts/CSharp/Common/Services/InputService.cs"
|
||||
QuestManager="*res://prefabs/quests/quest_manager_autoload.tscn"
|
||||
Signal_Debugger="*res://addons/SignalVisualizer/Debugger/SignalDebugger.gd"
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
[node name="BabushkaSceneBootstrap" type="Node2D"]
|
||||
|
||||
[node name="BabushkaSceneStartMenu" parent="." instance=ExtResource("1_15ton")]
|
||||
_sceneNamesToLoad = PackedStringArray("res://scenes/Babushka_scene_fight_world_room.tscn")
|
||||
|
||||
[node name="SceneParent" type="Node" parent="."]
|
||||
|
||||
@@ -1,19 +1,33 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://cjshlwk8ajpnp"]
|
||||
[gd_scene load_steps=10 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="Script" uid="uid://c76mhhqyk4lgh" path="res://scripts/CSharp/Common/Fight/FightHappening.cs" id="1_gsk03"]
|
||||
[ext_resource type="Script" uid="uid://dwsqst8fhhqlc" path="res://scripts/CSharp/Common/Fight/AllFightersVisual.cs" id="2_lu4y4"]
|
||||
[ext_resource type="PackedScene" uid="uid://bcld43daavmrn" path="res://prefabs/fight/fight_scene_switcher.tscn" id="2_phrlx"]
|
||||
[ext_resource type="PackedScene" uid="uid://7jsxokx67gpq" path="res://prefabs/fight/fighterVisuals/vesna_fighter_visual.tscn" id="4_qo0gi"]
|
||||
[ext_resource type="PackedScene" uid="uid://0vm3jb1hnkkb" path="res://prefabs/fight/fighterVisuals/blob_fighter_visual.tscn" id="4_vp8s0"]
|
||||
[ext_resource type="Script" uid="uid://buiwuf7pjfq8" path="res://scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs" id="4_ydj1i"]
|
||||
[ext_resource type="Script" uid="uid://byf2ywov34g0x" path="res://scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs" id="8_bkwsr"]
|
||||
[ext_resource type="Script" uid="uid://d2ugtb3dalrg3" path="res://scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs" id="8_tv7cl"]
|
||||
|
||||
[node name="BabushkaSceneFightHappening" type="Node2D"]
|
||||
|
||||
[node name="FightHappening" type="Node" parent="."]
|
||||
script = ExtResource("1_gsk03")
|
||||
|
||||
[node name="Camera2D" type="Camera2D" parent="."]
|
||||
|
||||
[node name="FightSetup" type="Node2D" parent="."]
|
||||
script = ExtResource("1_fiutj")
|
||||
|
||||
[node name="FightVisuals" type="Node2D" parent="."]
|
||||
[node name="FightVisuals" type="Node2D" parent="." node_paths=PackedStringArray("_allyFighters", "_enemyFighters")]
|
||||
position = Vector2(0, 259)
|
||||
script = ExtResource("2_lu4y4")
|
||||
_allyFighters = NodePath("AllyFighters")
|
||||
_enemyFighters = NodePath("EnemyFighters")
|
||||
_blobFighterVisual = ExtResource("4_vp8s0")
|
||||
_vesnaFighterVisual = ExtResource("4_qo0gi")
|
||||
_positionDistanceFromCenter = PackedFloat32Array(200, 400, 600)
|
||||
|
||||
[node name="AllyFighters" type="Node2D" parent="FightVisuals"]
|
||||
|
||||
@@ -23,7 +37,13 @@ script = ExtResource("2_lu4y4")
|
||||
|
||||
[node name="FightSceneSwitcher" parent="." instance=ExtResource("2_phrlx")]
|
||||
|
||||
[node name="ActionSelect" type="CanvasLayer" parent="."]
|
||||
[node name="ActionSelect" type="CanvasLayer" parent="." node_paths=PackedStringArray("_attackActionButton", "_summonActionButton", "_talkActionButton", "_fleeActionButton")]
|
||||
visible = false
|
||||
script = ExtResource("8_bkwsr")
|
||||
_attackActionButton = NodePath("BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/AttackButton")
|
||||
_summonActionButton = NodePath("BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2/Summon Button")
|
||||
_talkActionButton = NodePath("BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3/Talk Button")
|
||||
_fleeActionButton = NodePath("BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer4/Flee Button")
|
||||
|
||||
[node name="BottomPanel" type="Control" parent="ActionSelect"]
|
||||
custom_minimum_size = Vector2(0, 200)
|
||||
@@ -134,3 +154,29 @@ 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"
|
||||
|
||||
[node name="StateReactionInputActionSelect" type="Node" parent="ActionSelect"]
|
||||
script = ExtResource("4_ydj1i")
|
||||
_fightState = 6
|
||||
|
||||
[node name="StateMachineDebugger" type="Node" parent="." node_paths=PackedStringArray("_label")]
|
||||
script = ExtResource("8_tv7cl")
|
||||
_label = NodePath("Label")
|
||||
|
||||
[node name="Label" type="Label" parent="StateMachineDebugger"]
|
||||
offset_left = -973.0
|
||||
offset_top = -500.0
|
||||
offset_right = -523.0
|
||||
offset_bottom = 444.0
|
||||
text = "Hello world"
|
||||
|
||||
[connection signal="SignalTransitionState" from="FightHappening" to="FightVisuals" method="FightHappeningStateChange"]
|
||||
[connection signal="SignalTransitionState" from="FightHappening" to="ActionSelect/StateReactionInputActionSelect" method="FightHappeningStateTransitioned"]
|
||||
[connection signal="SignalTransitionState" from="FightHappening" to="StateMachineDebugger" method="StateChange"]
|
||||
[connection signal="pressed" from="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/AttackButton" to="ActionSelect" method="SelectAction" binds= [1]]
|
||||
[connection signal="pressed" from="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2/Summon Button" to="ActionSelect" method="SelectAction" binds= [2]]
|
||||
[connection signal="pressed" from="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3/Talk Button" to="ActionSelect" method="SelectAction" binds= [3]]
|
||||
[connection signal="pressed" from="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer4/Flee Button" to="ActionSelect" method="SelectAction" binds= [4]]
|
||||
[connection signal="OnStateEntered" from="ActionSelect/StateReactionInputActionSelect" to="ActionSelect" method="show"]
|
||||
[connection signal="OnStateEntered" from="ActionSelect/StateReactionInputActionSelect" to="ActionSelect" method="StateEntered"]
|
||||
[connection signal="OnStateExited" from="ActionSelect/StateReactionInputActionSelect" to="ActionSelect" method="hide"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=52 format=3 uid="uid://cacnapfv7w567"]
|
||||
[gd_scene load_steps=53 format=3 uid="uid://cacnapfv7w567"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bqomwxclsbhd3" path="res://scripts/CSharp/Common/Camera/CameraController.cs" id="1_pi6ua"]
|
||||
[ext_resource type="Texture2D" uid="uid://8sr11ex30n0m" path="res://art/mockups/Kenney_Backgrounds/Samples/uncolored_hills.png" id="2_hqa4k"]
|
||||
@@ -38,8 +38,9 @@
|
||||
[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" path="res://scripts/CSharp/Common/Fight/FightSceneSetup.cs" id="37_hqa4k"]
|
||||
[ext_resource type="Script" uid="uid://dbu8afaiohpdh" path="res://scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs" id="40_cvg1r"]
|
||||
[ext_resource type="PackedScene" uid="uid://bcld43daavmrn" path="res://prefabs/fight/fight_scene_switcher.tscn" id="40_elhbh"]
|
||||
[ext_resource type="PackedScene" uid="uid://qfdiudt3vpai" path="res://prefabs/fight/roaming_enemy_group.tscn" id="41_cvg1r"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_ruj2u"]
|
||||
shader = ExtResource("16_0fard")
|
||||
@@ -1998,7 +1999,6 @@ y_sort_enabled = true
|
||||
|
||||
[node name="Visuals" type="Node2D" parent="YSorted/Paths/Path0/PathVariants/Closed"]
|
||||
y_sort_enabled = true
|
||||
scale = Vector2(1, 1)
|
||||
|
||||
[node name="bush14" type="Sprite2D" parent="YSorted/Paths/Path0/PathVariants/Closed/Visuals"]
|
||||
y_sort_enabled = true
|
||||
@@ -2022,7 +2022,6 @@ y_sort_enabled = true
|
||||
|
||||
[node name="Visuals" type="Node2D" parent="YSorted/Paths/Path0/PathVariants/OpenToFightRoom"]
|
||||
y_sort_enabled = true
|
||||
scale = Vector2(1, 1)
|
||||
|
||||
[node name="bush14" type="Sprite2D" parent="YSorted/Paths/Path0/PathVariants/OpenToFightRoom/Visuals"]
|
||||
z_index = 100
|
||||
@@ -2074,7 +2073,6 @@ y_sort_enabled = true
|
||||
|
||||
[node name="Visuals" type="Node2D" parent="YSorted/Paths/Path1/PathVariants/Closed"]
|
||||
y_sort_enabled = true
|
||||
scale = Vector2(1, 1)
|
||||
|
||||
[node name="bush14" type="Sprite2D" parent="YSorted/Paths/Path1/PathVariants/Closed/Visuals"]
|
||||
y_sort_enabled = true
|
||||
@@ -2112,7 +2110,6 @@ y_sort_enabled = true
|
||||
|
||||
[node name="Visuals" type="Node2D" parent="YSorted/Paths/Path1/PathVariants/OpenToFightRoom"]
|
||||
y_sort_enabled = true
|
||||
scale = Vector2(1, 1)
|
||||
|
||||
[node name="bush14" type="Sprite2D" parent="YSorted/Paths/Path1/PathVariants/OpenToFightRoom/Visuals"]
|
||||
z_index = 100
|
||||
@@ -2136,20 +2133,28 @@ pathIndex = 1
|
||||
position = Vector2(-335, 18)
|
||||
shape = SubResource("RectangleShape2D_ir2xa")
|
||||
|
||||
[node name="FightSceneSetup" type="Node" parent="." node_paths=PackedStringArray("debugLabel")]
|
||||
unique_name_in_owner = true
|
||||
script = ExtResource("37_hqa4k")
|
||||
debugLabel = NodePath("../Debug Label")
|
||||
[node name="EnemyGroupSpawns" type="Node2D" parent="YSorted"]
|
||||
position = Vector2(11116, 2546)
|
||||
|
||||
[node name="Spawn1" type="Node2D" parent="YSorted/EnemyGroupSpawns"]
|
||||
position = Vector2(-1008, -358)
|
||||
|
||||
[node name="Spawn2" type="Node2D" parent="YSorted/EnemyGroupSpawns"]
|
||||
position = Vector2(1679, -434)
|
||||
|
||||
[node name="Spawn3" type="Node2D" parent="YSorted/EnemyGroupSpawns"]
|
||||
position = Vector2(1560, 422)
|
||||
|
||||
[node name="Spawn4" type="Node2D" parent="YSorted/EnemyGroupSpawns"]
|
||||
position = Vector2(-1127, 671)
|
||||
|
||||
[node name="FightSceneSwitcher" parent="." instance=ExtResource("40_elhbh")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="Debug Label" type="Label" parent="."]
|
||||
offset_left = 10485.0
|
||||
offset_top = 1606.0
|
||||
offset_right = 12476.0
|
||||
offset_bottom = 3583.0
|
||||
theme_override_font_sizes/font_size = 80
|
||||
text = "hello world"
|
||||
[node name="FightSceneSetup" type="Node" parent="." node_paths=PackedStringArray("_enemyGroupSpawns", "_fightSceneSwitcher")]
|
||||
script = ExtResource("40_cvg1r")
|
||||
_enemyGroupSpawns = [NodePath("../YSorted/EnemyGroupSpawns/Spawn1"), NodePath("../YSorted/EnemyGroupSpawns/Spawn2"), NodePath("../YSorted/EnemyGroupSpawns/Spawn3"), NodePath("../YSorted/EnemyGroupSpawns/Spawn4")]
|
||||
_roamingEnemyGroupPrefab = ExtResource("41_cvg1r")
|
||||
_fightSceneSwitcher = NodePath("../FightSceneSwitcher")
|
||||
|
||||
[editable path="YSorted/Vesna"]
|
||||
|
||||
@@ -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/fight/fighters/enemy_blob_fighter.tscn" id="27_hfhye"]
|
||||
[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://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/fight/fighters/enemy_mavkha_fighter.tscn" id="29_hfhye"]
|
||||
[ext_resource type="PackedScene" uid="uid://cr66tpdr5rma5" path="res://prefabs/fightOld/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,4 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Babushka.scripts.CSharp.Common.Util;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.CharacterControls;
|
||||
@@ -10,37 +12,37 @@ public partial class InteractionArea2D : Node2D
|
||||
[Export] private bool _active = true;
|
||||
[Export] private bool _useOutline = true;
|
||||
[Export] private ShaderMaterial _outlineMaterial;
|
||||
[Export] private bool _useSprite = true;
|
||||
[Export] private CanvasItem _spriteToOutline;
|
||||
//[Export] private bool _useSprite = true;
|
||||
[Export(PropertyHint.ArrayType)] private CanvasItem[] _spriteToOutline = [];
|
||||
[Export] private bool _showLabel = true;
|
||||
[Export] private int _id = -1; // TODO: remove
|
||||
|
||||
private Material _backupMaterial;
|
||||
private Material[] _backupMaterial;
|
||||
|
||||
[Signal] public delegate void InteractedToolEventHandler(int id); // TODO: remove
|
||||
|
||||
[Signal] public delegate void InteractedEventHandler();
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => _active;
|
||||
set => _active = value;
|
||||
set => _active = value;
|
||||
}
|
||||
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
|
||||
if (_useSprite && _useOutline)
|
||||
if (_useOutline)
|
||||
{
|
||||
try
|
||||
{
|
||||
_backupMaterial = _spriteToOutline.Material;
|
||||
_backupMaterial = _spriteToOutline.Select(s => s.Material).ToArray();
|
||||
}
|
||||
catch(Exception exception)
|
||||
catch (Exception exception)
|
||||
{
|
||||
GD.PrintErr($"No sprite to outline found on: {GetParent().Name}" + exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void OnPlayerEntered(Node2D player)
|
||||
@@ -48,13 +50,13 @@ public partial class InteractionArea2D : Node2D
|
||||
if (!_active)
|
||||
return;
|
||||
|
||||
if(_showLabel)
|
||||
if (_showLabel)
|
||||
_label.Show();
|
||||
|
||||
if (!_useSprite || !_useOutline)
|
||||
if (!_useOutline)
|
||||
return;
|
||||
|
||||
_spriteToOutline.Material = _outlineMaterial;
|
||||
_spriteToOutline.ForEach(s => s.Material = _outlineMaterial);
|
||||
}
|
||||
|
||||
public void OnPlayerExited(Node2D player)
|
||||
@@ -64,10 +66,14 @@ public partial class InteractionArea2D : Node2D
|
||||
|
||||
_label.Hide();
|
||||
|
||||
if (!_useSprite || !_useOutline)
|
||||
if (!_useOutline)
|
||||
return;
|
||||
|
||||
_spriteToOutline.Material = _backupMaterial;
|
||||
//_spriteToOutline.Material = _backupMaterial;
|
||||
for (var i = 0; i < _spriteToOutline.Length; i++)
|
||||
{
|
||||
_spriteToOutline[i].Material = _backupMaterial[i];
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
@@ -81,8 +87,13 @@ public partial class InteractionArea2D : Node2D
|
||||
{
|
||||
_label.Hide();
|
||||
|
||||
if (_useSprite && _useOutline)
|
||||
_spriteToOutline.Material = _backupMaterial;
|
||||
if (_useOutline)
|
||||
{
|
||||
for (var i = 0; i < _spriteToOutline.Length; i++)
|
||||
{
|
||||
_spriteToOutline[i].Material = _backupMaterial[i];
|
||||
}
|
||||
}
|
||||
|
||||
EmitSignal(SignalName.InteractedTool, _id);
|
||||
EmitSignal(SignalName.Interacted);
|
||||
@@ -93,7 +104,7 @@ public partial class InteractionArea2D : Node2D
|
||||
public void SetSpriteActiveState(bool success, int id) // TODO: remove
|
||||
{
|
||||
GD.PrintErr("SetSpriteActiveState is being called.");
|
||||
if(!_active)
|
||||
if (!_active)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight.ActionDetails;
|
||||
|
||||
public class TargetSelectActionDetail : FighterAction.FighterActionDetail
|
||||
{
|
||||
public enum VisualRange
|
||||
{
|
||||
Single
|
||||
}
|
||||
|
||||
// settings
|
||||
public required bool selectEnemy;
|
||||
public required bool selectAlly;
|
||||
public VisualRange visualRange = VisualRange.Single;
|
||||
|
||||
// result
|
||||
private FightWorld.Fighter? target;
|
||||
|
||||
public override bool DetailComplete()
|
||||
{
|
||||
return target != null;
|
||||
}
|
||||
|
||||
public void ResetResult()
|
||||
{
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void SetTarget(FightWorld.Fighter fighter)
|
||||
{
|
||||
target = fighter;
|
||||
}
|
||||
|
||||
public FightWorld.Fighter GetTarget()
|
||||
{
|
||||
return target ?? throw new InvalidOperationException("No target selected");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://e8c8ym0fyprn
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using Babushka.scripts.CSharp.Common.Fight.ActionDetails;
|
||||
using Babushka.scripts.CSharp.Common.Util;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight.Actions;
|
||||
|
||||
public class AllyAttackAction : FighterAction
|
||||
{
|
||||
// details
|
||||
public TargetSelectActionDetail targetSelect = new()
|
||||
{
|
||||
selectEnemy = true,
|
||||
selectAlly = false
|
||||
};
|
||||
|
||||
public override Variant<float, Func<bool>> GetAnimationEnd()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override bool NextDetail()
|
||||
{
|
||||
return !targetSelect.DetailComplete();
|
||||
}
|
||||
|
||||
public override FighterActionDetail CurrentDetail()
|
||||
{
|
||||
return targetSelect;
|
||||
}
|
||||
|
||||
public override AllyActionButton BindToActionButton()
|
||||
{
|
||||
return AllyActionButton.Attack;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
targetSelect.ResetResult();
|
||||
}
|
||||
|
||||
public override void ExecuteAction()
|
||||
{
|
||||
targetSelect.GetTarget().AddHealth(-5);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c8c4t80bqsja5
|
||||
@@ -1,34 +1,125 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Babushka.scripts.CSharp.Common.Fight;
|
||||
using Babushka.scripts.CSharp.Common.Fight.ActionDetails;
|
||||
using Babushka.scripts.CSharp.Common.Util;
|
||||
|
||||
public partial class AllFightersVisual : Node
|
||||
{
|
||||
[Export] private Node2D _allyFighters;
|
||||
[Export] private Node2D _enemyFighters;
|
||||
[ExportCategory("References")] [Export]
|
||||
private Node2D _allyFighters = null!;
|
||||
|
||||
[Export] private PackedScene _blobFighterVisual;
|
||||
[Export] private PackedScene _bigBlobFighterVisual;
|
||||
[Export] private PackedScene _mavkaFighterVisual;
|
||||
[Export] private PackedScene _yourMomFighterVisual;
|
||||
[Export] private PackedScene _vesnaFighterVisual;
|
||||
[Export] private Node2D _enemyFighters = null!;
|
||||
|
||||
public void EnterFighter(FightWorld.Fighter fighter, bool isEnemy)
|
||||
[ExportCategory("Fighter Visual Scenes")]
|
||||
[Export] private PackedScene _blobFighterVisual = null!;
|
||||
[Export] private PackedScene _bigBlobFighterVisual = null!;
|
||||
[Export] private PackedScene _mavkaFighterVisual = null!;
|
||||
[Export] private PackedScene _yourMomFighterVisual = null!;
|
||||
[Export] private PackedScene _vesnaFighterVisual = null!;
|
||||
|
||||
[ExportCategory("Settings")]
|
||||
[Export(PropertyHint.ArrayType)] private float[] _positionDistanceFromCenter = [10, 20, 30];
|
||||
|
||||
private Dictionary<FightWorld.Fighter, FighterVisual> _fighterVisuals = new();
|
||||
|
||||
#region Shortcuts
|
||||
|
||||
private FightWorld.FightHappeningData HappeningData =>
|
||||
FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region State Reactions
|
||||
|
||||
public void FightHappeningStateChange(FightHappening.FightState from, FightHappening.FightState to)
|
||||
{
|
||||
var parent = isEnemy ? _enemyFighters : _allyFighters;
|
||||
|
||||
var packedScene = fighter.type switch
|
||||
if (to == FightHappening.FightState.FightersEnterAnim)
|
||||
{
|
||||
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()
|
||||
};
|
||||
EnterFighter();
|
||||
}
|
||||
|
||||
var fighterVisual = packedScene.Instantiate<FighterVisual>();
|
||||
fighterVisual.Initialize(fighter);
|
||||
parent.AddChild(fighterVisual);
|
||||
if (to == FightHappening.FightState.InputActionDetail)
|
||||
{
|
||||
if (HappeningData.actionStaging!.CurrentDetail() is TargetSelectActionDetail targetDetail)
|
||||
{
|
||||
ShowTargetSelect(targetDetail);
|
||||
}
|
||||
}
|
||||
|
||||
if (from == FightHappening.FightState.InputActionDetail)
|
||||
{
|
||||
HideTargetSelect();
|
||||
}
|
||||
}
|
||||
|
||||
public void EnterFighter()
|
||||
{
|
||||
if (HappeningData.fightersEnterStaging == null)
|
||||
return;
|
||||
|
||||
if (!HappeningData.fightersEnterStaging.HasAnyToExecute())
|
||||
return;
|
||||
|
||||
|
||||
foreach (var fighter in HappeningData.fightersEnterStaging.enteringEnemyFighters)
|
||||
{
|
||||
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);
|
||||
_enemyFighters.AddChild(fighterVisual);
|
||||
fighterVisual.Position = new Vector2(_positionDistanceFromCenter[_enemyFighters.GetChildCount() - 1], 0);
|
||||
_fighterVisuals.Add(fighter, fighterVisual);
|
||||
}
|
||||
|
||||
foreach (var fighter in HappeningData.fightersEnterStaging.enteringAllyFighters)
|
||||
{
|
||||
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);
|
||||
_allyFighters.AddChild(fighterVisual);
|
||||
fighterVisual.Position = new Vector2(-_positionDistanceFromCenter[_allyFighters.GetChildCount() - 1], 0);
|
||||
_fighterVisuals.Add(fighter, fighterVisual);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowTargetSelect(TargetSelectActionDetail targetDetail)
|
||||
{
|
||||
if (targetDetail.selectEnemy)
|
||||
_fighterVisuals.Where(kv => kv.Key.isEnemy).ForEach(kv => kv.Value.SetTargetSelectionActive(true));
|
||||
|
||||
if (targetDetail.selectAlly)
|
||||
_fighterVisuals.Where(kv => !kv.Key.isEnemy).ForEach(kv => kv.Value.SetTargetSelectionActive(true));
|
||||
}
|
||||
|
||||
private void HideTargetSelect()
|
||||
{
|
||||
foreach (var visual in _fighterVisuals.Values)
|
||||
{
|
||||
visual.SetTargetSelectionActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Babushka.scripts.CSharp.Common.Fight.Actions;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public class AllyFighters
|
||||
{
|
||||
public FightWorld.Fighter vesnaFighter = new()
|
||||
{
|
||||
type = FightWorld.Fighter.Type.Vesna,
|
||||
maxHealth = 20,
|
||||
isEnemy = false,
|
||||
availableActions =
|
||||
[
|
||||
new AllyAttackAction()
|
||||
]
|
||||
};
|
||||
public FightWorld.Fighter chuhaFighter = new()
|
||||
{
|
||||
type = FightWorld.Fighter.Type.Chuha,
|
||||
maxHealth = 15,
|
||||
isEnemy = false,
|
||||
availableActions =
|
||||
[
|
||||
new FighterAction.Skip()
|
||||
]
|
||||
};
|
||||
|
||||
public bool IsAlive()
|
||||
{
|
||||
return vesnaFighter.IsAlive();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dst8xcyiw18uc
|
||||
@@ -9,7 +9,7 @@ using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public class FightHappening
|
||||
public partial class FightHappening : Node
|
||||
{
|
||||
/*
|
||||
To get a visual overview of the FightHappening state machine, refer to the graph on miro:
|
||||
@@ -36,14 +36,14 @@ public class FightHappening
|
||||
EnemyWin,
|
||||
}
|
||||
|
||||
private class FightersEnterStaging
|
||||
public class FightersEnterStaging
|
||||
{
|
||||
public required List<FightWorld.Fighter> enteringAllyFighters;
|
||||
public required List<FightWorld.Fighter> enteringEnemyFighters;
|
||||
|
||||
public bool HasAnyToExecute()
|
||||
{
|
||||
return enteringAllyFighters.Count != 0 || enteringEnemyFighters.Count != 0;
|
||||
return enteringAllyFighters.Any() || enteringEnemyFighters.Any();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class FightHappening
|
||||
|
||||
#endregion
|
||||
|
||||
#region ShortCuts
|
||||
#region Shortcuts
|
||||
|
||||
private static FightWorld.FightHappeningData HappeningData =>
|
||||
FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException();
|
||||
@@ -67,19 +67,34 @@ public class FightHappening
|
||||
|
||||
#region Events
|
||||
|
||||
public event Action<FightState>? transitionFromState;
|
||||
public event Action<FightState, FightState>? transitionState;
|
||||
public event Action<FightState>? transitionToState;
|
||||
[Signal]
|
||||
public delegate void SignalTransitionFromStateEventHandler(FightState state);
|
||||
|
||||
[Signal]
|
||||
public delegate void SignalTransitionStateEventHandler(FightState from, FightState to);
|
||||
|
||||
[Signal]
|
||||
public delegate void SignalTransitionToStateEventHandler(FightState state);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Staging
|
||||
#region Singleton
|
||||
|
||||
private FightersEnterStaging? _fightersEnterStaging;
|
||||
private FighterAction? _actionStaging;
|
||||
public static FightHappening Instance = null!;
|
||||
|
||||
private void SetupInstance()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
SetupInstance();
|
||||
StartFight();
|
||||
}
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void StartFight()
|
||||
@@ -88,17 +103,51 @@ public class FightHappening
|
||||
ChangeState(FightState.FightStartAnim);
|
||||
}
|
||||
|
||||
public void ActionSelect(FighterAction action)
|
||||
{
|
||||
RequireState(FightState.InputActionSelect);
|
||||
HappeningData.actionStaging = action;
|
||||
action.Reset();
|
||||
ChangeState(FightState.ActionCheckDetails);
|
||||
}
|
||||
|
||||
public void DetailFilled()
|
||||
{
|
||||
RequireState(FightState.InputActionDetail);
|
||||
ChangeState(FightState.ActionCheckDetails);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region State Machine
|
||||
|
||||
private bool _inTransition = false;
|
||||
private FightState? _changeToAfterTransition = null;
|
||||
|
||||
private void ChangeState(FightState nextState)
|
||||
{
|
||||
_changeToAfterTransition = null;
|
||||
if (_inTransition)
|
||||
{
|
||||
_changeToAfterTransition = nextState;
|
||||
return;
|
||||
}
|
||||
|
||||
_inTransition = true;
|
||||
TransitionFromState();
|
||||
var lastState = HappeningData.fightState;
|
||||
HappeningData.fightState = nextState;
|
||||
TransitionFromToState(nextState, lastState);
|
||||
TransitionToState(nextState);
|
||||
|
||||
EmitSignalSignalTransitionFromState(lastState);
|
||||
EmitSignalSignalTransitionState(lastState, nextState);
|
||||
EmitSignalSignalTransitionToState(nextState);
|
||||
_inTransition = false;
|
||||
|
||||
if (_changeToAfterTransition.HasValue)
|
||||
{
|
||||
ChangeState(_changeToAfterTransition.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void TransitionFromState()
|
||||
@@ -108,21 +157,10 @@ public class FightHappening
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -130,8 +168,8 @@ public class FightHappening
|
||||
AdvanceToStateInSeconds(FightState.FightersEnter, StartAnimationTime);
|
||||
break;
|
||||
case FightState.FightersEnter:
|
||||
_fightersEnterStaging = StageFightersEnter();
|
||||
if (_fightersEnterStaging.HasAnyToExecute())
|
||||
HappeningData.fightersEnterStaging = StageFightersEnter();
|
||||
if (HappeningData.fightersEnterStaging.HasAnyToExecute())
|
||||
{
|
||||
ExecuteFightersEnter();
|
||||
ChangeState(FightState.FightersEnterAnim);
|
||||
@@ -150,10 +188,11 @@ public class FightHappening
|
||||
ChangeState(FightState.StateCheck);
|
||||
break;
|
||||
case FightState.StateCheck:
|
||||
// restest action staging
|
||||
_actionStaging = null;
|
||||
// restest action staging and fighter enter staging
|
||||
HappeningData.actionStaging = null;
|
||||
HappeningData.fightersEnterStaging = null;
|
||||
|
||||
if ( /*TODO: are all allys dead*/ false)
|
||||
if (!FightWorld.Instance.allyFighters.IsAlive())
|
||||
{
|
||||
ChangeState(FightState.EnemyWin);
|
||||
}
|
||||
@@ -161,7 +200,7 @@ public class FightHappening
|
||||
{
|
||||
ChangeState(FightState.PlayerWin);
|
||||
}
|
||||
else if (CurrentFighter.actionsLeft <= 0)
|
||||
else if (CurrentFighter.actionPointsLeft <= 0)
|
||||
{
|
||||
ChangeState(FightState.FightersEnter);
|
||||
}
|
||||
@@ -179,9 +218,11 @@ public class FightHappening
|
||||
// wait for player input
|
||||
break;
|
||||
case FightState.ActionCheckDetails:
|
||||
RequireNotNull(HappeningData.actionStaging);
|
||||
|
||||
if (ActionAbort())
|
||||
ChangeState(FightState.InputActionSelect);
|
||||
else if (ActionNeededDetail() != null)
|
||||
else if (ActionNeededDetail())
|
||||
ChangeState(FightState.InputActionDetail);
|
||||
else
|
||||
ChangeState(FightState.ActionExecute);
|
||||
@@ -190,7 +231,7 @@ public class FightHappening
|
||||
// wait for player input
|
||||
break;
|
||||
case FightState.EnemyActionSelect:
|
||||
_actionStaging = CurrentFighter.AutoSelectAction();
|
||||
HappeningData.actionStaging = CurrentFighter.AutoSelectAction();
|
||||
ChangeState(FightState.ActionExecute);
|
||||
break;
|
||||
case FightState.ActionExecute:
|
||||
@@ -212,7 +253,6 @@ public class FightHappening
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Game Logic
|
||||
@@ -221,38 +261,33 @@ public class FightHappening
|
||||
{
|
||||
// ally
|
||||
var enteringAllyFighters = new List<FightWorld.Fighter>();
|
||||
//TODO
|
||||
var allyFighters = FightWorld.Instance.allyFighters;
|
||||
if (!allyFighters.vesnaFighter.entered)
|
||||
{
|
||||
enteringAllyFighters.Add(allyFighters.vesnaFighter);
|
||||
}
|
||||
|
||||
// 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
|
||||
enteringEnemyFighters = HappeningData.enemyGroup.GetUptoUnenteredFighters(enemySpaceLeft).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private void ExecuteFightersEnter()
|
||||
{
|
||||
Debug.Assert(_fightersEnterStaging != null);
|
||||
foreach (var fighter in _fightersEnterStaging.enteringAllyFighters)
|
||||
Debug.Assert(HappeningData.fightersEnterStaging != null);
|
||||
foreach (var fighter in HappeningData.fightersEnterStaging.enteringAllyFighters)
|
||||
{
|
||||
fighter.entered = true;
|
||||
HappeningData.fighterStack.AddAsLast(fighter);
|
||||
}
|
||||
|
||||
foreach (var fighter in _fightersEnterStaging.enteringEnemyFighters)
|
||||
foreach (var fighter in HappeningData.fightersEnterStaging.enteringEnemyFighters)
|
||||
{
|
||||
fighter.entered = true;
|
||||
HappeningData.fighterStack.AddAsLast(fighter);
|
||||
@@ -262,30 +297,32 @@ public class FightHappening
|
||||
private void ExecuteNextFighter()
|
||||
{
|
||||
HappeningData.fighterStack.Next();
|
||||
CurrentFighter.actionPointsLeft = CurrentFighter.maxActionPoints;
|
||||
}
|
||||
|
||||
private void ExecuteAction()
|
||||
{
|
||||
Debug.Assert(_actionStaging != null);
|
||||
_actionStaging.ExecuteAction();
|
||||
Debug.Assert(HappeningData.actionStaging != null);
|
||||
HappeningData.actionStaging.ExecuteAction();
|
||||
CurrentFighter.actionPointsLeft -= HappeningData.actionStaging.GetActionPointCost();
|
||||
}
|
||||
|
||||
private Variant<float, Func<bool>> GetActionAnimationEnd()
|
||||
{
|
||||
Debug.Assert(_actionStaging != null);
|
||||
return _actionStaging.GetAnimationEnd();
|
||||
Debug.Assert(HappeningData.actionStaging != null);
|
||||
return HappeningData.actionStaging.GetAnimationEnd();
|
||||
}
|
||||
|
||||
private bool ActionAbort()
|
||||
{
|
||||
Debug.Assert(_actionStaging != null);
|
||||
return _actionStaging.MarkedForAbort();
|
||||
Debug.Assert(HappeningData.actionStaging != null);
|
||||
return HappeningData.actionStaging.MarkedForAbort();
|
||||
}
|
||||
|
||||
private FighterAction.FighterActionDetail? ActionNeededDetail()
|
||||
private bool ActionNeededDetail()
|
||||
{
|
||||
Debug.Assert(_actionStaging != null);
|
||||
return _actionStaging.NeededDetail();
|
||||
Debug.Assert(HappeningData.actionStaging != null);
|
||||
return HappeningData.actionStaging.NextDetail();
|
||||
}
|
||||
|
||||
#endregion // Game Logic
|
||||
@@ -301,6 +338,14 @@ public class FightHappening
|
||||
$"Can not call this Method while in state {HappeningData.fightState}. Only available in {string.Join(" ,", states)}");
|
||||
}
|
||||
|
||||
private void RequireNotNull(Object? o)
|
||||
{
|
||||
if (o != null)
|
||||
return;
|
||||
|
||||
throw new Exception("Object must not be null to call this method");
|
||||
}
|
||||
|
||||
private void AdvanceToStateInSeconds(FightState nextState, float seconds)
|
||||
{
|
||||
FightWorld.Instance.GetTree().CreateTimer(seconds).Timeout += () => ChangeState(nextState);
|
||||
@@ -317,4 +362,6 @@ public class FightHappening
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightHappeningStateDebugger : Node
|
||||
{
|
||||
[Export] private Label _label;
|
||||
|
||||
private FightWorld.FightHappeningData Data => FightWorld.Instance.fightHappeningData!;
|
||||
|
||||
public void StateChange(FightHappening.FightState from, FightHappening.FightState to)
|
||||
{
|
||||
_label.Text += $"State changed from {from} to {to}\n";
|
||||
switch (to)
|
||||
{
|
||||
case FightHappening.FightState.None:
|
||||
break;
|
||||
case FightHappening.FightState.FightStartAnim:
|
||||
break;
|
||||
case FightHappening.FightState.FightersEnter:
|
||||
break;
|
||||
case FightHappening.FightState.FightersEnterAnim:
|
||||
_label.Text +=
|
||||
$" {Data.fightersEnterStaging!.enteringAllyFighters.Count} allies " +
|
||||
$"and {Data.fightersEnterStaging.enteringEnemyFighters.Count} enemies are entering the fight.\n";
|
||||
break;
|
||||
case FightHappening.FightState.NextFighter:
|
||||
break;
|
||||
case FightHappening.FightState.StateCheck:
|
||||
break;
|
||||
case FightHappening.FightState.InputActionSelect:
|
||||
break;
|
||||
case FightHappening.FightState.ActionCheckDetails:
|
||||
break;
|
||||
case FightHappening.FightState.InputActionDetail:
|
||||
break;
|
||||
case FightHappening.FightState.ActionExecute:
|
||||
_label.Text += $" Executing action: {Data.actionStaging!.GetType()}\n";
|
||||
break;
|
||||
case FightHappening.FightState.ActionAnim:
|
||||
break;
|
||||
case FightHappening.FightState.EnemyActionSelect:
|
||||
break;
|
||||
case FightHappening.FightState.PlayerWin:
|
||||
break;
|
||||
case FightHappening.FightState.EnemyWin:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(to), to, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://d2ugtb3dalrg3
|
||||
@@ -0,0 +1,27 @@
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightHappeningStateReaction : Node
|
||||
{
|
||||
[Export] private FightHappening.FightState _fightState;
|
||||
|
||||
[Signal]
|
||||
public delegate void OnStateEnteredEventHandler();
|
||||
|
||||
[Signal]
|
||||
public delegate void OnStateExitedEventHandler();
|
||||
|
||||
public void FightHappeningStateTransitioned(FightHappening.FightState fromState, FightHappening.FightState toState)
|
||||
{
|
||||
if (fromState == _fightState)
|
||||
{
|
||||
EmitSignalOnStateExited();
|
||||
}
|
||||
|
||||
if (toState == _fightState)
|
||||
{
|
||||
EmitSignalOnStateEntered();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://buiwuf7pjfq8
|
||||
@@ -1,21 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using Babushka.scripts.CSharp.Common.Util;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightRoomSceneSetup : Node
|
||||
{
|
||||
[Export] private Label debugLabel;
|
||||
[Export(PropertyHint.ArrayType)] private Node2D[] _enemyGroupSpawns;
|
||||
[Export] private PackedScene _roamingEnemyGroupPrefab;
|
||||
[Export] private FightSceneSwitcher _fightSceneSwitcher;
|
||||
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
var room = FightWorld.Instance.currentRoom!;
|
||||
debugLabel.Text = $"Room Debug:\n{room.paths.Count} paths out of this room\n{room.enemyGroups.Count} enemy groups:\n";
|
||||
foreach (var enemyGroup in room.enemyGroups)
|
||||
|
||||
var i = 0;
|
||||
foreach (var availableParent in _enemyGroupSpawns.Shuffle())
|
||||
{
|
||||
debugLabel.Text += $" {enemyGroup.enemies.Count} enemies:\n";
|
||||
foreach (var enemy in enemyGroup.enemies)
|
||||
{
|
||||
debugLabel.Text += $" {enemy.type}\n";
|
||||
}
|
||||
var enemyGroup = room.enemyGroups[i];
|
||||
var roamingEnemyGroup = _roamingEnemyGroupPrefab.Instantiate<RoamingEnemyGroup>();
|
||||
roamingEnemyGroup.Initialize(enemyGroup, _fightSceneSwitcher);
|
||||
availableParent.AddChild(roamingEnemyGroup);
|
||||
if (i >= room.enemyGroups.Count - 1) break;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public partial class FightSceneSwitcher : Node
|
||||
private async void UnloadAfterDelay()
|
||||
{
|
||||
await ToSignal(GetTree().CreateTimer(1.0f), "timeout"); // 1.0f seconds
|
||||
sceneRoot.QueueFree();
|
||||
//sceneRoot.QueueFree();
|
||||
}
|
||||
|
||||
public void SwitchRoom(int pathIndex)
|
||||
@@ -38,4 +38,16 @@ public partial class FightSceneSwitcher : Node
|
||||
FightWorld.Instance.currentRoom = nextRoom;
|
||||
LoadNext();
|
||||
}
|
||||
|
||||
public void SwitchToFight(FightWorld.FighterGroup enemyGroup)
|
||||
{
|
||||
if (FightWorld.Instance.fightHappeningData != null)
|
||||
throw new Exception("Trying to start a fight while already in a fight");
|
||||
|
||||
FightWorld.Instance.fightHappeningData = new FightWorld.FightHappeningData
|
||||
{
|
||||
enemyGroup = enemyGroup,
|
||||
};
|
||||
LoadNext();
|
||||
}
|
||||
}
|
||||
@@ -5,21 +5,22 @@ namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public static class FightUtils
|
||||
{
|
||||
public static int GetEnteredAmount(this FightWorld.EnemyGroup self)
|
||||
public static int GetEnteredAmount(this FightWorld.FighterGroup self)
|
||||
{
|
||||
return self.enemies.Count(e => e.IsAlive() && e.entered);
|
||||
}
|
||||
|
||||
public static bool TryGetFirstUnenteredFighter(this FightWorld.EnemyGroup self, out FightWorld.Fighter fighter)
|
||||
public static IEnumerable<FightWorld.Fighter> GetUptoUnenteredFighters(
|
||||
this FightWorld.FighterGroup self,
|
||||
int maxFighters)
|
||||
{
|
||||
foreach (var f in self.enemies.Where(e=>!e.entered && e.IsAlive()))
|
||||
{
|
||||
fighter = f;
|
||||
return true;
|
||||
}
|
||||
if (maxFighters <= self.enemies.Count)
|
||||
return self.enemies
|
||||
.Where(e => !e.entered && e.IsAlive());
|
||||
|
||||
fighter = null!;
|
||||
return false;
|
||||
return self.enemies
|
||||
.Where(e => !e.entered && e.IsAlive())
|
||||
.Take(maxFighters);
|
||||
}
|
||||
|
||||
public static bool IsAlive(this FightWorld.Fighter self)
|
||||
@@ -37,9 +38,13 @@ public static class FightUtils
|
||||
return self.health ?? self.maxHealth;
|
||||
}
|
||||
|
||||
public static bool AreAllDead(this FightWorld.EnemyGroup self)
|
||||
public static void AddHealth(this FightWorld.Fighter self, int addHealth)
|
||||
{
|
||||
self.health = self.GetHealth() + addHealth;
|
||||
}
|
||||
|
||||
public static bool AreAllDead(this FightWorld.FighterGroup self)
|
||||
{
|
||||
return self.enemies.All(e => e.IsDead());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,10 +14,10 @@ public partial class FightWorld : Node
|
||||
public class Room
|
||||
{
|
||||
public required Dictionary<int, Room> paths;
|
||||
public required List<EnemyGroup> enemyGroups;
|
||||
public required List<FighterGroup> enemyGroups;
|
||||
}
|
||||
|
||||
public class EnemyGroup
|
||||
public class FighterGroup
|
||||
{
|
||||
public required List<Fighter> enemies;
|
||||
}
|
||||
@@ -26,7 +26,9 @@ public partial class FightWorld : Node
|
||||
{
|
||||
public FightHappening.FightState fightState = FightHappening.FightState.None;
|
||||
public FighterStack fighterStack = new();
|
||||
public required EnemyGroup enemyGroup;
|
||||
public required FighterGroup enemyGroup;
|
||||
public FightHappening.FightersEnterStaging? fightersEnterStaging;
|
||||
public FighterAction? actionStaging;
|
||||
}
|
||||
|
||||
public class Fighter
|
||||
@@ -37,16 +39,18 @@ public partial class FightWorld : Node
|
||||
BigBlob,
|
||||
Mavka,
|
||||
YourMom,
|
||||
Vesna
|
||||
Vesna,
|
||||
Chuha
|
||||
}
|
||||
|
||||
public required Type type;
|
||||
public required int maxHealth;
|
||||
public required bool isEnemy;
|
||||
public required List<FighterAction> availableActions;
|
||||
public int maxActionPoints = 1;
|
||||
public int? health = null; // null => initialize to full health on spawn
|
||||
public bool entered = false;
|
||||
public int actionsLeft;
|
||||
public int actionPointsLeft;
|
||||
|
||||
public FighterAction AutoSelectAction()
|
||||
{
|
||||
@@ -69,6 +73,7 @@ public partial class FightWorld : Node
|
||||
public World? world = null;
|
||||
public Room? currentRoom = null;
|
||||
public FightHappeningData? fightHappeningData = null;
|
||||
public AllyFighters allyFighters = new();
|
||||
|
||||
public void MyEnterTree()
|
||||
{
|
||||
@@ -123,9 +128,9 @@ public partial class FightWorld : Node
|
||||
return room;
|
||||
}
|
||||
|
||||
private List<EnemyGroup> GenerateEnemyGroups()
|
||||
private List<FighterGroup> GenerateEnemyGroups()
|
||||
{
|
||||
var enemyGroups = new List<EnemyGroup>();
|
||||
var enemyGroups = new List<FighterGroup>();
|
||||
|
||||
var enemyGroupCount = GD.RandRange(1, 3);
|
||||
|
||||
@@ -137,9 +142,9 @@ public partial class FightWorld : Node
|
||||
return enemyGroups;
|
||||
}
|
||||
|
||||
private EnemyGroup GenerateSingleEnemyGroup()
|
||||
private FighterGroup GenerateSingleEnemyGroup()
|
||||
{
|
||||
var enemyGroup = new EnemyGroup
|
||||
var enemyGroup = new FighterGroup
|
||||
{
|
||||
enemies = []
|
||||
};
|
||||
@@ -158,13 +163,14 @@ public partial class FightWorld : Node
|
||||
{
|
||||
var typeRoll = GD.RandRange(0, 99);
|
||||
|
||||
var type = typeRoll switch
|
||||
{
|
||||
< 50 => Fighter.Type.Blob,
|
||||
< 75 => Fighter.Type.BigBlob,
|
||||
< 90 => Fighter.Type.Mavka,
|
||||
_ => Fighter.Type.YourMom
|
||||
};
|
||||
//var type = typeRoll switch
|
||||
//{
|
||||
// < 50 => Fighter.Type.Blob,
|
||||
// < 75 => Fighter.Type.BigBlob,
|
||||
// < 90 => Fighter.Type.Mavka,
|
||||
// _ => Fighter.Type.YourMom
|
||||
//};
|
||||
var type = Fighter.Type.Blob;
|
||||
|
||||
var enemy = new Fighter
|
||||
{
|
||||
@@ -172,7 +178,8 @@ public partial class FightWorld : Node
|
||||
health = null,
|
||||
isEnemy = true,
|
||||
maxHealth = 12,
|
||||
availableActions = [
|
||||
availableActions =
|
||||
[
|
||||
new FighterAction.Skip()
|
||||
]
|
||||
};
|
||||
|
||||
@@ -7,6 +7,17 @@ namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public abstract class FighterAction
|
||||
{
|
||||
// enum has explicit values, because they are set in godot signals as integers
|
||||
// e.g. here: BabushkaSceneFightHappening => ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/AttackButton
|
||||
public enum AllyActionButton
|
||||
{
|
||||
None,
|
||||
Attack = 1,
|
||||
Summon = 2,
|
||||
Talk = 3,
|
||||
Flee = 4,
|
||||
}
|
||||
|
||||
public class TargetSelection
|
||||
{
|
||||
// ReSharper disable once MemberHidesStaticFromOuterClass
|
||||
@@ -63,7 +74,46 @@ public abstract class FighterAction
|
||||
return _abort;
|
||||
}
|
||||
|
||||
public abstract FighterActionDetail? NeededDetail();
|
||||
/// <summary>
|
||||
/// Returns the FighterActionDetail, that is currently handled.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual FighterActionDetail CurrentDetail()
|
||||
{
|
||||
throw new Exception("Action has no details to handle");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the next Detail to be handled. Returns false, when there are no more details to handle.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract bool NextDetail();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the action point cost of this action.
|
||||
/// Right now, only the values 1 and 0 make sense.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual int GetActionPointCost()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will be called right after the action is selected by the player. Can be used to reset the state of the details
|
||||
/// </summary>
|
||||
public virtual void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this action should be bound to an action button in the UI, return the corresponding enum value here.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual AllyActionButton BindToActionButton()
|
||||
{
|
||||
return AllyActionButton.None;
|
||||
}
|
||||
|
||||
public class Skip : FighterAction
|
||||
{
|
||||
@@ -72,9 +122,10 @@ public abstract class FighterAction
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public override FighterActionDetail? NeededDetail()
|
||||
public override bool NextDetail()
|
||||
{
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c60jugfee0bpv
|
||||
@@ -0,0 +1 @@
|
||||
uid://bahm4ukspymm2
|
||||
@@ -1,131 +1,72 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using Babushka.scripts.CSharp.Common.Fight.ActionDetails;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
[Tool]
|
||||
public partial class FighterVisual : Node2D
|
||||
{
|
||||
//[Export] public string name;
|
||||
//[Export] public int maxHealth;
|
||||
//[Export] public int attackStrength;
|
||||
//[Export] public int maxActions = 1;
|
||||
[Export] public FightWorld.Fighter.Type type;
|
||||
#region Shortcuts
|
||||
|
||||
private FightWorld.FightHappeningData HappeningData =>
|
||||
FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException();
|
||||
|
||||
#endregion
|
||||
|
||||
[ExportCategory("References")]
|
||||
[Export] private Node2D _attackButtons;
|
||||
[Export] private Node2D _targetButtons;
|
||||
[Export] private Node2D _targetMarker;
|
||||
[Export] private Label _healthText;
|
||||
[Export] private Node2D _visualSprite;
|
||||
[Export] private Node2D _visualParent;
|
||||
[Export] private Node2D _targetSelectionParent;
|
||||
|
||||
[Signal] public delegate void DamageTakenEventHandler();
|
||||
[Signal] public delegate void AttackingEventHandler();
|
||||
[Signal] public delegate void DyingEventHandler();
|
||||
[Signal] public delegate void HealedEventHandler();
|
||||
|
||||
[Signal]
|
||||
public delegate void DamageTakenEventHandler();
|
||||
|
||||
[Signal]
|
||||
public delegate void AttackingEventHandler();
|
||||
|
||||
[Signal]
|
||||
public delegate void DyingEventHandler();
|
||||
|
||||
[Signal]
|
||||
public delegate void HealedEventHandler();
|
||||
|
||||
|
||||
private FightWorld.Fighter _boundFighter;
|
||||
|
||||
//private void Die()
|
||||
//{
|
||||
// _visualSprite.Scale = new Vector2(1, 0.3f);
|
||||
// EmitSignalDying();
|
||||
//}
|
||||
|
||||
//public override void _Ready()
|
||||
//{
|
||||
// UpdateHealthVisual();
|
||||
// ResetActions();
|
||||
//}
|
||||
|
||||
public void Initialize(FightWorld.Fighter fighter)
|
||||
{
|
||||
_boundFighter = fighter;
|
||||
UpdateHealthVisual();
|
||||
UpdateMirrorState();
|
||||
}
|
||||
|
||||
public void Attack()
|
||||
/// <summary>
|
||||
/// fighter visuals should always look to the right in the scene.
|
||||
/// This function flips the sprites horizontally, when the fighter is an enemy.
|
||||
/// </summary>
|
||||
private void UpdateMirrorState()
|
||||
{
|
||||
//FightHappening.SelectAttack(this);
|
||||
_visualParent.Scale = new Vector2(_boundFighter.isEnemy ? -1 : 1, 1);
|
||||
}
|
||||
|
||||
public void HideAttackButton()
|
||||
public void SetTargetSelectionActive(bool value)
|
||||
{
|
||||
_attackButtons.Hide();
|
||||
_targetSelectionParent.Visible = value;
|
||||
_targetSelectionParent.ProcessMode = value ? ProcessModeEnum.Inherit : ProcessModeEnum.Disabled;
|
||||
}
|
||||
|
||||
public void ShowAttackButton()
|
||||
// listen from inside
|
||||
public void ClickedTarget()
|
||||
{
|
||||
_attackButtons.Show();
|
||||
}
|
||||
|
||||
public void HideTargetButtons()
|
||||
{
|
||||
_targetButtons.Hide();
|
||||
}
|
||||
|
||||
public void ShowTargetButtons()
|
||||
{
|
||||
_targetButtons.Show();
|
||||
}
|
||||
|
||||
public void TargetMouseEvent(Node viewport, InputEvent inputEvent, int shapeIdx)
|
||||
{
|
||||
if (inputEvent.IsPressed())
|
||||
ClickedTarget();
|
||||
}
|
||||
|
||||
public void AttackMouseEvent(Node viewport, InputEvent inputEvent, int shapeIdx)
|
||||
{
|
||||
if (inputEvent.IsPressed())
|
||||
ClickedAttack();
|
||||
}
|
||||
|
||||
public void HealMouseEvent(Node viewport, InputEvent inputEvent, int shapeIdx)
|
||||
{
|
||||
if (inputEvent.IsPressed())
|
||||
ClickedHeal();
|
||||
}
|
||||
|
||||
private void ClickedAttack()
|
||||
{
|
||||
//FightHappening.SelectAttack(this);
|
||||
}
|
||||
|
||||
private void ClickedHeal()
|
||||
{
|
||||
//FightHappening.SelectHeal(this);
|
||||
}
|
||||
|
||||
private void ClickedTarget()
|
||||
{
|
||||
//FightHappening.SelectTargetAndAttack(this);
|
||||
}
|
||||
|
||||
public void StartHoverTarget()
|
||||
{
|
||||
_targetMarker.Visible = true;
|
||||
}
|
||||
|
||||
public void EndHoverTarget()
|
||||
{
|
||||
_targetMarker.Visible = false;
|
||||
}
|
||||
|
||||
public void UpdateHealthVisual()
|
||||
{
|
||||
_healthText.Text = $"{_boundFighter.health}";
|
||||
}
|
||||
|
||||
public bool IsDead()
|
||||
{
|
||||
//return Health <= 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ResetActions()
|
||||
{
|
||||
//_actions = maxActions;
|
||||
if (HappeningData.actionStaging!.CurrentDetail() is not TargetSelectActionDetail targetDetail)
|
||||
throw new InvalidOperationException("No target selection needed right now");
|
||||
|
||||
targetDetail.SetTarget(_boundFighter);
|
||||
FightHappening.Instance.DetailFilled();
|
||||
}
|
||||
|
||||
// Animations
|
||||
public void AttackAnimation(FightAttack attack)
|
||||
{
|
||||
EmitSignalAttacking();
|
||||
@@ -134,7 +75,6 @@ public partial class FighterVisual : Node2D
|
||||
tween.TweenCallback(Callable.From(() => attack.target?.HitAnimation(attack)));
|
||||
tween.TweenProperty(this, "position", new Vector2(0, 0), 0.7)
|
||||
.SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out);
|
||||
|
||||
}
|
||||
|
||||
private void HitAnimation(FightAttack attack)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://b2n37glcxm8wv
|
||||
@@ -0,0 +1,20 @@
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class RoamingEnemyGroup : Node2D
|
||||
{
|
||||
private FightWorld.FighterGroup _boundEnemyGroup;
|
||||
private FightSceneSwitcher _fightSceneSwitcher;
|
||||
|
||||
public void Initialize(FightWorld.FighterGroup enemyGroup, FightSceneSwitcher fightSceneSwitcher)
|
||||
{
|
||||
_boundEnemyGroup = enemyGroup;
|
||||
_fightSceneSwitcher = fightSceneSwitcher;
|
||||
}
|
||||
|
||||
public void StartFight()
|
||||
{
|
||||
_fightSceneSwitcher.SwitchToFight(_boundEnemyGroup);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://lequnojtar76
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Fight.UI;
|
||||
|
||||
public partial class ActionSelectUiSetup : CanvasLayer
|
||||
{
|
||||
// shortcuts
|
||||
private FightWorld.FightHappeningData HappeningData =>
|
||||
FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException();
|
||||
private FightWorld.Fighter CurrentFighter => HappeningData.fighterStack.Current;
|
||||
|
||||
// references
|
||||
[Export] private Button _attackActionButton = null!;
|
||||
[Export] private Button _summonActionButton = null!;
|
||||
[Export] private Button _talkActionButton = null!;
|
||||
[Export] private Button _fleeActionButton = null!;
|
||||
|
||||
// gets called from a state reaction enter (InputActionSelect)
|
||||
public void StateEntered()
|
||||
{
|
||||
var actions = CurrentFighter.availableActions;
|
||||
|
||||
_attackActionButton.Visible = actions.Any(a => a.BindToActionButton() == FighterAction.AllyActionButton.Attack);
|
||||
_summonActionButton.Visible = actions.Any(a => a.BindToActionButton() == FighterAction.AllyActionButton.Summon);
|
||||
_talkActionButton.Visible = actions.Any(a => a.BindToActionButton() == FighterAction.AllyActionButton.Talk);
|
||||
_fleeActionButton.Visible = actions.Any(a => a.BindToActionButton() == FighterAction.AllyActionButton.Flee);
|
||||
}
|
||||
|
||||
public void SelectAction(FighterAction.AllyActionButton actionButton)
|
||||
{
|
||||
var action = CurrentFighter.availableActions.First(a => a.BindToActionButton() == actionButton);
|
||||
FightHappening.Instance.ActionSelect(action);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://byf2ywov34g0x
|
||||
@@ -0,0 +1,16 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public partial class TargetSelectionClick : Area2D
|
||||
{
|
||||
[Signal]
|
||||
public delegate void TargetSelectedEventHandler();
|
||||
|
||||
public override void _InputEvent(Viewport viewport, InputEvent @event, int shapeIdx)
|
||||
{
|
||||
if (@event is InputEventMouseButton { Pressed: true, ButtonIndex: MouseButton.Left })
|
||||
{
|
||||
EmitSignalTargetSelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://boprnfciqgixf
|
||||
@@ -16,6 +16,16 @@ public static class LinqExtras
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach<T>(this IEnumerable<T> self, Action<T, int> action)
|
||||
{
|
||||
var i = 0;
|
||||
foreach (var t in self)
|
||||
{
|
||||
action.Invoke(t, i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public static T? Random<T>(this IEnumerable<T> self)
|
||||
{
|
||||
var selfList = self.ToList();
|
||||
@@ -24,4 +34,16 @@ public static class LinqExtras
|
||||
var randomIndex = new Random().Next(0, selfList.Count);
|
||||
return selfList[randomIndex];
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> self)
|
||||
{
|
||||
var selfList = self.ToList();
|
||||
var random = new Random();
|
||||
for (var i = 0; i < selfList.Count; i++)
|
||||
{
|
||||
var j = random.Next(i, selfList.Count);
|
||||
(selfList[i], selfList[j]) = (selfList[j], selfList[i]);
|
||||
}
|
||||
return selfList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bxs7sn7j3vd0n
|
||||
Reference in New Issue
Block a user