using System.Collections.Generic; using System.Linq; using Schema; using UnityEngine; using UnityEngine.AI; using VOID.Generic.Dict; using VOID.Generic.Objects.Unit; using VOID.Generic.Util; namespace VOID.Generic.AI.Schema.Actions { [Description("Gets unit by selected filters and save it as blackboard variable")] [Category(SchemaCategory.CombatThisUnit)] public class GetUnit : Action { private enum UnitType { Any, Enemy, Neutral, Friendly } private enum SearchType { ClosestByDistance, FarthestByDistance, Random, LeastHp, MostHp, ClosestByPath, FarthestByPath } [SerializeField] private UnitType _findUnitBy; [SerializeField] private SearchType _searchBy; [SerializeField, Space(15)] private BlackboardEntrySelector _saveTo; public override NodeStatus Tick(object nodeMemory, SchemaAgent agent) { var thisUnit = ((UnitObjectSchemaAgent)agent).unit; if (!thisUnit.basicState.turnManager) return NodeStatus.Failure; // Get all participants in combat except current unit var allUnits = thisUnit.basicState.turnManager.allUnitsInQueue.Where(otherUnit => otherUnit != thisUnit) .ToList(); // Filter by UnitType if (_findUnitBy is UnitType.Enemy) allUnits = GetEnemy(thisUnit, allUnits); if (_findUnitBy is UnitType.Neutral) allUnits = GetNeutral(thisUnit, allUnits); if (_findUnitBy is UnitType.Friendly) allUnits = GetFriendly(thisUnit, allUnits); // Filter by SearchType if (_searchBy is SearchType.ClosestByDistance) _saveTo.value = GetClosestByDistance(thisUnit, allUnits); if (_searchBy is SearchType.FarthestByDistance) _saveTo.value = GetFarthestByDistance(thisUnit, allUnits); if (_searchBy is SearchType.Random) _saveTo.value = RandomUtil.RandomElement(allUnits); if (_searchBy is SearchType.LeastHp) _saveTo.value = GetByLeastHp(allUnits); if (_searchBy is SearchType.MostHp) _saveTo.value = GetByMostHp(allUnits); if (_searchBy is SearchType.ClosestByPath) _saveTo.value = GetClosestByPath(thisUnit, allUnits); if (_searchBy is SearchType.FarthestByPath) _saveTo.value = GetFarthestByPath(thisUnit, allUnits); // Could not find anything if (!_saveTo.value) return NodeStatus.Failure; return NodeStatus.Success; } private List GetEnemy(UnitObject thisUnit, List units) { return units.Where(otherUnit => thisUnit.unitAttitude.GetAttitudeWith(otherUnit) < AttitudeType.Neutral) .ToList(); } private List GetNeutral(UnitObject thisUnit, List units) { return units.Where(otherUnit => thisUnit.unitAttitude.GetAttitudeWith(otherUnit) == AttitudeType.Neutral) .ToList(); } private List GetFriendly(UnitObject thisUnit, List units) { return units.Where(otherUnit => thisUnit.unitAttitude.GetAttitudeWith(otherUnit) > AttitudeType.Neutral) .ToList(); } private UnitObject GetClosestByDistance(UnitObject thisUnit, List units) { var closestDistance = float.MaxValue; var closestUnit = (UnitObject)null; units.ForEach(otherUnit => { var distance = RangeUtil.GetDistance(thisUnit, otherUnit); if (distance >= closestDistance) return; closestDistance = distance; closestUnit = otherUnit; }); return closestUnit; } private UnitObject GetFarthestByDistance(UnitObject thisUnit, List units) { var farthestDistance = float.MinValue; var farthestUnit = (UnitObject)null; units.ForEach(otherUnit => { var distance = RangeUtil.GetDistance(thisUnit, otherUnit); if (distance <= farthestDistance) return; farthestDistance = distance; farthestUnit = otherUnit; }); return farthestUnit; } private UnitObject GetClosestByPath(UnitObject thisUnit, List units) { var closestPathLength = float.MaxValue; var closestUnit = (UnitObject)null; units.ForEach(otherUnit => { thisUnit.unitNavAgent.CalculatePathTo(otherUnit.transform.position); var path = thisUnit.unitNavAgent.GetPath(); var pathLength = NavMeshPathUtil.GetPathLength(path); if (path.status is not NavMeshPathStatus.PathInvalid) pathLength += Vector3.Distance(path.corners.Last(), otherUnit.transform.position); if (pathLength >= closestPathLength) return; closestPathLength = pathLength; closestUnit = otherUnit; }); return closestUnit; } private UnitObject GetFarthestByPath(UnitObject thisUnit, List units) { var farthestPathLength = float.MinValue; var farthestUnit = (UnitObject)null; units.ForEach(otherUnit => { thisUnit.unitNavAgent.CalculatePathTo(otherUnit.transform.position); var path = thisUnit.unitNavAgent.GetPath(); var pathLength = NavMeshPathUtil.GetPathLength(path); if (path.status is not NavMeshPathStatus.PathInvalid) pathLength += Vector3.Distance(path.corners.Last(), otherUnit.transform.position); if (pathLength <= farthestPathLength) return; farthestPathLength = pathLength; farthestUnit = otherUnit; }); return farthestUnit; } private UnitObject GetByLeastHp(List units) { var leastHp = float.MinValue; var leastHpUnit = (UnitObject)null; units.ForEach(otherUnit => { var hp = otherUnit.basicData.currentResources.health; if (hp >= leastHp) return; leastHp = hp; leastHpUnit = otherUnit; }); return leastHpUnit; } private UnitObject GetByMostHp(List units) { var mostHp = float.MaxValue; var mostHpUnit = (UnitObject)null; units.ForEach(otherUnit => { var hp = otherUnit.basicData.currentResources.health; if (hp <= mostHp) return; mostHp = hp; mostHpUnit = otherUnit; }); return mostHpUnit; } } }