Made fight fightable

This commit is contained in:
jonathan
2025-09-30 16:23:05 +02:00
parent f27dd199b8
commit 0e315396c9
42 changed files with 889 additions and 251 deletions
+101 -54
View File
@@ -9,7 +9,7 @@ using Godot;
namespace Babushka.scripts.CSharp.Common.Fight;
public class FightHappening
public partial class FightHappening : Node
{
/*
To get a visual overview of the FightHappening state machine, refer to the graph on miro:
@@ -36,14 +36,14 @@ public class FightHappening
EnemyWin,
}
private class FightersEnterStaging
public class FightersEnterStaging
{
public required List<FightWorld.Fighter> enteringAllyFighters;
public required List<FightWorld.Fighter> enteringEnemyFighters;
public bool HasAnyToExecute()
{
return enteringAllyFighters.Count != 0 || enteringEnemyFighters.Count != 0;
return enteringAllyFighters.Any() || enteringEnemyFighters.Any();
}
}
@@ -56,7 +56,7 @@ public class FightHappening
#endregion
#region ShortCuts
#region Shortcuts
private static FightWorld.FightHappeningData HappeningData =>
FightWorld.Instance.fightHappeningData ?? throw new NoFightHappeningException();
@@ -67,18 +67,33 @@ public class FightHappening
#region Events
public event Action<FightState>? transitionFromState;
public event Action<FightState, FightState>? transitionState;
public event Action<FightState>? transitionToState;
[Signal]
public delegate void SignalTransitionFromStateEventHandler(FightState state);
[Signal]
public delegate void SignalTransitionStateEventHandler(FightState from, FightState to);
[Signal]
public delegate void SignalTransitionToStateEventHandler(FightState state);
#endregion
#region Staging
#region Singleton
private FightersEnterStaging? _fightersEnterStaging;
private FighterAction? _actionStaging;
public static FightHappening Instance = null!;
private void SetupInstance()
{
Instance = this;
}
#endregion
public override void _Ready()
{
SetupInstance();
StartFight();
}
#region Public Methods
@@ -88,17 +103,51 @@ public class FightHappening
ChangeState(FightState.FightStartAnim);
}
public void ActionSelect(FighterAction action)
{
RequireState(FightState.InputActionSelect);
HappeningData.actionStaging = action;
action.Reset();
ChangeState(FightState.ActionCheckDetails);
}
public void DetailFilled()
{
RequireState(FightState.InputActionDetail);
ChangeState(FightState.ActionCheckDetails);
}
#endregion
#region State Machine
private bool _inTransition = false;
private FightState? _changeToAfterTransition = null;
private void ChangeState(FightState nextState)
{
_changeToAfterTransition = null;
if (_inTransition)
{
_changeToAfterTransition = nextState;
return;
}
_inTransition = true;
TransitionFromState();
var lastState = HappeningData.fightState;
HappeningData.fightState = nextState;
TransitionFromToState(nextState, lastState);
TransitionToState(nextState);
EmitSignalSignalTransitionFromState(lastState);
EmitSignalSignalTransitionState(lastState, nextState);
EmitSignalSignalTransitionToState(nextState);
_inTransition = false;
if (_changeToAfterTransition.HasValue)
{
ChangeState(_changeToAfterTransition.Value);
}
}
private void TransitionFromState()
@@ -108,21 +157,10 @@ public class FightHappening
{
default: break;
}
// notify everyone else
transitionFromState?.Invoke(HappeningData.fightState);
}
private void TransitionFromToState(FightState nextState, FightState lastState)
{
transitionState?.Invoke(lastState, nextState);
}
private void TransitionToState(FightState nextState)
{
// notify everyone else
transitionToState?.Invoke(nextState);
// fixed behaviour
switch (HappeningData.fightState)
{
@@ -130,8 +168,8 @@ public class FightHappening
AdvanceToStateInSeconds(FightState.FightersEnter, StartAnimationTime);
break;
case FightState.FightersEnter:
_fightersEnterStaging = StageFightersEnter();
if (_fightersEnterStaging.HasAnyToExecute())
HappeningData.fightersEnterStaging = StageFightersEnter();
if (HappeningData.fightersEnterStaging.HasAnyToExecute())
{
ExecuteFightersEnter();
ChangeState(FightState.FightersEnterAnim);
@@ -150,10 +188,11 @@ public class FightHappening
ChangeState(FightState.StateCheck);
break;
case FightState.StateCheck:
// restest action staging
_actionStaging = null;
// restest action staging and fighter enter staging
HappeningData.actionStaging = null;
HappeningData.fightersEnterStaging = null;
if ( /*TODO: are all allys dead*/ false)
if (!FightWorld.Instance.allyFighters.IsAlive())
{
ChangeState(FightState.EnemyWin);
}
@@ -161,7 +200,7 @@ public class FightHappening
{
ChangeState(FightState.PlayerWin);
}
else if (CurrentFighter.actionsLeft <= 0)
else if (CurrentFighter.actionPointsLeft <= 0)
{
ChangeState(FightState.FightersEnter);
}
@@ -179,9 +218,11 @@ public class FightHappening
// wait for player input
break;
case FightState.ActionCheckDetails:
RequireNotNull(HappeningData.actionStaging);
if (ActionAbort())
ChangeState(FightState.InputActionSelect);
else if (ActionNeededDetail() != null)
else if (ActionNeededDetail())
ChangeState(FightState.InputActionDetail);
else
ChangeState(FightState.ActionExecute);
@@ -190,7 +231,7 @@ public class FightHappening
// wait for player input
break;
case FightState.EnemyActionSelect:
_actionStaging = CurrentFighter.AutoSelectAction();
HappeningData.actionStaging = CurrentFighter.AutoSelectAction();
ChangeState(FightState.ActionExecute);
break;
case FightState.ActionExecute:
@@ -212,7 +253,6 @@ public class FightHappening
default: break;
}
}
#endregion
#region Game Logic
@@ -221,38 +261,33 @@ public class FightHappening
{
// ally
var enteringAllyFighters = new List<FightWorld.Fighter>();
//TODO
var allyFighters = FightWorld.Instance.allyFighters;
if (!allyFighters.vesnaFighter.entered)
{
enteringAllyFighters.Add(allyFighters.vesnaFighter);
}
// enemy
const int totalEnemySpace = 3;
var enemySpaceLeft = totalEnemySpace - HappeningData.enemyGroup.GetEnteredAmount();
var enterEnemyFighters = new List<FightWorld.Fighter>();
for (var i = 0; i < enemySpaceLeft; i++)
{
if (HappeningData.enemyGroup.TryGetFirstUnenteredFighter(out var fighter))
{
enterEnemyFighters.Add(fighter);
}
}
return new FightersEnterStaging
{
enteringAllyFighters = enteringAllyFighters,
enteringEnemyFighters = enterEnemyFighters
enteringEnemyFighters = HappeningData.enemyGroup.GetUptoUnenteredFighters(enemySpaceLeft).ToList()
};
}
private void ExecuteFightersEnter()
{
Debug.Assert(_fightersEnterStaging != null);
foreach (var fighter in _fightersEnterStaging.enteringAllyFighters)
Debug.Assert(HappeningData.fightersEnterStaging != null);
foreach (var fighter in HappeningData.fightersEnterStaging.enteringAllyFighters)
{
fighter.entered = true;
HappeningData.fighterStack.AddAsLast(fighter);
}
foreach (var fighter in _fightersEnterStaging.enteringEnemyFighters)
foreach (var fighter in HappeningData.fightersEnterStaging.enteringEnemyFighters)
{
fighter.entered = true;
HappeningData.fighterStack.AddAsLast(fighter);
@@ -262,30 +297,32 @@ public class FightHappening
private void ExecuteNextFighter()
{
HappeningData.fighterStack.Next();
CurrentFighter.actionPointsLeft = CurrentFighter.maxActionPoints;
}
private void ExecuteAction()
{
Debug.Assert(_actionStaging != null);
_actionStaging.ExecuteAction();
Debug.Assert(HappeningData.actionStaging != null);
HappeningData.actionStaging.ExecuteAction();
CurrentFighter.actionPointsLeft -= HappeningData.actionStaging.GetActionPointCost();
}
private Variant<float, Func<bool>> GetActionAnimationEnd()
{
Debug.Assert(_actionStaging != null);
return _actionStaging.GetAnimationEnd();
Debug.Assert(HappeningData.actionStaging != null);
return HappeningData.actionStaging.GetAnimationEnd();
}
private bool ActionAbort()
{
Debug.Assert(_actionStaging != null);
return _actionStaging.MarkedForAbort();
Debug.Assert(HappeningData.actionStaging != null);
return HappeningData.actionStaging.MarkedForAbort();
}
private FighterAction.FighterActionDetail? ActionNeededDetail()
private bool ActionNeededDetail()
{
Debug.Assert(_actionStaging != null);
return _actionStaging.NeededDetail();
Debug.Assert(HappeningData.actionStaging != null);
return HappeningData.actionStaging.NextDetail();
}
#endregion // Game Logic
@@ -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
}