using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class Unit : MonoBehaviour, IDamageable
{
private const int ACTION_POINTS_BASE = 2;
public static event EventHandler OnAnyActionPointsChanged;
public static event EventHandler OnAnyUnitSpawned;
public static event EventHandler OnAnyUnitDead;
[SerializeField] private bool isEnemy;
[SerializeField] private TurnSystem turnSystem;
private GridPosition gridPosition;
MoveAction moveAction;
private BaseAction[] baseActionArray;
private SpendablePoints<ActionPoints> actionPoints = ACTION_POINTS_BASE;
private HealthSystem healthSystem;
private Dictionary<int, List<IUnitBuff>> buffDictionary = new Dictionary<int, List<IUnitBuff>>();
private void Awake() {
healthSystem = GetComponent<HealthSystem>();
moveAction = GetComponent<MoveAction>();
baseActionArray = GetComponents<BaseAction>();
}
private void Start() {
gridPosition = LevelGrid.Instance.GetGridPosition(transform.position);
LevelGrid.Instance.AddUnitAtGridPosition(gridPosition,this);
turnSystem.OnTurnChanged += TurnSystem_OnTurnChanged;
healthSystem.OnDead += HealthSystem_OnDead;
OnAnyUnitSpawned?.Invoke(this, EventArgs.Empty);
}
private void Update()
{
updateGridPosition();
}
public T GetAction<T>() where T: BaseAction =>
(T)baseActionArray.First(baseAction => baseAction is T);
public MoveAction GetDefaultAction() =>
GetAction<MoveAction>();
private void updateGridPosition() {
GridPosition newGridPosition = LevelGrid.Instance.GetGridPosition(transform.position);
if (gridPosition != newGridPosition) {
GridPosition oldGridPosition = gridPosition;
gridPosition = newGridPosition;
LevelGrid.Instance.UnitMovedGridPosition(oldGridPosition, newGridPosition, this);
}
}
public GridPosition GetGridPosition () => gridPosition;
public Vector3 GetWorldPosition () => transform.position;
public BaseAction[] GetBaseActionArray() {
return baseActionArray;
}
public bool TrySpendActionPointToTakeAction(BaseAction baseAction) {
if (CanSpendActionPointToTakeAction(baseAction)) {
SpendActionPoints(baseAction.GetActionPointsCost());
return true;
} else {
return false;
}
}
public bool CanSpendActionPointToTakeAction(BaseAction baseAction) => (actionPoints >= baseAction.GetActionPointsCost());
private void SpendActionPoints(SpendablePoints<ActionPoints> amount) {
actionPoints -= amount;
OnAnyActionPointsChanged?.Invoke(this, EventArgs.Empty);
}
public void AddActionPoints(SpendablePoints<ActionPoints> amount) {
actionPoints += amount;
OnAnyActionPointsChanged?.Invoke(this, EventArgs.Empty);
}
private bool IsMyTurn() => (turnSystem.IsPlayerTurn() != IsEnemy());
public void TurnSystem_OnTurnChanged(object sender, EventArgs empty) {
ExpireBuffs();
if (!IsMyTurn()) {
return;
}
actionPoints = ACTION_POINTS_BASE;
OnAnyActionPointsChanged?.Invoke(this, EventArgs.Empty);
ApplyBuffs();
}
public void AddBuff (int duration, IUnitBuff buff) {
int turnExpiration = turnSystem.GetTurnNumber() + duration;
buff.ApplyBuff(this);
if (buffDictionary.TryGetValue(turnExpiration, out List<IUnitBuff> buffList)) {
buffList.Add(buff);
} else {
buffList = new List<IUnitBuff>() {
buff
};
buffDictionary.Add(turnExpiration, buffList);
}
}
private void ApplyBuffs() {
foreach (var buff in buffDictionary.SelectMany(bufflist => bufflist.Value))
{
buff.ApplyBuff(this);
}
}
private void ExpireBuffs() {
buffDictionary.Remove(turnSystem.GetTurnNumber());
}
public SpendablePoints<ActionPoints> GetActionPoints() {
return actionPoints;
}
public bool IsEnemy() => isEnemy;
public void Damage(SpendablePoints<HealthPoints> damageAmount) {
healthSystem.Damage(damageAmount);
}
private void HealthSystem_OnDead(object sender, EventArgs empty) {
LevelGrid.Instance.ClearUnitAtGridPosition(gridPosition, this);
Destroy(gameObject);
OnAnyUnitDead?.Invoke(this, EventArgs.Empty);
}
public float GetHealthNormilized() => healthSystem.GetHealthNormalized();
}