Here is the problem I attempted to solve:
I have a rough solution working but was hoping for some recommendations on how this could be improved, as I think it's a useful feature. I am aware that this problem can be solved by creating a new conditional that is just a composite of the conditionals I want to be evaluated at the same time. But, if possible, I want to avoid making these kinds of redundant composite conditionals.
To solve this problem I created a custom conditional task called "multi conditional" that can reference as many different conditionals as desired and only returns success if all of the conditionals returned success. There is also an option to invert each referenced conditional individually if desired. This way you can observe several conditionals together when using conditional aborts. So far it has worked, but feels a little janky. Here is the code for this new conditional:
And here is a picture of what it looks like within the tree (more for example than an actual use-case) Here I have the multi conditional evaluating a condtional called 'see player' and also evaluating an inverted conditional 'is within radius'. In this case the low priority abort on the combat sequence task is only activated if both 'see player' returns success and the inverted 'is within radius' returns success.
As you can see, the conditionals are not attached to the tree however it still works because of the references linking them to the multiconditional. I was curious if anyone had some ideas for how they would implement this kind of custom task so that the conditionals it evaluates are connected to the tree and any other possible improvements. One rough area with this implementation is that I have to manually set the size of the "inversion flags" array. I created it this way because I have very limited experience with scripting custom editors, and had no clue how to resize this array without access to any kind of "OnValidate" function.
Any thoughts or suggestions would be greatly appreciated, thank you!
I have a rough solution working but was hoping for some recommendations on how this could be improved, as I think it's a useful feature. I am aware that this problem can be solved by creating a new conditional that is just a composite of the conditionals I want to be evaluated at the same time. But, if possible, I want to avoid making these kinds of redundant composite conditionals.
To solve this problem I created a custom conditional task called "multi conditional" that can reference as many different conditionals as desired and only returns success if all of the conditionals returned success. There is also an option to invert each referenced conditional individually if desired. This way you can observe several conditionals together when using conditional aborts. So far it has worked, but feels a little janky. Here is the code for this new conditional:
C#:
[TaskCategory("NPC/Conditional")]
[TaskDescription("The MultiConditional evaluates multiple conditionals at once and only returns True if all conditionals are true.")]
public class MultiConditional : Conditional
{
public Conditional[] condtionalTasks;
public bool[] inversionFlags;
public override void OnAwake()
{
if (condtionalTasks.Length > 0)
{
foreach (var conditional in condtionalTasks)
{
conditional.Owner = Owner;
conditional.GameObject = gameObject;
conditional.Transform = transform;
conditional.OnAwake();
}
}
}
public override void OnStart()
{
if (condtionalTasks.Length > 0)
{
foreach (var conditional in condtionalTasks)
{
conditional.OnStart();
}
}
}
public override TaskStatus OnUpdate()
{
//initialize as a failure, all input conditionals must return true for this task to return success.
var status = TaskStatus.Failure;
if (condtionalTasks.Length > 0)
{
for (var i = 0; i < condtionalTasks.Length; i++)
{
var conditional = condtionalTasks[i];
status = conditional.OnUpdate();
if (inversionFlags[i])
status = InvertStatus(status);
//if any single conditional in this array return failure we want the entire multiconditional to return failure.
if (status == TaskStatus.Failure)
return TaskStatus.Failure;
}
return status;
}
return TaskStatus.Failure;
}
public override void OnEnd()
{
if (condtionalTasks.Length > 0)
{
foreach (var conditional in condtionalTasks)
{
conditional.OnEnd();
}
}
}
public override void OnReset() => condtionalTasks = new Conditional[0];
private TaskStatus InvertStatus(TaskStatus inputStatus)
{
var invertedStatus = TaskStatus.Inactive;
if (inputStatus == TaskStatus.Failure)
invertedStatus = TaskStatus.Success;
else if (inputStatus == TaskStatus.Success)
invertedStatus = TaskStatus.Failure;
return invertedStatus;
}
}
And here is a picture of what it looks like within the tree (more for example than an actual use-case) Here I have the multi conditional evaluating a condtional called 'see player' and also evaluating an inverted conditional 'is within radius'. In this case the low priority abort on the combat sequence task is only activated if both 'see player' returns success and the inverted 'is within radius' returns success.
As you can see, the conditionals are not attached to the tree however it still works because of the references linking them to the multiconditional. I was curious if anyone had some ideas for how they would implement this kind of custom task so that the conditionals it evaluates are connected to the tree and any other possible improvements. One rough area with this implementation is that I have to manually set the size of the "inversion flags" array. I created it this way because I have very limited experience with scripting custom editors, and had no clue how to resize this array without access to any kind of "OnValidate" function.
Any thoughts or suggestions would be greatly appreciated, thank you!