From 0e315396c95044f0fefb832455b91a52fb01d4ea Mon Sep 17 00:00:00 2001 From: jonathan Date: Tue, 30 Sep 2025 16:23:05 +0200 Subject: [PATCH] Made fight fightable --- Babushka.sln.DotSettings.user | 5 + .../fighterVisuals/blob_fighter_visual.tscn | 18 ++ .../fighterVisuals/vesna_fighter_visual.tscn | 58 +++++++ prefabs/fight/roaming_enemy_group.tscn | 41 +++++ prefabs/fightOld/fight_manager_autoload.tscn | 2 +- .../fighters/enemy_blob_fighter.tscn | 0 .../fighters/enemy_mavkha_fighter.tscn | 0 .../fighters/vesna_fighter.tscn | 0 project.godot | 1 + scenes/Babushka_scene_bootstrap.tscn | 1 + scenes/Babushka_scene_fight_happening.tscn | 54 +++++- scenes/Babushka_scene_fight_world_room.tscn | 39 +++-- scenes/Babushka_scene_forest_fight_1_2d.tscn | 4 +- .../ActionDetails/TargetSelectActionDetail.cs | 39 +++++ .../TargetSelectActionDetail.cs.uid | 1 + .../Common/Fight/Actions/AllyAttackAction.cs | 46 ++++++ .../Fight/Actions/AllyAttackAction.cs.uid | 1 + .../CSharp/Common/Fight/AllFightersVisual.cs | 139 +++++++++++++--- scripts/CSharp/Common/Fight/AllyFighters.cs | 32 ++++ .../CSharp/Common/Fight/AllyFighters.cs.uid | 1 + scripts/CSharp/Common/Fight/FightHappening.cs | 155 ++++++++++++------ .../Fight/FightHappeningStateDebugger.cs | 53 ++++++ .../Fight/FightHappeningStateDebugger.cs.uid | 1 + .../Fight/FightHappeningStateReaction.cs | 27 +++ .../Fight/FightHappeningStateReaction.cs.uid | 1 + .../Common/Fight/FightRoomSceneSetup.cs | 24 ++- .../CSharp/Common/Fight/FightSceneSwitcher.cs | 14 +- scripts/CSharp/Common/Fight/FightUtils.cs | 33 ++-- scripts/CSharp/Common/Fight/FightWorld.cs | 41 +++-- scripts/CSharp/Common/Fight/FighterAction.cs | 61 ++++++- .../CSharp/Common/Fight/FighterAction.cs.uid | 1 + .../CSharp/Common/Fight/FighterStack.cs.uid | 1 + scripts/CSharp/Common/Fight/FighterVisual.cs | 150 +++++------------ .../Fight/NoFightHappeningException.cs.uid | 1 + .../CSharp/Common/Fight/RoamingEnemyGroup.cs | 20 +++ .../Common/Fight/RoamingEnemyGroup.cs.uid | 1 + .../Common/Fight/UI/ActionSelectUiSetup.cs | 35 ++++ .../Fight/UI/ActionSelectUiSetup.cs.uid | 1 + .../Common/Fight/UI/TargetSelectionClick.cs | 16 ++ .../Fight/UI/TargetSelectionClick.cs.uid | 1 + scripts/CSharp/Common/Util/LinqExtras.cs | 22 +++ scripts/CSharp/Common/Util/Variant.cs.uid | 1 + 42 files changed, 890 insertions(+), 252 deletions(-) create mode 100644 prefabs/fight/fighterVisuals/blob_fighter_visual.tscn create mode 100644 prefabs/fight/fighterVisuals/vesna_fighter_visual.tscn create mode 100644 prefabs/fight/roaming_enemy_group.tscn rename prefabs/{fight => fightOld}/fighters/enemy_blob_fighter.tscn (100%) rename prefabs/{fight => fightOld}/fighters/enemy_mavkha_fighter.tscn (100%) rename prefabs/{fight => fightOld}/fighters/vesna_fighter.tscn (100%) create mode 100644 scripts/CSharp/Common/Fight/ActionDetails/TargetSelectActionDetail.cs create mode 100644 scripts/CSharp/Common/Fight/ActionDetails/TargetSelectActionDetail.cs.uid create mode 100644 scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs create mode 100644 scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs.uid create mode 100644 scripts/CSharp/Common/Fight/AllyFighters.cs create mode 100644 scripts/CSharp/Common/Fight/AllyFighters.cs.uid create mode 100644 scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs create mode 100644 scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs.uid create mode 100644 scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs create mode 100644 scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs.uid create mode 100644 scripts/CSharp/Common/Fight/FighterAction.cs.uid create mode 100644 scripts/CSharp/Common/Fight/FighterStack.cs.uid create mode 100644 scripts/CSharp/Common/Fight/NoFightHappeningException.cs.uid create mode 100644 scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs create mode 100644 scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs.uid create mode 100644 scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs create mode 100644 scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs.uid create mode 100644 scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs create mode 100644 scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs.uid create mode 100644 scripts/CSharp/Common/Util/Variant.cs.uid diff --git a/Babushka.sln.DotSettings.user b/Babushka.sln.DotSettings.user index 770ca7c..cc77894 100644 --- a/Babushka.sln.DotSettings.user +++ b/Babushka.sln.DotSettings.user @@ -1,6 +1,7 @@  ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -9,9 +10,11 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -23,8 +26,10 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded <SessionState ContinuousTestingMode="0" IsActive="True" Name="Tests" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <TestAncestor> diff --git a/prefabs/fight/fighterVisuals/blob_fighter_visual.tscn b/prefabs/fight/fighterVisuals/blob_fighter_visual.tscn new file mode 100644 index 0000000..df51740 --- /dev/null +++ b/prefabs/fight/fighterVisuals/blob_fighter_visual.tscn @@ -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 diff --git a/prefabs/fight/fighterVisuals/vesna_fighter_visual.tscn b/prefabs/fight/fighterVisuals/vesna_fighter_visual.tscn new file mode 100644 index 0000000..606b028 --- /dev/null +++ b/prefabs/fight/fighterVisuals/vesna_fighter_visual.tscn @@ -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"] diff --git a/prefabs/fight/roaming_enemy_group.tscn b/prefabs/fight/roaming_enemy_group.tscn new file mode 100644 index 0000000..34af99f --- /dev/null +++ b/prefabs/fight/roaming_enemy_group.tscn @@ -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"] diff --git a/prefabs/fightOld/fight_manager_autoload.tscn b/prefabs/fightOld/fight_manager_autoload.tscn index 6f6385b..a7d72f2 100644 --- a/prefabs/fightOld/fight_manager_autoload.tscn +++ b/prefabs/fightOld/fight_manager_autoload.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://cnjsepvaqdbyq"] [ext_resource type="Script" uid="uid://j5ge24rk25wm" path="res://scripts/CSharp/Common/FightOld/FightManager.cs" id="1_8p7ev"] -[ext_resource type="PackedScene" uid="uid://cpanatqdjjpa3" path="res://prefabs/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") diff --git a/prefabs/fight/fighters/enemy_blob_fighter.tscn b/prefabs/fightOld/fighters/enemy_blob_fighter.tscn similarity index 100% rename from prefabs/fight/fighters/enemy_blob_fighter.tscn rename to prefabs/fightOld/fighters/enemy_blob_fighter.tscn diff --git a/prefabs/fight/fighters/enemy_mavkha_fighter.tscn b/prefabs/fightOld/fighters/enemy_mavkha_fighter.tscn similarity index 100% rename from prefabs/fight/fighters/enemy_mavkha_fighter.tscn rename to prefabs/fightOld/fighters/enemy_mavkha_fighter.tscn diff --git a/prefabs/fight/fighters/vesna_fighter.tscn b/prefabs/fightOld/fighters/vesna_fighter.tscn similarity index 100% rename from prefabs/fight/fighters/vesna_fighter.tscn rename to prefabs/fightOld/fighters/vesna_fighter.tscn diff --git a/project.godot b/project.godot index e6f41eb..c4309b8 100644 --- a/project.godot +++ b/project.godot @@ -28,6 +28,7 @@ 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" +InputService="*res://scripts/CSharp/Common/Services/InputService.cs" QuestManager="*res://prefabs/quests/quest_manager_autoload.tscn" FightManagerAutoload="*res://prefabs/fight/fight_manager_autoload.tscn" InputService="*res://scripts/CSharp/Common/Services/InputService.cs" diff --git a/scenes/Babushka_scene_bootstrap.tscn b/scenes/Babushka_scene_bootstrap.tscn index 5b1809d..fe66be1 100644 --- a/scenes/Babushka_scene_bootstrap.tscn +++ b/scenes/Babushka_scene_bootstrap.tscn @@ -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="."] diff --git a/scenes/Babushka_scene_fight_happening.tscn b/scenes/Babushka_scene_fight_happening.tscn index 7aa492f..96a3c6f 100644 --- a/scenes/Babushka_scene_fight_happening.tscn +++ b/scenes/Babushka_scene_fight_happening.tscn @@ -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"] diff --git a/scenes/Babushka_scene_fight_world_room.tscn b/scenes/Babushka_scene_fight_world_room.tscn index 9dc77c7..f7bfc7f 100644 --- a/scenes/Babushka_scene_fight_world_room.tscn +++ b/scenes/Babushka_scene_fight_world_room.tscn @@ -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"] diff --git a/scenes/Babushka_scene_forest_fight_1_2d.tscn b/scenes/Babushka_scene_forest_fight_1_2d.tscn index ba1e6b3..860d079 100644 --- a/scenes/Babushka_scene_forest_fight_1_2d.tscn +++ b/scenes/Babushka_scene_forest_fight_1_2d.tscn @@ -26,10 +26,10 @@ [ext_resource type="Shader" uid="uid://xnky830dtfsn" path="res://shader/repeat_texture.gdshader" id="25_sgom5"] [ext_resource type="Script" uid="uid://di0xxwfw43m0i" path="res://scripts/CSharp/Common/FightOld/FightStarter.cs" id="26_gg38r"] [ext_resource type="PackedScene" uid="uid://hk8ahyp6dgl6" path="res://prefabs/fightOld/fight_base_scene.tscn" id="27_55b52"] -[ext_resource type="PackedScene" uid="uid://bp64p6y72j71w" path="res://prefabs/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"] diff --git a/scripts/CSharp/Common/Fight/ActionDetails/TargetSelectActionDetail.cs b/scripts/CSharp/Common/Fight/ActionDetails/TargetSelectActionDetail.cs new file mode 100644 index 0000000..a160b07 --- /dev/null +++ b/scripts/CSharp/Common/Fight/ActionDetails/TargetSelectActionDetail.cs @@ -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"); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/ActionDetails/TargetSelectActionDetail.cs.uid b/scripts/CSharp/Common/Fight/ActionDetails/TargetSelectActionDetail.cs.uid new file mode 100644 index 0000000..6b7ed4c --- /dev/null +++ b/scripts/CSharp/Common/Fight/ActionDetails/TargetSelectActionDetail.cs.uid @@ -0,0 +1 @@ +uid://e8c8ym0fyprn diff --git a/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs b/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs new file mode 100644 index 0000000..20760b3 --- /dev/null +++ b/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs @@ -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> 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); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs.uid b/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs.uid new file mode 100644 index 0000000..1998e81 --- /dev/null +++ b/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs.uid @@ -0,0 +1 @@ +uid://c8c4t80bqsja5 diff --git a/scripts/CSharp/Common/Fight/AllFightersVisual.cs b/scripts/CSharp/Common/Fight/AllFightersVisual.cs index e99b836..da9a63e 100644 --- a/scripts/CSharp/Common/Fight/AllFightersVisual.cs +++ b/scripts/CSharp/Common/Fight/AllFightersVisual.cs @@ -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; - - [Export] private PackedScene _blobFighterVisual; - [Export] private PackedScene _bigBlobFighterVisual; - [Export] private PackedScene _mavkaFighterVisual; - [Export] private PackedScene _yourMomFighterVisual; - [Export] private PackedScene _vesnaFighterVisual; - - public void EnterFighter(FightWorld.Fighter fighter, bool isEnemy) + [ExportCategory("References")] [Export] + private Node2D _allyFighters = null!; + + [Export] private Node2D _enemyFighters = null!; + + [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 _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; + if (to == FightHappening.FightState.FightersEnterAnim) + { + EnterFighter(); + } + + if (to == FightHappening.FightState.InputActionDetail) + { + if (HappeningData.actionStaging!.CurrentDetail() is TargetSelectActionDetail targetDetail) + { + ShowTargetSelect(targetDetail); + } + } - var packedScene = fighter.type switch + if (from == FightHappening.FightState.InputActionDetail) { - FightWorld.Fighter.Type.Blob => _blobFighterVisual, - FightWorld.Fighter.Type.BigBlob => _bigBlobFighterVisual, - FightWorld.Fighter.Type.Mavka => _mavkaFighterVisual, - FightWorld.Fighter.Type.YourMom => _yourMomFighterVisual, - FightWorld.Fighter.Type.Vesna => _vesnaFighterVisual, - _ => throw new ArgumentOutOfRangeException() - }; - - var fighterVisual = packedScene.Instantiate(); - fighterVisual.Initialize(fighter); - parent.AddChild(fighterVisual); + 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.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.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 +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/AllyFighters.cs b/scripts/CSharp/Common/Fight/AllyFighters.cs new file mode 100644 index 0000000..ce294bd --- /dev/null +++ b/scripts/CSharp/Common/Fight/AllyFighters.cs @@ -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(); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/AllyFighters.cs.uid b/scripts/CSharp/Common/Fight/AllyFighters.cs.uid new file mode 100644 index 0000000..777ec0a --- /dev/null +++ b/scripts/CSharp/Common/Fight/AllyFighters.cs.uid @@ -0,0 +1 @@ +uid://dst8xcyiw18uc diff --git a/scripts/CSharp/Common/Fight/FightHappening.cs b/scripts/CSharp/Common/Fight/FightHappening.cs index 3910ea0..ea189a8 100644 --- a/scripts/CSharp/Common/Fight/FightHappening.cs +++ b/scripts/CSharp/Common/Fight/FightHappening.cs @@ -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 enteringAllyFighters; public required List 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,18 +67,33 @@ public class FightHappening #region Events - public event Action? transitionFromState; - public event Action? transitionState; - public event Action? 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 + + public static FightHappening Instance = null!; - private FightersEnterStaging? _fightersEnterStaging; - private FighterAction? _actionStaging; + private void SetupInstance() + { + Instance = this; + } #endregion + + public override void _Ready() + { + SetupInstance(); + StartFight(); + } #region Public Methods @@ -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(); - //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(); - - 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> 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 @@ -300,6 +337,14 @@ public class FightHappening throw new Exception( $"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) { @@ -317,4 +362,6 @@ public class FightHappening } #endregion + + } \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs b/scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs new file mode 100644 index 0000000..b9c4a70 --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs @@ -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); + } + } +} diff --git a/scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs.uid b/scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs.uid new file mode 100644 index 0000000..4de7fe7 --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs.uid @@ -0,0 +1 @@ +uid://d2ugtb3dalrg3 diff --git a/scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs b/scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs new file mode 100644 index 0000000..cc7bb2b --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs.uid b/scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs.uid new file mode 100644 index 0000000..ea8036a --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappeningStateReaction.cs.uid @@ -0,0 +1 @@ +uid://buiwuf7pjfq8 diff --git a/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs b/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs index 3df9eec..12c316d 100644 --- a/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs +++ b/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs @@ -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.Initialize(enemyGroup, _fightSceneSwitcher); + availableParent.AddChild(roamingEnemyGroup); + if (i >= room.enemyGroups.Count - 1) break; + i++; } } } \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FightSceneSwitcher.cs b/scripts/CSharp/Common/Fight/FightSceneSwitcher.cs index 5b31b1c..c25318c 100644 --- a/scripts/CSharp/Common/Fight/FightSceneSwitcher.cs +++ b/scripts/CSharp/Common/Fight/FightSceneSwitcher.cs @@ -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(); + } } \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FightUtils.cs b/scripts/CSharp/Common/Fight/FightUtils.cs index 25fc961..5bf0966 100644 --- a/scripts/CSharp/Common/Fight/FightUtils.cs +++ b/scripts/CSharp/Common/Fight/FightUtils.cs @@ -5,41 +5,46 @@ 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 GetUptoUnenteredFighters( + this FightWorld.FighterGroup self, + int maxFighters) { - foreach (var f in self.enemies.Where(e=>!e.entered && e.IsAlive())) - { - fighter = f; - return true; - } - - fighter = null!; - return false; + if (maxFighters <= self.enemies.Count) + return self.enemies + .Where(e => !e.entered && e.IsAlive()); + + return self.enemies + .Where(e => !e.entered && e.IsAlive()) + .Take(maxFighters); } 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) + 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()); } - } \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FightWorld.cs b/scripts/CSharp/Common/Fight/FightWorld.cs index b27c6d4..ea49c34 100644 --- a/scripts/CSharp/Common/Fight/FightWorld.cs +++ b/scripts/CSharp/Common/Fight/FightWorld.cs @@ -14,10 +14,10 @@ public partial class FightWorld : Node public class Room { public required Dictionary paths; - public required List enemyGroups; + public required List enemyGroups; } - public class EnemyGroup + public class FighterGroup { public required List 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 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 GenerateEnemyGroups() + private List GenerateEnemyGroups() { - var enemyGroups = new List(); + var enemyGroups = new List(); 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() ] }; diff --git a/scripts/CSharp/Common/Fight/FighterAction.cs b/scripts/CSharp/Common/Fight/FighterAction.cs index b18ed6b..a156089 100644 --- a/scripts/CSharp/Common/Fight/FighterAction.cs +++ b/scripts/CSharp/Common/Fight/FighterAction.cs @@ -7,13 +7,24 @@ 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 public static readonly TargetSelection Skip = new() { skipTargetSelection = () => true }; public Func skipTargetSelection = () => false; } - + public abstract class FighterActionDetail { public abstract bool DetailComplete(); @@ -63,7 +74,46 @@ public abstract class FighterAction return _abort; } - public abstract FighterActionDetail? NeededDetail(); + /// + /// Returns the FighterActionDetail, that is currently handled. + /// + /// + public virtual FighterActionDetail CurrentDetail() + { + throw new Exception("Action has no details to handle"); + } + + /// + /// Sets the next Detail to be handled. Returns false, when there are no more details to handle. + /// + /// + public abstract bool NextDetail(); + + /// + /// Returns the action point cost of this action. + /// Right now, only the values 1 and 0 make sense. + /// + /// + public virtual int GetActionPointCost() + { + return 1; + } + + /// + /// Will be called right after the action is selected by the player. Can be used to reset the state of the details + /// + public virtual void Reset() + { + } + + /// + /// If this action should be bound to an action button in the UI, return the corresponding enum value here. + /// + /// + 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; } } -} + +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FighterAction.cs.uid b/scripts/CSharp/Common/Fight/FighterAction.cs.uid new file mode 100644 index 0000000..31ed96a --- /dev/null +++ b/scripts/CSharp/Common/Fight/FighterAction.cs.uid @@ -0,0 +1 @@ +uid://c60jugfee0bpv diff --git a/scripts/CSharp/Common/Fight/FighterStack.cs.uid b/scripts/CSharp/Common/Fight/FighterStack.cs.uid new file mode 100644 index 0000000..1d25b2f --- /dev/null +++ b/scripts/CSharp/Common/Fight/FighterStack.cs.uid @@ -0,0 +1 @@ +uid://bahm4ukspymm2 diff --git a/scripts/CSharp/Common/Fight/FighterVisual.cs b/scripts/CSharp/Common/Fight/FighterVisual.cs index c092191..ec2d6dc 100644 --- a/scripts/CSharp/Common/Fight/FighterVisual.cs +++ b/scripts/CSharp/Common/Fight/FighterVisual.cs @@ -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; - - [ExportCategory("References")] - [Export] private Node2D _attackButtons; - [Export] private Node2D _targetButtons; - [Export] private Node2D _targetMarker; - [Export] private Label _healthText; - [Export] private Node2D _visualSprite; - - [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(); - } - - public void Attack() - { - //FightHappening.SelectAttack(this); - } - - public void HideAttackButton() - { - _attackButtons.Hide(); - } + #region Shortcuts - public void ShowAttackButton() - { - _attackButtons.Show(); - } + private FightWorld.FightHappeningData HappeningData => + FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException(); - public void HideTargetButtons() - { - _targetButtons.Hide(); - } + #endregion + + [ExportCategory("References")] + [Export] private Node2D _visualParent; + [Export] private Node2D _targetSelectionParent; + - public void ShowTargetButtons() - { - _targetButtons.Show(); - } + [Signal] + public delegate void DamageTakenEventHandler(); - public void TargetMouseEvent(Node viewport, InputEvent inputEvent, int shapeIdx) - { - if (inputEvent.IsPressed()) - ClickedTarget(); - } + [Signal] + public delegate void AttackingEventHandler(); - 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(); - } + [Signal] + public delegate void DyingEventHandler(); - private void ClickedAttack() - { - //FightHappening.SelectAttack(this); - } + [Signal] + public delegate void HealedEventHandler(); - private void ClickedHeal() - { - //FightHappening.SelectHeal(this); - } - private void ClickedTarget() - { - //FightHappening.SelectTargetAndAttack(this); - } + private FightWorld.Fighter _boundFighter; - public void StartHoverTarget() + public void Initialize(FightWorld.Fighter fighter) { - _targetMarker.Visible = true; + _boundFighter = fighter; + UpdateMirrorState(); } - public void EndHoverTarget() + /// + /// fighter visuals should always look to the right in the scene. + /// This function flips the sprites horizontally, when the fighter is an enemy. + /// + private void UpdateMirrorState() { - _targetMarker.Visible = false; + _visualParent.Scale = new Vector2(_boundFighter.isEnemy ? -1 : 1, 1); } - public void UpdateHealthVisual() + public void SetTargetSelectionActive(bool value) { - _healthText.Text = $"{_boundFighter.health}"; + _targetSelectionParent.Visible = value; + _targetSelectionParent.ProcessMode = value ? ProcessModeEnum.Inherit : ProcessModeEnum.Disabled; } - public bool IsDead() + // listen from inside + public void ClickedTarget() { - //return Health <= 0; - return true; - } + if (HappeningData.actionStaging!.CurrentDetail() is not TargetSelectActionDetail targetDetail) + throw new InvalidOperationException("No target selection needed right now"); - public void ResetActions() - { - //_actions = maxActions; + 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) @@ -154,4 +94,4 @@ public partial class FighterVisual : Node2D tween.TweenProperty(this, "scale", new Vector2(1, 1), 0.4) .SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out); } -} +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/NoFightHappeningException.cs.uid b/scripts/CSharp/Common/Fight/NoFightHappeningException.cs.uid new file mode 100644 index 0000000..b0e51cf --- /dev/null +++ b/scripts/CSharp/Common/Fight/NoFightHappeningException.cs.uid @@ -0,0 +1 @@ +uid://b2n37glcxm8wv diff --git a/scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs b/scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs new file mode 100644 index 0000000..c025054 --- /dev/null +++ b/scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs @@ -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); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs.uid b/scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs.uid new file mode 100644 index 0000000..8096990 --- /dev/null +++ b/scripts/CSharp/Common/Fight/RoamingEnemyGroup.cs.uid @@ -0,0 +1 @@ +uid://lequnojtar76 diff --git a/scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs b/scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs new file mode 100644 index 0000000..5f3610c --- /dev/null +++ b/scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs @@ -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); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs.uid b/scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs.uid new file mode 100644 index 0000000..f2b406c --- /dev/null +++ b/scripts/CSharp/Common/Fight/UI/ActionSelectUiSetup.cs.uid @@ -0,0 +1 @@ +uid://byf2ywov34g0x diff --git a/scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs b/scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs new file mode 100644 index 0000000..285b5b5 --- /dev/null +++ b/scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs.uid b/scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs.uid new file mode 100644 index 0000000..8900cec --- /dev/null +++ b/scripts/CSharp/Common/Fight/UI/TargetSelectionClick.cs.uid @@ -0,0 +1 @@ +uid://boprnfciqgixf diff --git a/scripts/CSharp/Common/Util/LinqExtras.cs b/scripts/CSharp/Common/Util/LinqExtras.cs index 92a79c1..fc84aa8 100644 --- a/scripts/CSharp/Common/Util/LinqExtras.cs +++ b/scripts/CSharp/Common/Util/LinqExtras.cs @@ -16,6 +16,16 @@ public static class LinqExtras } } + public static void ForEach(this IEnumerable self, Action action) + { + var i = 0; + foreach (var t in self) + { + action.Invoke(t, i); + i++; + } + } + public static T? Random(this IEnumerable 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 Shuffle(this IEnumerable 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; + } } diff --git a/scripts/CSharp/Common/Util/Variant.cs.uid b/scripts/CSharp/Common/Util/Variant.cs.uid new file mode 100644 index 0000000..e9fac77 --- /dev/null +++ b/scripts/CSharp/Common/Util/Variant.cs.uid @@ -0,0 +1 @@ +uid://bxs7sn7j3vd0n