using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
[Serializable]
public struct Range {
[SerializeField] int range;
public Range(int range) {
if (range < 0) {
throw new ArgumentException("range cannot be negative", "range");
}
this.range = range;
}
public static implicit operator int(Range rangeToConvert) => rangeToConvert.range;
public static explicit operator Range(int range) => new Range(range);
}
public abstract class BaseAction : MonoBehaviour
{
public static event EventHandler onAnyActionStarted;
public static event EventHandler onAnyActionCompleted;
protected Unit unit;
private bool isActive;
protected CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
protected SpendablePoints<ActionPoints> actionCost = 1;
[SerializeField] protected Range maxDistance = (Range)0;
protected virtual void Awake() {
unit = transform.GetComponent<Unit>();
}
protected void StopAction() {
cancellationTokenSource.Cancel();
cancellationTokenSource.Dispose();
cancellationTokenSource = new CancellationTokenSource();
}
protected CancellationToken StartAction(out CancellationToken cancellationToken) {
cancellationToken = cancellationTokenSource.Token;
isActive = true;
cancellationToken.Register(() => {
isActive = false;
onAnyActionCompleted?.Invoke(this, EventArgs.Empty);
});
onAnyActionStarted?.Invoke(this, EventArgs.Empty);
return cancellationToken;
}
public bool IsActive() => isActive;
public Unit GetUnit() => unit;
public Range GetMaxDistance() => maxDistance;
public virtual SpendablePoints<ActionPoints> GetActionPointsCost() => actionCost;
public abstract string GetActionName();
public abstract CancellationToken TakeAction(in GridPosition targetGridPosition, out CancellationToken cancellationToken);
public virtual bool IsValidActionGridPosition(GridPosition gridPosition) =>
GetValidActionGridPosition().Contains(gridPosition);
public virtual IEnumerable<GridPosition> GetValidActionGridPosition() =>
GetValidActionGridPosition(unit.GetGridPosition());
public virtual IEnumerable<GridPosition> GetValidActionGridPosition(GridPosition gridPosition) =>
GetOffsetsInCircularRange(maxDistance).
Select(offset => gridPosition + offset).
Where((testGridPosition) => IsValidTargetPosition(gridPosition, testGridPosition));
public virtual IEnumerable<GridPosition> GetValidActionRangeGridPosition() =>
GetValidActionRangeGridPosition(unit.GetGridPosition());
public virtual IEnumerable<GridPosition> GetValidActionRangeGridPosition(GridPosition gridPosition) =>
GetOffsetsInCircularRange(maxDistance).
Select(offset => gridPosition + offset).
Where((testGridPosition) => IsValidTargetRangePosition(testGridPosition));
public bool IsValidTargetPosition(in GridPosition unitGridPosition, GridPosition testGridPosition) =>
(IsValidTargetRangePosition(testGridPosition) && IsValidTargetPositionSpecific(unitGridPosition, testGridPosition));
protected abstract bool IsValidTargetPositionSpecific(in GridPosition unitGridPosition, in GridPosition testGridPosition);
public virtual bool IsValidTargetRangePosition(in GridPosition testGridPosition) =>
(LevelGrid.Instance.IsValidGridPosition(testGridPosition));
public abstract EnemyAIAction GetEnemyAIAction(GridPosition gridPosition);
public IEnumerable<(BaseAction baseAction, EnemyAIAction enemyAIAction)> GetPossibleEnemyAIAction() {
return (GetValidActionGridPosition().Select(gridPosition => (baseAction: this, enemyAIAction: GetEnemyAIAction(gridPosition))));
}
IEnumerable<(int x, int z)> GetOffsetsInCircularRange(Range range) {
for (int x = -range; x <= range; x++) {
for (int z = -range; z <= range; z++) {
if ((MathF.Abs(x) + MathF.Abs(z) <= range)) {
yield return (x, z);
}
}
}
}
}