diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index fcb595cdbd3..622cc84134e 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -22,6 +22,8 @@ #define AI_BEHAVIOR_KEEP_MOVE_TARGET_ON_FINISH (1<<2) ///Does finishing this task make the AI stop moving towards the target? #define AI_BEHAVIOR_KEEP_MOVING_TOWARDS_TARGET_ON_FINISH (1<<3) +///Does this behavior NOT block planning? +#define AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION (1<<4) ///AI flags #define STOP_MOVING_WHEN_PULLED (1<<0) diff --git a/code/controllers/subsystem/ai_controllers.dm b/code/controllers/subsystem/ai_controllers.dm index 82c22869e32..3d8d2653149 100644 --- a/code/controllers/subsystem/ai_controllers.dm +++ b/code/controllers/subsystem/ai_controllers.dm @@ -27,7 +27,8 @@ SUBSYSTEM_DEF(ai_controllers) if(!COOLDOWN_FINISHED(ai_controller, failed_planning_cooldown)) continue - if(!LAZYLEN(ai_controller.current_behaviors)) - ai_controller.SelectBehaviors(wait * 0.1) - if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan - COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN) + if(!ai_controller.able_to_plan()) + continue + ai_controller.SelectBehaviors(wait * 0.1) + if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan + COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN) diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 2c1d733baf8..25da255284a 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -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