using System; using System.Linq; using Schema; using Sirenix.Utilities; using UnityEngine; using VOID.Generic.Dict.Ability; using VOID.Generic.Util; using VOID.ScriptableObjects.Abilities; using Action = Schema.Action; namespace VOID.Generic.AI.Schema.Actions { [Description("Gets ability by selected filters from this unit and save it as blackboard variable")] [Category(SchemaCategory.ThisUnit)] public class GetAbility : Action { private enum SearchType { First, Random, LeastExpensive, MostExpensive, GreatestRange } private enum AbilityPurposeType { Any, All } [SerializeField] private bool includeBasicAttack; [SerializeField] private BlackboardEntrySelector atLeastRange; [SerializeField] private AbilityPurposeType abilityPurposeType; [SerializeField] private AbilityPurposeFlag abilityPurpose; [SerializeField] private SearchType searchBy; [SerializeField, WriteOnly, Space(15)] private BlackboardEntrySelector saveTo; public override NodeStatus Tick(object nodeMemory, SchemaAgent agent) { var thisUnit = ((UnitObjectSchemaAgent)agent).unit; var allAbilities = thisUnit.unitAbilityBook.abilities.ToList(); // Unit dont have any abilities if (allAbilities.IsNullOrEmpty()) return NodeStatus.Failure; if (includeBasicAttack) allAbilities.Add(thisUnit.unitAbilityBook.attackAbility); // Filter by range required allAbilities = allAbilities.Where(ability => ability.range >= atLeastRange.value).ToList(); // Filter by wanted purpose allAbilities = allAbilities.Where(ability => { switch (abilityPurposeType) { case AbilityPurposeType.All when (ability.abilityPurpose & abilityPurpose) == abilityPurpose: case AbilityPurposeType.Any when (ability.abilityPurpose & abilityPurpose) != AbilityPurposeFlag.None: return true; default: return false; } }).ToList(); // Getting final ability and saving it saveTo.value = searchBy switch { SearchType.First => allAbilities.FirstOrDefault(), SearchType.Random => RandomUtil.RandomElement(allAbilities), SearchType.LeastExpensive => allAbilities.Aggregate(allAbilities.First(), (a1, a2) => a2.actionPointCost > a1.actionPointCost ? a1 : a2), SearchType.MostExpensive => allAbilities.Aggregate(allAbilities.First(), (a1, a2) => a2.actionPointCost <= a1.actionPointCost ? a1 : a2), SearchType.GreatestRange => allAbilities.Aggregate(allAbilities.First(), (a1, a2) => a2.range <= a1.range ? a1 : a2), _ => throw new ArgumentOutOfRangeException() }; if (!saveTo.value) return NodeStatus.Failure; return NodeStatus.Success; } } }