Files
VOIDRPG/Assets/90 - Scripts/Generic/AI/Schema/Actions/UnitUseAbility.cs
T
2026-07-09 21:33:33 +02:00

110 lines
4.1 KiB
C#

using System;
using System.Linq;
using Schema;
using UnityEngine;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Unit;
using VOID.Generic.Objects.Unit.Actions;
using VOID.Generic.Objects.Unit.Events;
using VOID.ScriptableObjects.Abilities;
using Action = Schema.Action;
namespace VOID.Generic.AI.Schema.Actions
{
[Description("Order this unit to use selected ability")]
[Category(SchemaCategory.ThisUnit)]
public class UnitUseAbility : Action
{
private class UnitUseAbilityMemory
{
public SchemaUnitEventWrapper<AnimationGenericEvent, UnitUseAbilityMemory> onCastAnimationEnd;
public bool isRunning;
public bool isFinished;
}
private enum TargetType
{
Position,
Unit
}
[SerializeField] private BlackboardEntrySelector<BasicAbility> _ability;
[SerializeField, Space(15)] private TargetType _targetType;
[SerializeField] private BlackboardEntrySelector<Transform> _position;
[SerializeField] private BlackboardEntrySelector<UnitObject> _unit;
public override NodeStatus Tick(object nodeMemory, SchemaAgent agent)
{
var memory = (UnitUseAbilityMemory)nodeMemory;
var unitAgent = (UnitObjectSchemaAgent)agent;
var thisUnit = unitAgent.unit;
// Ability not selected
if (!_ability.value) return NodeStatus.Failure;
// Whenever is during casting or already done that
if (memory.isFinished) return NodeStatus.Success;
if (memory.isRunning) return NodeStatus.Running;
// Targets not selected
if (_targetType == TargetType.Position && !_position.value) return NodeStatus.Failure;
if (_targetType == TargetType.Unit && !_unit.value) return NodeStatus.Failure;
AbilityAction abilityAction;
if (_targetType is TargetType.Position)
{
// TODO: for now if ability needs multiple targets all will be identical
var targets = Enumerable.Repeat(_position.value.position, _ability.value.castUsages).ToArray();
abilityAction = new AbilityAction(thisUnit, _ability.value, targets);
}
else if (_targetType is TargetType.Unit)
{
// TODO: for now if ability needs multiple targets all will be identical
var targets = Enumerable.Repeat(_unit.value, _ability.value.castUsages).ToArray();
abilityAction = new AbilityAction(thisUnit, _ability.value, targets);
}
else
{
throw new ArgumentOutOfRangeException();
}
// Check if that action can be done
if (!abilityAction.CanDoItBoolean()) return NodeStatus.Failure;
// Listen to end of abilisty casting animation
memory.onCastAnimationEnd?.Off();
memory.onCastAnimationEnd = new SchemaUnitEventWrapper<AnimationGenericEvent, UnitUseAbilityMemory>(
thisUnit.unitEvents.onAnimation[AnimationType.Ability].onEnd, OnAbilityCastEnd, unitAgent, memory);
memory.onCastAnimationEnd.On();
// Everything seems ok - order unit to do that action
thisUnit.OrderStop();
thisUnit.Order(abilityAction);
memory.isRunning = true;
return NodeStatus.Running;
}
public override void OnNodeExit(object nodeMemory, SchemaAgent agent)
{
var memory = (UnitUseAbilityMemory)nodeMemory;
memory.onCastAnimationEnd?.Off();
memory.isFinished = false;
memory.isRunning = false;
}
public override void OnNodeAbort(object nodeMemory, SchemaAgent agent)
{
var memory = (UnitUseAbilityMemory)nodeMemory;
memory.onCastAnimationEnd?.Off();
memory.isFinished = false;
memory.isRunning = false;
}
private void OnAbilityCastEnd(AnimationGenericEvent abilityCastEvent, UnitUseAbilityMemory memory,
UnitObjectSchemaAgent agent)
{
memory.isFinished = true;
}
}
}