diff --git a/prefabs/fight/damage_flying_nuber.tscn b/prefabs/fight/damage_flying_nuber.tscn index c2c2d1a..c209975 100644 --- a/prefabs/fight/damage_flying_nuber.tscn +++ b/prefabs/fight/damage_flying_nuber.tscn @@ -1,10 +1,30 @@ -[gd_scene load_steps=2 format=3 uid="uid://l1hdihubffeg"] +[gd_scene load_steps=3 format=3 uid="uid://l1hdihubffeg"] [ext_resource type="Script" uid="uid://b5i41b6502xam" path="res://scripts/CSharp/Common/Fight/FighterDamageIndicatorFlyingNumber.cs" id="1_m0ub6"] +[ext_resource type="Texture2D" uid="uid://do0y56t1moi2" path="res://art/mockups/erdbeeren.png" id="2_ctnqp"] -[node name="DamageFlyingNuber" type="Node2D" node_paths=PackedStringArray("_label")] +[node name="DamageFlyingNuber" type="Node2D" node_paths=PackedStringArray("_label", "_sprite")] script = ExtResource("1_m0ub6") _label = NodePath("Label") +_sprite = NodePath("TextureRect") + +[node name="TextureRect" type="TextureRect" parent="."] +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -61.0 +offset_top = -61.0 +offset_right = 61.0 +offset_bottom = 61.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +texture = ExtResource("2_ctnqp") +expand_mode = 1 +stretch_mode = 5 [node name="Label" type="Label" parent="."] custom_minimum_size = Vector2(200, 100) diff --git a/prefabs/fight/fight_world_autoload.tscn b/prefabs/fight/fight_world_autoload.tscn index 1692884..e6d7a57 100644 --- a/prefabs/fight/fight_world_autoload.tscn +++ b/prefabs/fight/fight_world_autoload.tscn @@ -1,6 +1,10 @@ -[gd_scene load_steps=2 format=3 uid="uid://n5cj71bxxjkk"] +[gd_scene load_steps=4 format=3 uid="uid://n5cj71bxxjkk"] [ext_resource type="Script" uid="uid://dqe1i2qmpttwf" path="res://scripts/CSharp/Common/Fight/FightWorld.cs" id="1_tnyce"] +[ext_resource type="Resource" uid="uid://duq7tshxv6uhp" path="res://resources/items/beet_seed.tres" id="2_lxs0o"] +[ext_resource type="Resource" uid="uid://0mnsr4anoaiq" path="res://resources/items/beet.tres" id="3_008v8"] [node name="FightWorldAutoload" type="Node2D"] script = ExtResource("1_tnyce") +_itemToDropByEnemyGroup = ExtResource("2_lxs0o") +itemBeetrootToEatForHealth = ExtResource("3_008v8") diff --git a/scenes/Babushka_scene_farm_outside_2d.tscn b/scenes/Babushka_scene_farm_outside_2d.tscn index be2050a..08045be 100644 --- a/scenes/Babushka_scene_farm_outside_2d.tscn +++ b/scenes/Babushka_scene_farm_outside_2d.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=118 format=3 uid="uid://gigb28qk8t12"] +[gd_scene load_steps=119 format=3 uid="uid://gigb28qk8t12"] [ext_resource type="PackedScene" uid="uid://c25udixd5m6l0" path="res://prefabs/characters/Vesna.tscn" id="1_7wfwe"] [ext_resource type="Texture2D" uid="uid://8sr11ex30n0m" path="res://art/mockups/Kenney_Backgrounds/Samples/uncolored_hills.png" id="2_7b2ri"] @@ -37,6 +37,7 @@ [ext_resource type="Resource" uid="uid://d1uuxp1lp4aro" path="res://resources/items/tomato_seed.tres" id="35_64mdn"] [ext_resource type="Texture2D" uid="uid://65e44yde224q" path="res://art/farm/Babushka_house_01.png" id="36_e5b7x"] [ext_resource type="Resource" uid="uid://duq7tshxv6uhp" path="res://resources/items/beet_seed.tres" id="36_fv1t2"] +[ext_resource type="Resource" uid="uid://0mnsr4anoaiq" path="res://resources/items/beet.tres" id="36_q1g8e"] [ext_resource type="AudioStream" uid="uid://cfqg50am0swb7" path="res://audio/Music/Farming_90BPM_69Bars_Loop.wav" id="37_8ey8m"] [ext_resource type="AudioStream" uid="uid://dku1rq5cocisg" path="res://audio/Music/Farming_90BPM_69Bars.wav" id="37_di1ed"] [ext_resource type="Shader" uid="uid://braevmqauoek7" path="res://shader/swaying_plant.gdshader" id="37_taxvr"] @@ -1043,6 +1044,24 @@ shape = SubResource("CircleShape2D_tm0yg") [node name="Icon" parent="YSorted/SeedPickup" index="4"] scale = Vector2(1, 1) +[node name="BeetPickup" parent="YSorted" instance=ExtResource("25_hukxv")] +position = Vector2(5787, 2269) +_finiteSupply = 3 +metadata/SaveID = "e1bbe13f-0622-42b8-97f3-87a8af369dc0" + +[node name="SpawnWithItem" parent="YSorted/BeetPickup" index="0"] +_blueprint = ExtResource("36_q1g8e") + +[node name="PickupInteractionArea" parent="YSorted/BeetPickup" index="3" node_paths=PackedStringArray("_spritesToOutline")] +_spritesToOutline = [NodePath("../../SeedPickup/Icon")] +metadata/SaveID = "ad152c51-3631-42c1-9aa4-4df896b35d8c" + +[node name="CollisionShape3D" parent="YSorted/BeetPickup/PickupInteractionArea/Area2D" index="0"] +shape = SubResource("CircleShape2D_tm0yg") + +[node name="Icon" parent="YSorted/BeetPickup" index="4"] +scale = Vector2(1, 1) + [node name="SeedPickup2" parent="YSorted" instance=ExtResource("25_hukxv")] position = Vector2(10705, 2257) _finiteSupply = 3 @@ -2507,6 +2526,7 @@ script = ExtResource("80_w1kgo") [connection signal="SuccessfulPickUp" from="YSorted/CanGenericPickup" to="YSorted/Vesna" method="HandlePickUp"] [connection signal="SuccessfulPickUp" from="YSorted/RakeGenericPickup" to="YSorted/Vesna" method="HandlePickUp"] [connection signal="SuccessfulPickUp" from="YSorted/SeedPickup" to="YSorted/Vesna" method="HandlePickUp"] +[connection signal="SuccessfulPickUp" from="YSorted/BeetPickup" to="YSorted/Vesna" method="HandlePickUp"] [connection signal="SuccessfulPickUp" from="YSorted/SeedPickup2" to="YSorted/Vesna" method="HandlePickUp"] [connection signal="InteractedTool" from="YSorted/Farm visuals/Static/EnterHouseInteraction" to="." method="LoadSceneAtIndex"] [connection signal="InteractedTool" from="YSorted/Blocker/InteractionArea" to="." method="LoadSceneAtIndex"] @@ -2531,6 +2551,8 @@ script = ExtResource("80_w1kgo") [editable path="YSorted/RakeGenericPickup/PickupInteractionArea"] [editable path="YSorted/SeedPickup"] [editable path="YSorted/SeedPickup/PickupInteractionArea"] +[editable path="YSorted/BeetPickup"] +[editable path="YSorted/BeetPickup/PickupInteractionArea"] [editable path="YSorted/SeedPickup2"] [editable path="YSorted/SeedPickup2/PickupInteractionArea"] [editable path="YSorted/Blocker/InteractionArea"] diff --git a/scenes/Babushka_scene_fight_happening.tscn b/scenes/Babushka_scene_fight_happening.tscn index 943f465..183a8b2 100644 --- a/scenes/Babushka_scene_fight_happening.tscn +++ b/scenes/Babushka_scene_fight_happening.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=14 format=3 uid="uid://cjshlwk8ajpnp"] +[gd_scene load_steps=20 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://c76mhhqyk4lgh" path="res://scripts/CSharp/Common/Fight/FightHappening.cs" id="1_gsk03"] @@ -6,6 +6,7 @@ [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="Script" uid="uid://cdrjvgm82pxoj" path="res://scripts/CSharp/Common/Fight/FightHappeningAnimationContext.cs" id="4_v5rv6"] [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="PackedScene" uid="uid://bydwj3pbvqrhb" path="res://prefabs/minigame/minigame.tscn" id="8_2b3cf"] @@ -13,20 +14,30 @@ [ext_resource type="Script" uid="uid://bwm0nhvt1083k" path="res://scripts/CSharp/Common/Fight/FightMinigameHandler.cs" id="8_falfe"] [ext_resource type="Script" uid="uid://d2ugtb3dalrg3" path="res://scripts/CSharp/Common/Fight/FightHappeningStateDebugger.cs" id="8_tv7cl"] [ext_resource type="Script" uid="uid://2f7rqk50gtdg" path="res://scripts/CSharp/Common/Fight/SwitchSceneOnFightEnd.cs" id="10_qqd8u"] +[ext_resource type="Script" uid="uid://6nniwfxye8ss" path="res://scripts/CSharp/Common/Fight/UsedItemIndicatorVisual.cs" id="14_b4ll5"] +[ext_resource type="Script" uid="uid://71mdwp2m4rta" path="res://scripts/CSharp/Common/Fight/UI/HealButtonVisual.cs" id="14_oy2wu"] +[ext_resource type="Resource" uid="uid://0mnsr4anoaiq" path="res://resources/items/beet.tres" id="15_k4fcr"] +[ext_resource type="PackedScene" uid="uid://l1hdihubffeg" path="res://prefabs/fight/damage_flying_nuber.tscn" id="15_oy2wu"] +[ext_resource type="Texture2D" uid="uid://djewfwrdt4iv3" path="res://art/ui/UI/icons/icon-fruit-beetroot.png" id="16_k4fcr"] [node name="BabushkaSceneFightHappening" type="Node2D"] [node name="FightHappening" type="Node" parent="."] script = ExtResource("1_gsk03") -[node name="ActionAnimationController" type="Node" parent="." node_paths=PackedStringArray("_allFightersVisual")] +[node name="ActionAnimationController" type="Node" parent="." node_paths=PackedStringArray("_allFightersVisual", "_animationContext")] script = ExtResource("2_7kjgs") _allFightersVisual = NodePath("../FightVisuals") +_animationContext = NodePath("AnimationContext") [node name="StateReactionActionAnimation" type="Node" parent="ActionAnimationController"] script = ExtResource("4_ydj1i") _fightState = 10 +[node name="AnimationContext" type="Node" parent="ActionAnimationController" node_paths=PackedStringArray("useHealItemIndicator")] +script = ExtResource("4_v5rv6") +useHealItemIndicator = NodePath("../../UseItemIndicator") + [node name="Camera2D" type="Camera2D" parent="."] [node name="FightSetup" type="Node2D" parent="."] @@ -146,7 +157,12 @@ theme_override_constants/margin_bottom = 10 [node name="Talk Button" type="Button" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3"] layout_mode = 2 theme_override_font_sizes/font_size = 41 -text = "Talk" +text = "x19 - Heal" +icon = ExtResource("16_k4fcr") +alignment = 0 +expand_icon = true +script = ExtResource("14_oy2wu") +_healItemBlueprint = ExtResource("15_k4fcr") [node name="MarginContainer4" type="MarginContainer" parent="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer"] layout_mode = 2 @@ -207,6 +223,12 @@ offset_right = 794.0 offset_bottom = -472.0 text = "Hello world" +[node name="UseItemIndicator" type="Node2D" parent="."] +position = Vector2(214, 319) +script = ExtResource("14_b4ll5") +_flyingIndicatorPrefab = ExtResource("15_oy2wu") +_itemTexture = ExtResource("16_k4fcr") + [connection signal="SignalTransitionState" from="FightHappening" to="ActionAnimationController/StateReactionActionAnimation" method="FightHappeningStateTransitioned"] [connection signal="SignalTransitionState" from="FightHappening" to="FightVisuals" method="FightHappeningStateChange"] [connection signal="SignalTransitionState" from="FightHappening" to="ActionSelect/StateReactionInputActionSelect" method="FightHappeningStateTransitioned"] @@ -221,4 +243,5 @@ text = "Hello world" [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="OnStateEntered" from="ActionSelect/StateReactionInputActionSelect" to="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3/Talk Button" method="UpdateText"] [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 ba3a569..ce9ae55 100644 --- a/scenes/Babushka_scene_fight_world_room.tscn +++ b/scenes/Babushka_scene_fight_world_room.tscn @@ -40,6 +40,7 @@ [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"] +[ext_resource type="PackedScene" uid="uid://dpbbroif2tnil" path="res://prefabs/interactions/generic_item_on_ground_2d.tscn" id="41_x3yi1"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_ruj2u"] shader = ExtResource("16_0fard") @@ -2175,6 +2176,7 @@ _sceneRoot = NodePath("..") 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") +_itemOnGroundPrefab = ExtResource("41_x3yi1") _fightSceneSwitcher = NodePath("../FightSceneSwitcher") [editable path="YSorted/Vesna"] diff --git a/scripts/CSharp/Common/Fight/ActionAnimationController.cs b/scripts/CSharp/Common/Fight/ActionAnimationController.cs index 04621fa..2d84378 100644 --- a/scripts/CSharp/Common/Fight/ActionAnimationController.cs +++ b/scripts/CSharp/Common/Fight/ActionAnimationController.cs @@ -11,11 +11,11 @@ public partial class ActionAnimationController : Node #endregion [Export] private AllFightersVisual _allFightersVisual = null!; - + [Export] private FightHappeningAnimationContext _animationContext = null!; public void StateEnter() { - _ = HappeningData.actionStaging!.AnimateAction(_allFightersVisual); + _ = HappeningData.actionStaging!.AnimateAction(_allFightersVisual,_animationContext); } public void StateExit() diff --git a/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs b/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs index e67a7f2..857e7b6 100644 --- a/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs +++ b/scripts/CSharp/Common/Fight/Actions/AllyAttackAction.cs @@ -47,10 +47,11 @@ public class AllyAttackAction : FighterAction public override void ExecuteAction() { var totalDamage = minigameDetail.damageHits!.Sum(dh => dh); - targetSelect.GetTarget().AddHealth(-totalDamage); + targetSelect.GetTarget().ChangeHealth(-totalDamage); } - public override async Task AnimateAction(AllFightersVisual allFightersVisual) + public override async Task AnimateAction(AllFightersVisual allFightersVisual, + FightHappeningAnimationContext animationContext) { var currentFighter = HappeningData.fighterTurn.Current; var targetFighter = targetSelect.GetTarget(); @@ -63,7 +64,7 @@ public class AllyAttackAction : FighterAction foreach (var hit in minigameDetail.damageHits!) { - targetFighterVisual.SpawnDamageIndicatorNumber(hit); + targetFighterVisual.SpawnDamageIndicatorNumber($"-{hit}"); } await currentFighterVisual.AnimatePosToBase(); diff --git a/scripts/CSharp/Common/Fight/Actions/BlobAttackAction.cs b/scripts/CSharp/Common/Fight/Actions/BlobAttackAction.cs index f0e7f90..009b16c 100644 --- a/scripts/CSharp/Common/Fight/Actions/BlobAttackAction.cs +++ b/scripts/CSharp/Common/Fight/Actions/BlobAttackAction.cs @@ -18,10 +18,11 @@ public class BlobAttackAction(int damage = 3) : FighterAction public override void ExecuteAction() { - FightWorld.Instance.allyFighters.vesnaFighter.AddHealth(-damage); + FightWorld.Instance.allyFighters.vesnaFighter.ChangeHealth(-damage); } - public override async Task AnimateAction(AllFightersVisual allFightersVisual) + public override async Task AnimateAction(AllFightersVisual allFightersVisual, + FightHappeningAnimationContext animationContext) { var currentFighter = HappeningData.fighterTurn.Current; var targetFighter = FightWorld.Instance.allyFighters.vesnaFighter; @@ -31,7 +32,7 @@ public class BlobAttackAction(int damage = 3) : FighterAction await currentFighterVisual.AnimatePosToTarget(targetFighterVisual); _ = targetFighterVisual.AnimateHit(); - targetFighterVisual.SpawnDamageIndicatorNumber(damage); + targetFighterVisual.SpawnDamageIndicatorNumber($"-{damage}"); await currentFighterVisual.AnimatePosToBase(); } } \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/Actions/EatBeetrootAction.cs b/scripts/CSharp/Common/Fight/Actions/EatBeetrootAction.cs new file mode 100644 index 0000000..791488b --- /dev/null +++ b/scripts/CSharp/Common/Fight/Actions/EatBeetrootAction.cs @@ -0,0 +1,48 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Babushka.scripts.CSharp.Common.Inventory; +using Babushka.scripts.CSharp.Common.Util; + +namespace Babushka.scripts.CSharp.Common.Fight.Actions; + +public class EatBeetrootAction : FighterAction +{ + public override Variant> GetAnimationEnd() => 1; + public override bool NextDetail() => false; + + private const int HealAmount = 20; + + public override bool ShouldAbort() + { + Debug.Assert(FightWorld.Instance.itemBeetrootToEatForHealth != null, + "Item to eat for health has not been set in the FightWorld autoload"); + return !InventoryManager.Instance.playerInventory!.HasItems(new ItemInstance + { blueprint = FightWorld.Instance.itemBeetrootToEatForHealth }); + } + + public override async Task AnimateAction(AllFightersVisual allFightersVisual, + FightHappeningAnimationContext animationContext) + { + var fighter = HappeningData.fighterTurn.Current; + var fighterVisual = allFightersVisual.GetVisualForFighter(fighter); + fighterVisual.SpawnDamageIndicatorNumber($"+{HealAmount}"); + animationContext.useHealItemIndicator.SpawnIndicator(); + await fighterVisual.AnimateHeal(); + } + + public override void ExecuteAction() + { + var fighter = HappeningData.fighterTurn.Current; + + var result = InventoryManager.Instance.playerInventory!.TryRemoveAllItems( + new ItemInstance { blueprint = FightWorld.Instance.itemBeetrootToEatForHealth! }); + + if (result != InventoryActionResult.Success) + throw new Exception("No Beetroot in inventory. This case should have been handled earlier"); + + fighter.ChangeHealth(HealAmount); + } + + public override AllyActionButton BindToActionButton() => AllyActionButton.Talk; // Temporarily bound to talk button +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/Actions/EatBeetrootAction.cs.uid b/scripts/CSharp/Common/Fight/Actions/EatBeetrootAction.cs.uid new file mode 100644 index 0000000..88e4809 --- /dev/null +++ b/scripts/CSharp/Common/Fight/Actions/EatBeetrootAction.cs.uid @@ -0,0 +1 @@ +uid://b2463q1waqvdu diff --git a/scripts/CSharp/Common/Fight/AllyFighters.cs b/scripts/CSharp/Common/Fight/AllyFighters.cs index 2881ee7..f10fcff 100644 --- a/scripts/CSharp/Common/Fight/AllyFighters.cs +++ b/scripts/CSharp/Common/Fight/AllyFighters.cs @@ -10,7 +10,8 @@ public class AllyFighters maxHealth = 60, availableActions = [ - new AllyAttackAction() + new AllyAttackAction(), + new EatBeetrootAction() ] }; public FightWorld.Fighter chuhaFighter = new() diff --git a/scripts/CSharp/Common/Fight/FightHappening.cs b/scripts/CSharp/Common/Fight/FightHappening.cs index 328710c..aadb417 100644 --- a/scripts/CSharp/Common/Fight/FightHappening.cs +++ b/scripts/CSharp/Common/Fight/FightHappening.cs @@ -222,9 +222,9 @@ public partial class FightHappening : Node case FightState.ActionCheckDetails: RequireNotNull(HappeningData.actionStaging); - if (ActionAbort()) + if (ShouldActionAbort()) ChangeState(FightState.InputActionSelect); - else if (ActionNeededDetail()) + else if (DoesActionNeededDetail()) ChangeState(FightState.InputActionDetail); else ChangeState(FightState.ActionExecute); @@ -328,13 +328,13 @@ public partial class FightHappening : Node return HappeningData.actionStaging.GetAnimationEnd(); } - private bool ActionAbort() + private bool ShouldActionAbort() { Debug.Assert(HappeningData.actionStaging != null); - return HappeningData.actionStaging.MarkedForAbort(); + return HappeningData.actionStaging.ShouldAbort(); } - private bool ActionNeededDetail() + private bool DoesActionNeededDetail() { Debug.Assert(HappeningData.actionStaging != null); return HappeningData.actionStaging.NextDetail(); @@ -344,7 +344,7 @@ public partial class FightHappening : Node private void ReviveVesna() { var vesnaFighter = FightWorld.Instance.allyFighters.vesnaFighter; - vesnaFighter.health = vesnaFighter.maxHealth; + vesnaFighter.Health = vesnaFighter.maxHealth; GD.Print("Vesna has been revived. This is for the current prototype only"); } diff --git a/scripts/CSharp/Common/Fight/FightHappeningAnimationContext.cs b/scripts/CSharp/Common/Fight/FightHappeningAnimationContext.cs new file mode 100644 index 0000000..8d1d141 --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappeningAnimationContext.cs @@ -0,0 +1,8 @@ +using Godot; + +namespace Babushka.scripts.CSharp.Common.Fight; + +public partial class FightHappeningAnimationContext : Node +{ + [Export] public UsedItemIndicatorVisual useHealItemIndicator = null!; +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FightHappeningAnimationContext.cs.uid b/scripts/CSharp/Common/Fight/FightHappeningAnimationContext.cs.uid new file mode 100644 index 0000000..3c6c81c --- /dev/null +++ b/scripts/CSharp/Common/Fight/FightHappeningAnimationContext.cs.uid @@ -0,0 +1 @@ +uid://cdrjvgm82pxoj diff --git a/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs b/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs index de19a5c..4ffe14c 100644 --- a/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs +++ b/scripts/CSharp/Common/Fight/FightRoomSceneSetup.cs @@ -1,15 +1,16 @@ using System.Collections.Generic; using System.Linq; -using Babushka.scripts.CSharp.Common.Util; +using Babushka.scripts.CSharp.Common.Inventory; using Godot; namespace Babushka.scripts.CSharp.Common.Fight; public partial class FightRoomSceneSetup : Node { - [Export(PropertyHint.ArrayType)] private Node2D[] _enemyGroupSpawns; - [Export] private PackedScene _roamingEnemyGroupPrefab; - [Export] private FightSceneSwitcher _fightSceneSwitcher; + [Export(PropertyHint.ArrayType)] private Node2D[] _enemyGroupSpawns = null!; + [Export] private PackedScene _roamingEnemyGroupPrefab = null!; + [Export] private PackedScene _itemOnGroundPrefab = null!; + [Export] private FightSceneSwitcher _fightSceneSwitcher = null!; public override void _Ready() @@ -19,11 +20,30 @@ public partial class FightRoomSceneSetup : Node foreach (var (parent, group) in _enemyGroupSpawns.Zip(room.enemyGroups)) { if (group.AreAllDead()) - continue; - - var roamingEnemyGroup = _roamingEnemyGroupPrefab.Instantiate(); - roamingEnemyGroup.Initialize(group, _fightSceneSwitcher); - parent.AddChild(roamingEnemyGroup); + { + SpawnLoot(group, parent); + } + else + { + SpawnEnemies(group, parent); + } } } + + private void SpawnEnemies(FightWorld.FighterGroup group, Node2D parent) + { + var roamingEnemyGroup = _roamingEnemyGroupPrefab.Instantiate(); + roamingEnemyGroup.Initialize(group, _fightSceneSwitcher); + parent.AddChild(roamingEnemyGroup); + } + + private void SpawnLoot(FightWorld.FighterGroup group, Node2D parent) + { + if (group.lootToDrop == null) + return; + + var onGroundInstance = _itemOnGroundPrefab.Instantiate(); + onGroundInstance.itemInstance = group.lootToDrop; + parent.AddChild(onGroundInstance); + } } \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FightUtils.cs b/scripts/CSharp/Common/Fight/FightUtils.cs index 52d33af..978f197 100644 --- a/scripts/CSharp/Common/Fight/FightUtils.cs +++ b/scripts/CSharp/Common/Fight/FightUtils.cs @@ -10,15 +10,16 @@ public static class FightUtils { return self.Where(e => e.IsAlive()); } - - public static IEnumerable WhereIsNotInFormation(this IEnumerable self, FighterFormation formation) + + public static IEnumerable WhereIsNotInFormation(this IEnumerable self, + FighterFormation formation) { return self.Where(e => !e.IsInFormation(formation)); } public static bool IsAlive(this FightWorld.Fighter self) { - return self.GetHealth() > 0; + return self.Health > 0; } public static bool IsDead(this FightWorld.Fighter self) @@ -26,16 +27,16 @@ public static class FightUtils return !self.IsAlive(); } - public static int GetHealth(this FightWorld.Fighter self) + /// + /// Changes the health of a fighter + /// + /// The fighter itself + /// The amount of health to add. Make negative to remove health + public static void ChangeHealth(this FightWorld.Fighter self, int amount) { - return Math.Max(self.health ?? self.maxHealth, 0); + self.Health += amount; } - public static void AddHealth(this FightWorld.Fighter self, int addHealth) - { - self.health = self.GetHealth() + addHealth; - } - public static bool IsInFormation(this FightWorld.Fighter self, FighterFormation formation) { return formation.ContainsFighter(self); diff --git a/scripts/CSharp/Common/Fight/FightWorld.cs b/scripts/CSharp/Common/Fight/FightWorld.cs index 083b60f..fc3e19d 100644 --- a/scripts/CSharp/Common/Fight/FightWorld.cs +++ b/scripts/CSharp/Common/Fight/FightWorld.cs @@ -1,5 +1,7 @@ +using System; using System.Collections.Generic; using Babushka.scripts.CSharp.Common.Fight.Actions; +using Babushka.scripts.CSharp.Common.Inventory; using Babushka.scripts.CSharp.Common.Util; using Godot; @@ -19,6 +21,7 @@ public partial class FightWorld : Node None, EndOfNight } + public required Dictionary paths; public required List enemyGroups; public Special specialRoom = Special.None; @@ -27,6 +30,7 @@ public partial class FightWorld : Node public class FighterGroup { public required List fighters; + public ItemInstance? lootToDrop = null; } public class FightHappeningData @@ -56,9 +60,17 @@ public partial class FightWorld : Node public required int maxHealth; public required List availableActions; public const int MaxActionPoints = 1; - public int? health = null; // null => initialize to full health on spawn public int actionPointsLeft; + private int? _healthBacking = null; + + public int Health + { + get => _healthBacking ?? maxHealth; + set => _healthBacking = Math.Clamp(value, 0, maxHealth); + } + + public FighterAction AutoSelectAction() { return availableActions.Random() ?? new FighterAction.Skip(); @@ -81,6 +93,10 @@ public partial class FightWorld : Node public FightHappeningData? fightHappeningData = null; public AllyFighters allyFighters = new(); + // settings + [Export] private ItemResource? _itemToDropByEnemyGroup; + [Export] public ItemResource? itemBeetrootToEatForHealth; + public void ResetFightWorld() { Generate(); @@ -89,10 +105,10 @@ public partial class FightWorld : Node public void Generate() { - world = new Generator().GenerateWorld(); + world = new Generator(this).GenerateWorld(); } - private class Generator + private class Generator(FightWorld fightWorld) { public World GenerateWorld() { @@ -113,7 +129,7 @@ public partial class FightWorld : Node { rooms.Add(GenerateDisconnectedRoom()); } - + rooms.Add(new Room { paths = [], @@ -162,6 +178,11 @@ public partial class FightWorld : Node fighters = [] }; + if (fightWorld._itemToDropByEnemyGroup != null) + { + enemyGroup.lootToDrop = new ItemInstance { blueprint = fightWorld._itemToDropByEnemyGroup }; + } + var enemyCount = GD.RandRange(2, 3); for (var i = 0; i < enemyCount; i++) @@ -189,7 +210,6 @@ public partial class FightWorld : Node var enemy = new Fighter { type = type, - health = null, maxHealth = GD.RandRange(8, 20), availableActions = [ diff --git a/scripts/CSharp/Common/Fight/FighterAction.cs b/scripts/CSharp/Common/Fight/FighterAction.cs index 789120d..cbaf939 100644 --- a/scripts/CSharp/Common/Fight/FighterAction.cs +++ b/scripts/CSharp/Common/Fight/FighterAction.cs @@ -30,8 +30,6 @@ public abstract class FighterAction public abstract bool DetailComplete(); } - private bool _abort = false; - #region Shortcuts protected static FightWorld.FightHappeningData HappeningData => @@ -61,19 +59,13 @@ public abstract class FighterAction /// Animates the action. /// /// - public virtual async Task AnimateAction(AllFightersVisual allFightersVisual) - { - } - - public void MarkAbort() + /// + public virtual async Task AnimateAction(AllFightersVisual allFightersVisual, + FightHappeningAnimationContext animationContext) { - _abort = true; } - public bool MarkedForAbort() - { - return _abort; - } + public virtual bool ShouldAbort() => false; /// /// Returns the FighterActionDetail, that is currently handled. diff --git a/scripts/CSharp/Common/Fight/FighterDamageIndicatorVisual.cs b/scripts/CSharp/Common/Fight/FighterDamageIndicatorVisual.cs index 4e79ac4..88aeddb 100644 --- a/scripts/CSharp/Common/Fight/FighterDamageIndicatorVisual.cs +++ b/scripts/CSharp/Common/Fight/FighterDamageIndicatorVisual.cs @@ -4,13 +4,13 @@ namespace Babushka.scripts.CSharp.Common.Fight; public partial class FighterDamageIndicatorVisual : Node2D { - [Export] private PackedScene _flyingNumberPrefab; + [Export] private PackedScene _flyingNumberPrefab = null!; - public void SpawnFlyingNumber(int number) + public void SpawnFlyingNumber(string text) { - var flyingNumberInstance = _flyingNumberPrefab.Instantiate(); + var flyingNumberInstance = _flyingNumberPrefab.Instantiate(); AddChild(flyingNumberInstance); - flyingNumberInstance.Initialize(number); + flyingNumberInstance.Initialize(text); } } \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FighterVisual.cs b/scripts/CSharp/Common/Fight/FighterVisual.cs index 9e3b7ab..73b5621 100644 --- a/scripts/CSharp/Common/Fight/FighterVisual.cs +++ b/scripts/CSharp/Common/Fight/FighterVisual.cs @@ -42,7 +42,12 @@ public partial class FighterVisual : Node2D _boundFighter.IsInFormation(HappeningData.enemyFighterFormation) ? -1 : 1, _boundFighter.IsDead() ? .3f : 1); - healthBarVisual.UpdateHealth(_boundFighter.GetHealth(), _boundFighter.maxHealth); + UpdateHealthBarVisuals(); + } + + private void UpdateHealthBarVisuals() + { + healthBarVisual.UpdateHealth(_boundFighter.Health, _boundFighter.maxHealth); } public void SetTargetSelectionActive(bool value) @@ -78,24 +83,26 @@ public partial class FighterVisual : Node2D public async Task AnimateHit() { + UpdateHealthBarVisuals(); var tween = GetTree().CreateTween(); tween.TweenProperty(_squashParent, "scale", new Vector2(1.4f, 0.6f), 0.15); tween.TweenProperty(_squashParent, "scale", new Vector2(1, 1), 0.4) .SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out); await ToSignal(tween, "finished"); } - - // Keep for reference for new Heal animation - //public void HealAnimation() - //{ - // EmitSignalHealed(); - // var tween = GetTree().CreateTween(); - // tween.TweenProperty(this, "scale", new Vector2(0.6f, 1.4f), 0.15); - // tween.TweenProperty(this, "scale", new Vector2(1, 1), 0.4) - // .SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out); - //} - public void SpawnDamageIndicatorNumber(int number) + + public async Task AnimateHeal() + { + UpdateHealthBarVisuals(); + var tween = GetTree().CreateTween(); + tween.TweenProperty(_squashParent, "scale", new Vector2(0.6f, 1.4f), 0.15); + tween.TweenProperty(_squashParent, "scale", new Vector2(1, 1), 0.4) + .SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out); + await ToSignal(tween, "finished"); + } + + public void SpawnDamageIndicatorNumber(string text) { - _fighterDamageIndicatorVisual.SpawnFlyingNumber(number); + _fighterDamageIndicatorVisual.SpawnFlyingNumber(text); } } \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/FighterDamageIndicatorFlyingNumber.cs b/scripts/CSharp/Common/Fight/FlyingIndicator.cs similarity index 57% rename from scripts/CSharp/Common/Fight/FighterDamageIndicatorFlyingNumber.cs rename to scripts/CSharp/Common/Fight/FlyingIndicator.cs index e833d67..0ea0b24 100644 --- a/scripts/CSharp/Common/Fight/FighterDamageIndicatorFlyingNumber.cs +++ b/scripts/CSharp/Common/Fight/FlyingIndicator.cs @@ -3,13 +3,19 @@ using Godot; namespace Babushka.scripts.CSharp.Common.Fight; -public partial class FighterDamageIndicatorFlyingNumber : Node2D +public partial class FlyingIndicator : Node2D { - [Export] private Label _label; - - public void Initialize(int number) + [Export] private Label _label = null!; + [Export] private TextureRect _sprite = null!; + + + public void Initialize(string? text = null, Texture2D? icon = null) { - _label.Text = number.ToString(); + _label.Visible = text != null; + _sprite.Visible = icon != null; + + if (text != null) _label.Text = text; + if (icon != null) _sprite.Texture = icon; var tween = CreateTween(); var xMovement = GD.RandRange(-150, 150); diff --git a/scripts/CSharp/Common/Fight/FighterDamageIndicatorFlyingNumber.cs.uid b/scripts/CSharp/Common/Fight/FlyingIndicator.cs.uid similarity index 100% rename from scripts/CSharp/Common/Fight/FighterDamageIndicatorFlyingNumber.cs.uid rename to scripts/CSharp/Common/Fight/FlyingIndicator.cs.uid diff --git a/scripts/CSharp/Common/Fight/UI/HealButtonVisual.cs b/scripts/CSharp/Common/Fight/UI/HealButtonVisual.cs new file mode 100644 index 0000000..7cc8a4a --- /dev/null +++ b/scripts/CSharp/Common/Fight/UI/HealButtonVisual.cs @@ -0,0 +1,15 @@ +using Babushka.scripts.CSharp.Common.Inventory; +using Godot; + +namespace Babushka.scripts.CSharp.Common.Fight.UI; + +public partial class HealButtonVisual : Button +{ + [Export] private ItemResource _healItemBlueprint = null!; + + public void UpdateText() + { + var healItemsLeft = InventoryManager.Instance.playerInventory!.TotalItemsOfBlueprint(_healItemBlueprint); + Text = $"x{healItemsLeft} - Heal"; + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/UI/HealButtonVisual.cs.uid b/scripts/CSharp/Common/Fight/UI/HealButtonVisual.cs.uid new file mode 100644 index 0000000..2634d19 --- /dev/null +++ b/scripts/CSharp/Common/Fight/UI/HealButtonVisual.cs.uid @@ -0,0 +1 @@ +uid://71mdwp2m4rta diff --git a/scripts/CSharp/Common/Fight/UsedItemIndicatorVisual.cs b/scripts/CSharp/Common/Fight/UsedItemIndicatorVisual.cs new file mode 100644 index 0000000..286fd94 --- /dev/null +++ b/scripts/CSharp/Common/Fight/UsedItemIndicatorVisual.cs @@ -0,0 +1,17 @@ +using Godot; + +namespace Babushka.scripts.CSharp.Common.Fight; + +public partial class UsedItemIndicatorVisual : Node2D +{ + [Export] private PackedScene _flyingIndicatorPrefab = null!; + [Export] private Texture2D _itemTexture = null!; + + + public void SpawnIndicator() + { + var flyingNumberInstance = _flyingIndicatorPrefab.Instantiate(); + AddChild(flyingNumberInstance); + flyingNumberInstance.Initialize(icon: _itemTexture); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Fight/UsedItemIndicatorVisual.cs.uid b/scripts/CSharp/Common/Fight/UsedItemIndicatorVisual.cs.uid new file mode 100644 index 0000000..168d3df --- /dev/null +++ b/scripts/CSharp/Common/Fight/UsedItemIndicatorVisual.cs.uid @@ -0,0 +1 @@ +uid://6nniwfxye8ss diff --git a/scripts/CSharp/Common/Inventory/InventoryInstance.cs b/scripts/CSharp/Common/Inventory/InventoryInstance.cs index 55fb944..431ec45 100644 --- a/scripts/CSharp/Common/Inventory/InventoryInstance.cs +++ b/scripts/CSharp/Common/Inventory/InventoryInstance.cs @@ -17,7 +17,7 @@ public partial class InventoryInstance : Node, ISaveable [Signal] public delegate void InventoryContentsChangedEventHandler(); - + public static string ID = "inventoryInstance"; /// @@ -52,7 +52,7 @@ public partial class InventoryInstance : Node, ISaveable SlotAmountChanged += UpdateSaveData; SavegameService.OnSaveGameReset += SaveGameReset; } - + public override void _ExitTree() { InventoryContentsChanged -= UpdateSaveData; @@ -101,7 +101,8 @@ public partial class InventoryInstance : Node, ISaveable return InventoryActionResult.DestinationFull; } - var itemInstance = _slots[slotIndex].itemInstance ?? new ItemInstance { blueprint = newItem.blueprint, amount = 0 }; + var itemInstance = _slots[slotIndex].itemInstance ?? + new ItemInstance { blueprint = newItem.blueprint, amount = 0 }; var maxStack = itemInstance!.blueprint.maxStack; var freeOnStack = maxStack - itemInstance.amount; var moveAmount = Math.Min(freeOnStack, newItem.amount); @@ -130,12 +131,12 @@ public partial class InventoryInstance : Node, ISaveable itemInstance = _slots[inventorySlot].itemInstance; if (itemInstance == null) return InventoryActionResult.SourceDoesNotExist; - + itemInstance.amount -= 1; - - if(itemInstance.amount == 0) + + if (itemInstance.amount == 0) _slots[inventorySlot].itemInstance = null; - + EmitSignal(SignalName.InventoryContentsChanged); return InventoryActionResult.Success; } @@ -145,6 +146,38 @@ public partial class InventoryInstance : Node, ISaveable return RemoveItem(inventorySlot, out _); } + public InventoryActionResult TryRemoveAllItems(ItemInstance items) + { + var hasItemsCount = TotalItemsOfBlueprint(items.blueprint); + if (hasItemsCount < items.amount) + return InventoryActionResult.SourceDoesNotExist; + + var amountToRemove = items.amount; + foreach (var s in _slots) + { + if (s.IsEmpty() || s.itemInstance!.blueprint != items.blueprint) + continue; + + var slotItem = s.itemInstance!; + if (slotItem.amount <= amountToRemove) + { + amountToRemove -= slotItem.amount; + s.itemInstance = null; + } + else + { + slotItem.amount -= amountToRemove; + amountToRemove = 0; + } + + if (amountToRemove == 0) + break; + } + + EmitSignal(SignalName.InventoryContentsChanged); + return InventoryActionResult.Success; + } + public InventoryActionResult AddItemToSlot(ItemInstance itemInstance, int destinationSlot) { if (destinationSlot < 0 || destinationSlot >= _slots.Count) @@ -174,8 +207,8 @@ public partial class InventoryInstance : Node, ISaveable { return items.All(HasItems); } - - #region SAVE AND LOAD + + #region SAVE AND LOAD public void UpdateSaveData() { @@ -189,17 +222,17 @@ public partial class InventoryInstance : Node, ISaveable string[] value = new string[2]; value[0] = _slots[i].itemInstance.blueprint.ResourcePath; value[1] = _slots[i].itemInstance.amount.ToString(); - payloadData.Add(key,value); + payloadData.Add(key, value); } } - + SavegameService.AppendDataToSave(ID, payloadData); } public void LoadFromSaveData() { var id = ID; - + Godot.Collections.Dictionary save = SavegameService.GetSaveData(id); if (save.Count > 0) @@ -210,15 +243,15 @@ public partial class InventoryInstance : Node, ISaveable { string[] savePayload = inventoryItemData.AsStringArray(); ItemResource resource = ResourceLoader.Load(savePayload[0]); - int _amount = int.Parse(savePayload[1]); - + int _amount = int.Parse(savePayload[1]); + ItemInstance instance = new ItemInstance { blueprint = resource, amount = _amount }; AddItem(instance); } } } } - + /// /// Called when a new save is created. /// Needs to do a runtime check because the InventoryInstance is already in existence at the beginning of the first scene. @@ -230,5 +263,6 @@ public partial class InventoryInstance : Node, ISaveable slot.itemInstance = null; } } + #endregion -} +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Inventory/ItemInstance.cs b/scripts/CSharp/Common/Inventory/ItemInstance.cs index f541e97..f0dd765 100644 --- a/scripts/CSharp/Common/Inventory/ItemInstance.cs +++ b/scripts/CSharp/Common/Inventory/ItemInstance.cs @@ -6,7 +6,7 @@ namespace Babushka.scripts.CSharp.Common.Inventory; [GlobalClass] public partial class ItemInstance: Resource { - [Export] public ItemResource blueprint; + [Export] public required ItemResource blueprint; [Export] public int amount = 1; public ItemInstance Clone()