public class PlayerInputState : InputState
{
public static Action OnCharacterSelected;
public static Action OnNewMoveAction;
public static Action OnCharactersAssigned;
public static Action OnPassAction;
public static Action OnNewCharacter;
public static Action OnTileSelection;
public static Action OnMovementStateEnter;
public static Action OnFail;
private Action OnClearHover;
private Action OnClearHoverVfx;
private Action _interrupt;
private ActionState _actionState;
private MoveAction _moveAction;
private ShootAction _shootAction;
private GameAction _bufferedAction;
private Character _hoveredCharacter;
private int _selectedCharacterIndex;
[Header("Hover Outline")]
private static readonly int AseOutlineWidth = Shader.PropertyToID("_ASEOutlineWidth");
[SerializeField] private float _outlineHoverValue = 0.2f;
[SerializeField] private float _defaultOutlineValue = 0.01f;
[SerializeField] private GameObject _hoverVfx;
public override void Initialize(object owner)
{
base.Initialize(owner);
_actionState = GetState();
UIManager.OnAttackClicked += Attack;
UIManager.OnAbilityClicked += Ability;
UIManager.OnDefenseClicked += DefenseProtocol;
}
public override void Enter()
{
_interrupt = null;
_bufferedAction = null;
if (Characters.Count == 0)
{
GameManager.Lose();
return;
}
if (GetState().GetCharacters(1).Count == 0)
{
GameManager.Win();
return;
}
if (Characters.All(c => c.Data.RemainingActions == 0))
{
OnCharacterSelected?.Invoke(null);
GameManager.SwitchTeams();
return;
}
if (SelectedCharacter.Data.RemainingActions == 0)
{
for(int i = 0; i < Characters.Count; i++)
{
if (Characters[i].Data.RemainingActions == 0)
continue;
SelectedCharacter = Characters[i];
_selectedCharacterIndex = i;
OnNewCharacter?.Invoke(SelectedCharacter);
}
}
OnCharacterSelected?.Invoke(SelectedCharacter);
OnMovementStateEnter?.Invoke(SelectedCharacter);
}
public override void StateUpdate()
{
if (_bufferedAction != null)
{
_actionState.CurrentAction = _bufferedAction;
OnCharacterSelected?.Invoke(null);
TransitionTo();
return;
}
if (_interrupt != null)
{
_interrupt.Invoke();
_interrupt = null;
return;
}
if(Input.GetButtonDown("ShootAction"))
{
ToAttackState(null);
return;
}
(bool hit, Vector2Int cell) = GridManager.RaycastGrid();
Character c = GameManager.Instance.GetCharacterAtPosition(cell, 0);
if(c == null)
c = GameManager.Instance.GetCharacterAtPosition(cell, 1);
SetHoveringOutline(c);
if (hit && GridManager.Instance.GetCell(cell).Type == 0)
{
VisualHelper.HighlightType type = VisualHelper.HighlightType.Move;
if (c != null && c.TeamId == 1) type = VisualHelper.HighlightType.Target;
VisualHelper.SetHighlightCells(new List {cell}, type);
OnTileSelection?.Invoke(GridManager.Instance.GetCell(cell));
}
else
OnTileSelection?.Invoke(null);
if (GetState().SwitchWeapons())
return;
if (CycleCharacters())
return;
if (PerformMovementAction())
return;
if (PerformShootAction())
return;
if (PerformAbilityAction())
return;
if (PerformPassAction())
return;
}
private bool PerformAbilityAction()
{
if (!Input.GetButtonDown("AbilityAction"))
return false;
Ability();
return true;
}
private bool CycleCharacters()
{
if(Input.GetButtonDown("Cycle"))
{
Cycle();
return true;
}
if (!Input.GetButtonDown("LeftClick"))
return false;
(bool hit, Vector2Int gridPos) = GridManager.RaycastGrid();
if (!hit)
return false;
Character character = GameManager.GetCharacterAtPosition(gridPos, 0);
if (character == null || character == SelectedCharacter)
return false;
_selectedCharacterIndex = Characters.IndexOf(character);
SelectedCharacter = character;
OnClearHover?.Invoke();
OnClearHover = null;
OnClearHoverVfx?.Invoke();
OnClearHoverVfx = null;
OnCharacterSelected?.Invoke(SelectedCharacter);
return true;
}
public override void AddCharacters(List characters)
{
base.AddCharacters(characters);
OnCharacterSelected?.Invoke(SelectedCharacter);
OnCharactersAssigned?.Invoke(characters.ToArray());
}
private bool PerformMovementAction()
{
if (SelectedCharacter.Data.RemainingActions == 0)
{
if(Input.GetButtonDown("LeftClick")) OnFail?.Invoke();
return false;
}
(bool hit, Vector2Int gridPos) = GridManager.RaycastGrid();
if (!hit || gridPos == SelectedCharacter.Data.Position)
{
OnNewMoveAction?.Invoke(null);
if(Input.GetButtonDown("LeftClick")) OnFail?.Invoke();
return false;
}
List list = GridManager.Instance.AStar(SelectedCharacter.Data.Cell, GridManager.Instance.GetCell(gridPos));
if (list == null || list.Count > SelectedCharacter.Data.RemainingSteps + 1)
{
if (list != null && list.Count > SelectedCharacter.Data.RemainingSteps + 1)
{
VisualHelper.SetHighlightCells(new List {gridPos}, VisualHelper.HighlightType.OutOfMovementRange);
if(Input.GetButtonDown("LeftClick"))
OnFail?.Invoke();
}
OnNewMoveAction?.Invoke(null);
return false;
}
_moveAction = new MoveAction(SelectedCharacter, list.Select(x => x.Position).ToList());
OnNewMoveAction?.Invoke(_moveAction);
if (_moveAction.Steps > SelectedCharacter.Class.MaxStepsPerAction)
VisualHelper.SetHighlightCells(new List {gridPos}, VisualHelper.HighlightType.Sprint);
if (!Input.GetButtonDown("LeftClick"))
return false;
_actionState.CurrentAction = _moveAction;
OnCharacterSelected?.Invoke(null);
TransitionTo();
return true;
}
private bool PerformShootAction()
{
if (!Input.GetButtonDown("LeftClick") && !Input.GetButtonDown("RightClick") || SelectedCharacter.Data.RemainingActions == 0)
return false;
(bool hit, Vector2Int gridPos) = GridManager.RaycastGrid();
if (!hit)
return false;
Character newTarget = GameManager.GetCharacterAtPosition(gridPos, 1);
if (newTarget == null)
return false;
ShootAction shootAction = new ShootAction(SelectedCharacter, newTarget, SelectedCharacter.Data.CurrentWeapon);
ToAttackState(shootAction);
return true;
}
private void ToAttackState(ShootAction action)
{
PlayerAttackState attackState = GetState();
attackState.ShootAction = action;
attackState.SelectedCharacter = SelectedCharacter;
TransitionTo();
}
private bool PerformPassAction()
{
if (!Input.GetButtonDown("Pass") || SelectedCharacter.Data.RemainingActions == 0 || StateMachine.CurrentState != this )
return false;
_actionState.CurrentAction = new PassAction(SelectedCharacter);
OnCharacterSelected?.Invoke(null);
OnPassAction?.Invoke(SelectedCharacter);
TransitionTo();
return true;
}
public override void Exit()
{
VisualHelper.SetHighlightCells(null);
_bufferedAction = null;
OnNewMoveAction?.Invoke(null);
OnTileSelection?.Invoke(null);
OnClearHover?.Invoke();
OnClearHover = null;
_hoveredCharacter = null;
}
private void Attack()
{
if (SelectedCharacter.Data.RemainingActions == 0)
return;
_interrupt = () =>
{
PlayerAttackState attackState = GetState();
attackState.ShootAction = null;
attackState.SelectedCharacter = SelectedCharacter;
TransitionTo();
};
}
private void Ability()
{
if (SelectedCharacter.Data.RemainingActions == 0)
return;
if (SelectedCharacter == null || StateMachine.CurrentState.GetType() != GetType() || SelectedCharacter.Data.RemainingAbilityUses <= 0)
return;
_interrupt = () => { };
if (SelectedCharacter.Class.ClassAbility.GetType() == typeof(SniperAbility))
TransitionTo();
else if (SelectedCharacter.Class.ClassAbility.GetType() == typeof(GrenadierAbility))
TransitionTo();
else if (SelectedCharacter.Class.ClassAbility.GetType() == typeof(RangerAbility))
TransitionTo();
}
private void DefenseProtocol()
{
if (SelectedCharacter == null || SelectedCharacter.Data.RemainingActions == 0 || StateMachine.CurrentState != this)
return;
_actionState.CurrentAction = new PassAction(SelectedCharacter);
OnCharacterSelected?.Invoke(null);
OnPassAction?.Invoke(SelectedCharacter);
TransitionTo();
}
private void Cycle()
{
_selectedCharacterIndex = (_selectedCharacterIndex + 1) % Characters.Count;
SelectedCharacter = Characters[_selectedCharacterIndex];
OnClearHover?.Invoke();
OnClearHover = null;
OnCharacterSelected?.Invoke(SelectedCharacter);
if(SelectedCharacter.Data.RemainingActions == 0) Cycle(); //TODO: dont like this recursive call
OnNewCharacter?.Invoke(SelectedCharacter);
}
private void SetHoveringOutline(Character character)
{
OnClearHover?.Invoke();
OnClearHover = null;
if (character == null)
{
OnClearHoverVfx?.Invoke();
OnClearHoverVfx = null;
_hoveredCharacter = null;
}
if (character != null && character != SelectedCharacter)
{
if (character.TeamId == 0 && (_hoveredCharacter == null || _hoveredCharacter != character))
{
OnClearHoverVfx?.Invoke();
OnClearHover = null;
GameObject instance = Instantiate(_hoverVfx, character.Data.WorldRepresentation.transform.position, Quaternion.identity);
OnClearHoverVfx += () => Destroy(instance);
_hoveredCharacter = character;
}
SkinnedMeshRenderer _renderer =
character.Data.WorldRepresentation.GetComponentInChildren();
if(character.Behaviour == Character.BehaviourType.Ranged)
_renderer.materials[1].SetFloat(AseOutlineWidth, _outlineHoverValue);
else
_renderer.material.SetFloat(AseOutlineWidth, _outlineHoverValue);
OnClearHover += () =>
{
if(character.Behaviour == Character.BehaviourType.Ranged)
_renderer.materials[1].SetFloat(AseOutlineWidth, _defaultOutlineValue);
else
_renderer.material.SetFloat(AseOutlineWidth, _defaultOutlineValue);
};
}
}
}