Allows datum AI to create new plans while a plan is still executing (#71596)

## About The Pull Request

In some cases, you need to perform behaviors that can occur ontop of
different behaviors. E.g. "I need to continiously spit out foam while
moving to a point". If these behaviors are put separetely, it is
difficult to determine that the behavior for spitting out foam needs to
end. And in the current code, aslong as it has not ended, the plan will
never end. So once the AI reaches the point it would stand still at the
end and spit out foam unendingly.

To work around this I've made it so behaviors can be set to allow
planning while they run if they have the
AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION flag. If all remaining behaviors
on a controller have this flag, a new plan is made. If this plan is the
exact same as the plan that was currently being performed, nothing
happens. But if the plan is different, the current one is ended and the
new plan is executed. This means situations like this are handled
gracefully now. This will be required for basic bots.

## Why It's Good For The Game

More graceful handling of "continous" behaviors! :)

## Changelog

🆑 Capybara Holly
refactor: Allows datum AI to create new plans while a plan is still
executing
/🆑

Co-authored-by: Capybara <Capybara@CapybaraMailingServices.com>
This commit is contained in:
CapybaraExtravagante
2022-11-29 23:31:53 +01:00
committed by GitHub
parent 4e87c61f97
commit 1b8bd51ec2
3 changed files with 28 additions and 4 deletions

View File

@@ -9,6 +9,8 @@ multiple modular subtrees with behaviors
var/atom/pawn
///Bitfield of traits for this AI to handle extra behavior
var/ai_traits
///Current actions planned to be performed by the AI in the upcoming plan
var/list/planned_behaviors
///Current actions being performed by the AI.
var/list/current_behaviors
///Current actions and their respective last time ran as an assoc list.
@@ -190,6 +192,14 @@ multiple modular subtrees with behaviors
ProcessBehavior(action_delta_time, current_behavior)
return
///Determines whether the AI can currently make a new plan
/datum/ai_controller/proc/able_to_plan()
. = TRUE
for(var/datum/ai_behavior/current_behavior as anything in current_behaviors)
if(!(current_behavior.behavior_flags & AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION)) //We have a behavior that blocks planning
. = FALSE
break
///This is where you decide what actions are taken by the AI.
/datum/ai_controller/proc/SelectBehaviors(delta_time)
SHOULD_NOT_SLEEP(TRUE) //Fuck you don't sleep in procs like this.
@@ -197,12 +207,22 @@ multiple modular subtrees with behaviors
return FALSE
LAZYINITLIST(current_behaviors)
LAZYCLEARLIST(planned_behaviors)
if(LAZYLEN(planning_subtrees))
for(var/datum/ai_planning_subtree/subtree as anything in planning_subtrees)
if(subtree.SelectBehaviors(src, delta_time) == SUBTREE_RETURN_FINISH_PLANNING)
break
for(var/datum/ai_behavior/current_behavior as anything in current_behaviors)
if(LAZYACCESS(planned_behaviors, current_behavior))
continue
var/list/arguments = list(src, FALSE)
var/list/stored_arguments = behavior_args[type]
if(stored_arguments)
arguments += stored_arguments
current_behavior.finish_action(arglist(arguments))
///This proc handles changing ai status, and starts/stops processing if required.
/datum/ai_controller/proc/set_ai_status(new_ai_status)
if(ai_status == new_ai_status)
@@ -231,6 +251,7 @@ multiple modular subtrees with behaviors
if(!behavior.setup(arglist(arguments)))
return
LAZYADD(current_behaviors, behavior)
LAZYADDASSOC(planned_behaviors, behavior, TRUE)
arguments.Cut(1, 2)
if(length(arguments))
behavior_args[behavior_type] = arguments