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