You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
8.9 KiB
281 lines
8.9 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Babushka.scripts.CSharp.Common.Camera;
|
|
using Babushka.scripts.CSharp.Common.Util;
|
|
using Godot;
|
|
namespace Babushka.scripts.CSharp.Common.Fight;
|
|
|
|
public partial class FightInstance : Node2D //TODO: remake
|
|
{
|
|
[Export(PropertyHint.ArrayType)] private Node2D[] _friendlyFightSpots;
|
|
[Export(PropertyHint.ArrayType)] private Node2D[] _enemyFightSpots;
|
|
[Export] public Node2D camPositionNode;
|
|
[Export] private FightStateManager _fightStateManager;
|
|
[Export] private Label _fightEndText;
|
|
|
|
|
|
[Signal]
|
|
public delegate void FightStartedEventHandler();
|
|
|
|
[Signal]
|
|
public delegate void FightEndedEventHandler();
|
|
|
|
private List<Fighter> _friendlyFighters = new();
|
|
private List<Fighter> _enemyFighters = new();
|
|
|
|
private FightAttack? _stagedAttack = null;
|
|
|
|
public override void _Ready()
|
|
{
|
|
//_fightStateManager.CurrentFightState = FightStateManager.FightState.FightStartAnim;
|
|
_fightStateManager.ExitingTransition += from =>
|
|
{
|
|
switch (from)
|
|
{
|
|
case FightStateManager.FightState.None:
|
|
CaptureCamera();
|
|
Show();
|
|
EmitSignalFightStarted();
|
|
break;
|
|
case FightStateManager.FightState.Input:
|
|
HideAttackButtons();
|
|
break;
|
|
case FightStateManager.FightState.InputTargetSelect:
|
|
HideTargetButtons();
|
|
break;
|
|
case FightStateManager.FightState.FriendAttackAnim:
|
|
_stagedAttack = null;
|
|
break;
|
|
case FightStateManager.FightState.PlayerWinAnim:
|
|
case FightStateManager.FightState.EnemyWinAnim:
|
|
_fightEndText.Text = "";
|
|
break;
|
|
}
|
|
};
|
|
|
|
_fightStateManager.EnteringTransition += to =>
|
|
{
|
|
switch (to)
|
|
{
|
|
case FightStateManager.FightState.None:
|
|
EmitSignalFightEnded();
|
|
CleanUp();
|
|
Hide();
|
|
ReleaseCamera();
|
|
break;
|
|
case FightStateManager.FightState.Input:
|
|
if (CheckWin())
|
|
{
|
|
break;
|
|
}
|
|
ShowAttackButtons();
|
|
break;
|
|
case FightStateManager.FightState.InputTargetSelect:
|
|
ShowTargetButtons();
|
|
break;
|
|
case FightStateManager.FightState.FriendAttackAnim:
|
|
ExecuteAttack();
|
|
GetTree().CreateTimer(1).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.Enemy;
|
|
break;
|
|
case FightStateManager.FightState.Enemy:
|
|
if (CheckWin())
|
|
{
|
|
break;
|
|
}
|
|
DecideEnemyAttack();
|
|
_fightStateManager.CurrentFightState = FightStateManager.FightState.EnemyAttackAnim;
|
|
break;
|
|
case FightStateManager.FightState.EnemyAttackAnim:
|
|
ExecuteAttack();
|
|
GetTree().CreateTimer(1).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.Input;
|
|
break;
|
|
case FightStateManager.FightState.PlayerWinAnim:
|
|
_fightEndText.Text = "You Win!";
|
|
GetTree().CreateTimer(3).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.None;
|
|
break;
|
|
case FightStateManager.FightState.EnemyWinAnim:
|
|
_fightEndText.Text = "You Died :(";
|
|
GetTree().CreateTimer(3).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.None;
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
private void CleanUp()
|
|
{
|
|
_enemyFighters.ForEach(f => f.QueueFree());
|
|
_friendlyFighters.ForEach(f => f.QueueFree());
|
|
_enemyFighters = new();
|
|
_friendlyFighters = new();
|
|
}
|
|
private void DecideEnemyAttack()
|
|
{
|
|
var aliveEnemyFighters = _enemyFighters.Where(f => !f.IsDead()).ToList();
|
|
var aliveFriendlyFighters = _friendlyFighters.Where(f => !f.IsDead()).ToList();
|
|
|
|
if (aliveEnemyFighters.Count <= 0)
|
|
throw new InvalidOperationException("No enemy fighters available for attack.");
|
|
|
|
if (aliveFriendlyFighters.Count <= 0)
|
|
throw new InvalidOperationException("No friendly fighters available to target.");
|
|
|
|
var fighter = aliveEnemyFighters.Random();
|
|
var target = aliveFriendlyFighters.Random();
|
|
|
|
_stagedAttack = new FightAttack
|
|
{
|
|
attacker = fighter!,
|
|
needsSelectedTarget = true,
|
|
damage = fighter!.attackStrength,
|
|
target = target!
|
|
};
|
|
}
|
|
|
|
private void ExecuteAttack()
|
|
{
|
|
if (_stagedAttack == null)
|
|
throw new InvalidOperationException("No staged attack to execute.");
|
|
|
|
if (!_stagedAttack.needsSelectedTarget)
|
|
throw new NotImplementedException("Non-targeted attacks are not implemented yet.");
|
|
|
|
if (_stagedAttack.needsSelectedTarget && _stagedAttack.target == null)
|
|
throw new InvalidOperationException("No target selected for the staged attack.");
|
|
|
|
_stagedAttack.target!.Health -= _stagedAttack.damage;
|
|
|
|
_stagedAttack.attacker.AttackAnimation(_stagedAttack);
|
|
|
|
UpdateHealthVisual();
|
|
}
|
|
|
|
private void UpdateHealthVisual()
|
|
{
|
|
_friendlyFighters
|
|
.Concat(_enemyFighters)
|
|
.ForEach(f => f.UpdateHealthVisual());
|
|
}
|
|
|
|
private void ReleaseCamera()
|
|
{
|
|
CameraController.Instance.fightToShow = null;
|
|
}
|
|
|
|
private void CaptureCamera()
|
|
{
|
|
CameraController.Instance.fightToShow = this;
|
|
}
|
|
|
|
public void Start(FightParty fightParty, PackedScene?[] enemies)
|
|
{
|
|
if (_fightStateManager.IsRunning())
|
|
{
|
|
GD.PushWarning("Can not start a running fight");
|
|
return;
|
|
}
|
|
|
|
if (fightParty.vesna)
|
|
{
|
|
InstantiateFighter(_friendlyFightSpots[1], FightManager.Instance.fightingVesnaScene);
|
|
}
|
|
|
|
for (var i = 0; i < Math.Min(_enemyFightSpots.Length, enemies.Length); i++)
|
|
{
|
|
var enemy = enemies[i];
|
|
if (enemy == null)
|
|
continue;
|
|
|
|
InstantiateFighter(_enemyFightSpots[i], enemy, true);
|
|
}
|
|
|
|
_fightStateManager.ToStartAnim();
|
|
}
|
|
|
|
private void InstantiateFighter(Node2D parent, PackedScene fighterScene, bool isEnemy = false)
|
|
{
|
|
var fighter = fighterScene.Instantiate<Fighter>();
|
|
fighter.fightInstance = this;
|
|
parent.AddChild(fighter);
|
|
|
|
if (isEnemy)
|
|
{
|
|
_enemyFighters.Add(fighter);
|
|
}
|
|
else
|
|
{
|
|
_friendlyFighters.Add(fighter);
|
|
}
|
|
}
|
|
|
|
public void SelectAttack(Fighter fighter)
|
|
{
|
|
_stagedAttack = new FightAttack
|
|
{
|
|
attacker = fighter,
|
|
damage = fighter.attackStrength,
|
|
needsSelectedTarget = true
|
|
};
|
|
|
|
if (_stagedAttack.needsSelectedTarget)
|
|
{
|
|
_fightStateManager.CurrentFightState = FightStateManager.FightState.InputTargetSelect;
|
|
}
|
|
else
|
|
{
|
|
_fightStateManager.CurrentFightState = FightStateManager.FightState.FriendAttackAnim;
|
|
}
|
|
}
|
|
|
|
private void HideAttackButtons()
|
|
{
|
|
_friendlyFighters.ForEach(f => f.HideAttackButton());
|
|
}
|
|
|
|
private void ShowAttackButtons()
|
|
{
|
|
_friendlyFighters.ForEach(f => f.ShowAttackButton());
|
|
}
|
|
|
|
private void HideTargetButtons()
|
|
{
|
|
_enemyFighters.ForEach(f => f.HideTargetButtons());
|
|
}
|
|
|
|
private void ShowTargetButtons()
|
|
{
|
|
_enemyFighters.Where(f=>!f.IsDead()).ForEach(f => f.ShowTargetButtons());
|
|
}
|
|
|
|
public void SelectTargetAndAttack(Fighter fighter)
|
|
{
|
|
if (_stagedAttack == null)
|
|
throw new InvalidOperationException("No staged attack to select target for.");
|
|
|
|
_stagedAttack.target = fighter;
|
|
|
|
_fightStateManager.CurrentFightState = FightStateManager.FightState.FriendAttackAnim;
|
|
}
|
|
|
|
public bool CheckWin()
|
|
{
|
|
if (_enemyFighters.All(f => f.IsDead()))
|
|
{
|
|
_fightStateManager.CurrentFightState = FightStateManager.FightState.PlayerWinAnim;
|
|
return true;
|
|
}
|
|
if (_friendlyFighters.All(f => f.IsDead()))
|
|
{
|
|
_fightStateManager.CurrentFightState = FightStateManager.FightState.EnemyWinAnim;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
public class FightAttack
|
|
{
|
|
public int damage;
|
|
public bool needsSelectedTarget;
|
|
public Fighter? target;
|
|
public Fighter attacker;
|
|
}
|