Fight rework premature merge #22

Merged
Jonathan merged 16 commits from feature/fight_rework into develop 2025-11-04 10:25:14 +01:00
13 changed files with 127 additions and 54 deletions
Showing only changes of commit 83dc6bfd56 - Show all commits
+1 -2
View File
@@ -2,8 +2,7 @@
[ext_resource type="Script" uid="uid://cql8mt5jsmcdl" path="res://scripts/CSharp/Common/Fight/FightSceneSwitcher.cs" id="1_5dt1r"] [ext_resource type="Script" uid="uid://cql8mt5jsmcdl" path="res://scripts/CSharp/Common/Fight/FightSceneSwitcher.cs" id="1_5dt1r"]
[node name="FightSceneSwitcher" type="Node" node_paths=PackedStringArray("_sceneRoot")] [node name="FightSceneSwitcher" type="Node"]
script = ExtResource("1_5dt1r") script = ExtResource("1_5dt1r")
_sceneRoot = NodePath("")
_fightRoomScenePath = "res://scenes/Babushka_scene_fight_world_room.tscn" _fightRoomScenePath = "res://scenes/Babushka_scene_fight_world_room.tscn"
_fightHappeningScene = "res://scenes/Babushka_scene_fight_happening.tscn" _fightHappeningScene = "res://scenes/Babushka_scene_fight_happening.tscn"
@@ -52,7 +52,7 @@ public class AllyAttackAction : FighterAction
public override async Task AnimateAction(AllFightersVisual allFightersVisual) public override async Task AnimateAction(AllFightersVisual allFightersVisual)
{ {
var currentFighter = HappeningData.fighterStack.Current; var currentFighter = HappeningData.fighterTurn.Current;
var targetFighter = targetSelect.GetTarget(); var targetFighter = targetSelect.GetTarget();
var currentFighterVisual = allFightersVisual.GetVisualForFighter(currentFighter); var currentFighterVisual = allFightersVisual.GetVisualForFighter(currentFighter);
2
@@ -23,7 +23,7 @@ public class BlobAttackAction : FighterAction
public override async Task AnimateAction(AllFightersVisual allFightersVisual) public override async Task AnimateAction(AllFightersVisual allFightersVisual)
{ {
var currentFighter = HappeningData.fighterStack.Current; var currentFighter = HappeningData.fighterTurn.Current;
var targetFighter = FightWorld.Instance.allyFighters.vesnaFighter; var targetFighter = FightWorld.Instance.allyFighters.vesnaFighter;
var currentFighterVisual = allFightersVisual.GetVisualForFighter(currentFighter); var currentFighterVisual = allFightersVisual.GetVisualForFighter(currentFighter);
@@ -1,10 +1,11 @@
using Godot;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Babushka.scripts.CSharp.Common.Fight;
using Babushka.scripts.CSharp.Common.Fight.ActionDetails; using Babushka.scripts.CSharp.Common.Fight.ActionDetails;
using Babushka.scripts.CSharp.Common.Util; using Babushka.scripts.CSharp.Common.Util;
using Godot;
namespace Babushka.scripts.CSharp.Common.Fight;
public partial class AllFightersVisual : Node public partial class AllFightersVisual : Node
Jonathan marked this conversation as resolved Outdated
Outdated
Review

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

Diese Klasse managed das Layout der Kampfszene, oder? Das Naming hatte mich etwas verwirrt.
{ {
@@ -112,10 +113,14 @@ public partial class AllFightersVisual : Node
private void ShowTargetSelect(TargetSelectActionDetail targetDetail) private void ShowTargetSelect(TargetSelectActionDetail targetDetail)
{ {
if (targetDetail.selectEnemy) if (targetDetail.selectEnemy)
_fighterVisuals.Where(kv => kv.Key.isEnemy).ForEach(kv => kv.Value.SetTargetSelectionActive(true)); _fighterVisuals
.Where(kv => kv.Key.IsInFormation(HappeningData.enemyFighterFormation))
.ForEach(kv => kv.Value.SetTargetSelectionActive(true));
if (targetDetail.selectAlly) if (targetDetail.selectAlly)
_fighterVisuals.Where(kv => !kv.Key.isEnemy).ForEach(kv => kv.Value.SetTargetSelectionActive(true)); _fighterVisuals
.Where(kv => kv.Key.IsInFormation(HappeningData.allyFighterFormation))
.ForEach(kv => kv.Value.SetTargetSelectionActive(true));
} }
private void HideTargetSelect() private void HideTargetSelect()
@@ -8,7 +8,6 @@ public class AllyFighters
{ {
type = FightWorld.Fighter.Type.Vesna, type = FightWorld.Fighter.Type.Vesna,
maxHealth = 20, maxHealth = 20,
isEnemy = false,
availableActions = availableActions =
[ [
new AllyAttackAction() new AllyAttackAction()
@@ -18,7 +17,6 @@ public class AllyFighters
{ {
type = FightWorld.Fighter.Type.Chuha, type = FightWorld.Fighter.Type.Chuha,
maxHealth = 15, maxHealth = 15,
isEnemy = false,
availableActions = availableActions =
[ [
new FighterAction.Skip() new FighterAction.Skip()
+32 -13
View File
@@ -61,7 +61,7 @@ public partial class FightHappening : Node
private static FightWorld.FightHappeningData HappeningData => private static FightWorld.FightHappeningData HappeningData =>
FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException(); FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException();
private static FightWorld.Fighter CurrentFighter => HappeningData.fighterStack.Current; private static FightWorld.Fighter CurrentFighter => HappeningData.fighterTurn.Current;
#endregion #endregion
@@ -204,7 +204,7 @@ public partial class FightHappening : Node
{ {
ChangeState(FightState.FightersEnter); ChangeState(FightState.FightersEnter);
} }
else if (CurrentFighter.isEnemy) else if (CurrentFighter.IsInFormation(HappeningData.enemyFighterFormation))
{ {
ChangeState(FightState.EnemyActionSelect); ChangeState(FightState.EnemyActionSelect);
} }
@@ -249,10 +249,15 @@ public partial class FightHappening : Node
_ = AdvanceToStateWhenDone(FightState.StateCheck, actionTime); _ = AdvanceToStateWhenDone(FightState.StateCheck, actionTime);
} }
break;
case FightState.EnemyWin:
// TODO: remove and find proper solution
ReviveVesna();
break; break;
default: break; default: break;
} }
} }
#endregion #endregion
#region Game Logic #region Game Logic
@@ -262,19 +267,23 @@ public partial class FightHappening : Node
// ally // ally
var enteringAllyFighters = new List<FightWorld.Fighter>(); var enteringAllyFighters = new List<FightWorld.Fighter>();
var allyFighters = FightWorld.Instance.allyFighters; var allyFighters = FightWorld.Instance.allyFighters;
if (!allyFighters.vesnaFighter.entered) if (!allyFighters.vesnaFighter.IsInFormation(HappeningData.allyFighterFormation))
{ {
enteringAllyFighters.Add(allyFighters.vesnaFighter); enteringAllyFighters.Add(allyFighters.vesnaFighter);
} }
// enemy // enemy
const int totalEnemySpace = 3; const int totalEnemySpace = 3;
var enemySpaceLeft = totalEnemySpace - HappeningData.enemyGroup.GetEnteredAmount(); var enemySpaceLeft = HappeningData.enemyFighterFormation.GetEmptySlotCount();
return new FightersEnterStaging return new FightersEnterStaging
{ {
enteringAllyFighters = enteringAllyFighters, enteringAllyFighters = enteringAllyFighters,
enteringEnemyFighters = HappeningData.enemyGroup.GetUptoUnenteredFighters(enemySpaceLeft).ToList() enteringEnemyFighters = HappeningData.enemyGroup.fighters
.WhereIsAlive()
.WhereIsNotInFormation(HappeningData.enemyFighterFormation)
.Take(enemySpaceLeft)
.ToList()
}; };
} }
@@ -283,21 +292,25 @@ public partial class FightHappening : Node
Debug.Assert(HappeningData.fightersEnterStaging != null); Debug.Assert(HappeningData.fightersEnterStaging != null);
foreach (var fighter in HappeningData.fightersEnterStaging.enteringAllyFighters) foreach (var fighter in HappeningData.fightersEnterStaging.enteringAllyFighters)
{ {
fighter.entered = true; var emptySlotIndex = HappeningData.allyFighterFormation.GetFirstEmptySlot();
HappeningData.fighterStack.AddAsLast(fighter); if (emptySlotIndex < 0) throw new Exception("No empty slot for ally fighter to enter");
HappeningData.allyFighterFormation.SetFighterAtPosition(emptySlotIndex, fighter);
HappeningData.fighterTurn.AddAsLast(fighter);
} }
foreach (var fighter in HappeningData.fightersEnterStaging.enteringEnemyFighters) foreach (var fighter in HappeningData.fightersEnterStaging.enteringEnemyFighters)
{ {
fighter.entered = true; var emptySlotIndex = HappeningData.enemyFighterFormation.GetFirstEmptySlot();
HappeningData.fighterStack.AddAsLast(fighter); if (emptySlotIndex < 0) throw new Exception("No empty slot for enemy fighter to enter");
HappeningData.enemyFighterFormation.SetFighterAtPosition(emptySlotIndex, fighter);
HappeningData.fighterTurn.AddAsLast(fighter);
} }
} }
private void ExecuteNextFighter() private void ExecuteNextFighter()
{ {
HappeningData.fighterStack.Next(); HappeningData.fighterTurn.Next();
CurrentFighter.actionPointsLeft = CurrentFighter.maxActionPoints; CurrentFighter.actionPointsLeft = FightWorld.Fighter.MaxActionPoints;
} }
private void ExecuteAction() private void ExecuteAction()
@@ -325,6 +338,14 @@ public partial class FightHappening : Node
return HappeningData.actionStaging.NextDetail(); return HappeningData.actionStaging.NextDetail();
} }
// TODO: remove
private void ReviveVesna()
{
var vesnaFighter = FightWorld.Instance.allyFighters.vesnaFighter;
vesnaFighter.health = vesnaFighter.maxHealth;
GD.Print("Vesna has been revived. This is for the current prototype only");
}
#endregion // Game Logic #endregion // Game Logic
#region Utility #region Utility
@@ -362,6 +383,4 @@ public partial class FightHappening : Node
} }
#endregion #endregion
} }
+10 -13
View File
@@ -6,22 +6,14 @@ namespace Babushka.scripts.CSharp.Common.Fight;
public static class FightUtils public static class FightUtils
{ {
public static int GetEnteredAmount(this FightWorld.FighterGroup self) public static IEnumerable<FightWorld.Fighter> WhereIsAlive(this IEnumerable<FightWorld.Fighter> self)
{ {
return self.enemies.Count(e => e.IsAlive() && e.entered); return self.Where(e => e.IsAlive());
} }
public static IEnumerable<FightWorld.Fighter> GetUptoUnenteredFighters( public static IEnumerable<FightWorld.Fighter> WhereIsNotInFormation(this IEnumerable<FightWorld.Fighter> self, FighterFormation formation)
this FightWorld.FighterGroup self,
int maxFighters)
{ {
if (maxFighters <= self.enemies.Count) return self.Where(e => !e.IsInFormation(formation));
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) public static bool IsAlive(this FightWorld.Fighter self)
@@ -44,8 +36,13 @@ public static class FightUtils
self.health = self.GetHealth() + addHealth; self.health = self.GetHealth() + addHealth;
} }
public static bool IsInFormation(this FightWorld.Fighter self, FighterFormation formation)
{
return formation.ContainsFighter(self);
}
public static bool AreAllDead(this FightWorld.FighterGroup self) public static bool AreAllDead(this FightWorld.FighterGroup self)
{ {
return self.enemies.All(e => e.IsDead()); return self.fighters.All(e => e.IsDead());
} }
} }
+8 -9
View File
@@ -20,14 +20,16 @@ public partial class FightWorld : Node
public class FighterGroup public class FighterGroup
{ {
public required List<Fighter> enemies; public required List<Fighter> fighters;
} }
public class FightHappeningData public class FightHappeningData
{ {
public FightHappening.FightState fightState = FightHappening.FightState.None;
public FighterStack fighterStack = new();
public required FighterGroup enemyGroup; public required FighterGroup enemyGroup;
public FightHappening.FightState fightState = FightHappening.FightState.None;
public readonly FighterTurn fighterTurn = new();
public readonly FighterFormation allyFighterFormation = new();
public readonly FighterFormation enemyFighterFormation = new();
public FightHappening.FightersEnterStaging? fightersEnterStaging; public FightHappening.FightersEnterStaging? fightersEnterStaging;
public FighterAction? actionStaging; public FighterAction? actionStaging;
} }
@@ -46,11 +48,9 @@ public partial class FightWorld : Node
public required Type type; public required Type type;
public required int maxHealth; public required int maxHealth;
public required bool isEnemy;
public required List<FighterAction> availableActions; public required List<FighterAction> availableActions;
public int maxActionPoints = 1; public const int MaxActionPoints = 1;
public int? health = null; // null => initialize to full health on spawn public int? health = null; // null => initialize to full health on spawn
public bool entered = false;
public int actionPointsLeft; public int actionPointsLeft;
public FighterAction AutoSelectAction() public FighterAction AutoSelectAction()
@@ -147,14 +147,14 @@ public partial class FightWorld : Node
{ {
var enemyGroup = new FighterGroup var enemyGroup = new FighterGroup
{ {
enemies = [] fighters = []
}; };
var enemyCount = GD.RandRange(1, 3); var enemyCount = GD.RandRange(1, 3);
for (var i = 0; i < enemyCount; i++) for (var i = 0; i < enemyCount; i++)
{ {
enemyGroup.enemies.Add(GenerateSingleEnemy()); enemyGroup.fighters.Add(GenerateSingleEnemy());
} }
return enemyGroup; return enemyGroup;
@@ -177,7 +177,6 @@ public partial class FightWorld : Node
{ {
type = type, type = type,
health = null, health = null,
isEnemy = true,
maxHealth = 12, maxHealth = 12,
availableActions = availableActions =
[ [
@@ -0,0 +1,56 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Babushka.scripts.CSharp.Common.Fight;
public class FighterFormation
{
private readonly List<FightWorld.Fighter?> _fighters;
public FighterFormation(int slots = 3)
{
_fighters = [];
for (var i = 0; i < slots; i++)
{
_fighters.Add(null);
}
}
public FightWorld.Fighter? GetFighterAtPosition(int position)
{
Debug.Assert(position >= 0, "position>=0");
Debug.Assert(position < _fighters.Count, "position does not exist");
return _fighters[position];
}
public void SetFighterAtPosition(int position, FightWorld.Fighter value)
{
Debug.Assert(position >= 0, "position>=0");
Debug.Assert(position < _fighters.Count, "position does not exist");
_fighters[position] = value;
}
public bool ContainsFighter(FightWorld.Fighter fighter)
{
return _fighters.Contains(fighter);
}
public int GetFirstEmptySlot()
{
for (var i = 0; i < _fighters.Count; i++)
{
if (_fighters[i] == null)
return i;
}
return -1;
}
public int GetEmptySlotCount()
{
return _fighters.Count(fighter => fighter == null);
}
}
@@ -3,7 +3,7 @@ using System.Diagnostics;
namespace Babushka.scripts.CSharp.Common.Fight; namespace Babushka.scripts.CSharp.Common.Fight;
public class FighterStack public class FighterTurn
{ {
private class Node private class Node
{ {
+1 -1
View File
@@ -38,7 +38,7 @@ public partial class FighterVisual : Node2D
/// </summary> /// </summary>
private void UpdateMirrorState() private void UpdateMirrorState()
{ {
_visualParent.Scale = new Vector2(_boundFighter.isEnemy ? -1 : 1, 1); _visualParent.Scale = new Vector2(_boundFighter.IsInFormation(HappeningData.enemyFighterFormation) ? -1 : 1, 1);
} }
public void UpdateHealthBar() public void UpdateHealthBar()
@@ -8,7 +8,7 @@ public partial class ActionSelectUiSetup : CanvasLayer
// shortcuts // shortcuts
private FightWorld.FightHappeningData HappeningData => private FightWorld.FightHappeningData HappeningData =>
FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException(); FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException();
private FightWorld.Fighter CurrentFighter => HappeningData.fighterStack.Current; private FightWorld.Fighter CurrentFighter => HappeningData.fighterTurn.Current;
// references // references
[Export] private Button _attackActionButton = null!; [Export] private Button _attackActionButton = null!;