diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index a13cc8b36fa..b525f66576c 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -435,6 +435,25 @@ multiple modular subtrees with behaviors blackboard[key] = thing post_blackboard_key_set(key) +/** + * Helper to force a key to be a certain thing no matter what's already there + * + * Useful for if you're overriding a list with a new list entirely, + * as otherwise it would throw a runtime error from trying to override a list + * + * Not necessary to use if you aren't dealing with lists, as set_blackboard_key will clear the existing value + * in that case already, but may be useful for clarity. + * + * * key - A blackboard key + * * thing - a value to set the blackboard key to. + */ +/datum/ai_controller/proc/override_blackboard_key(key, thing) + if(blackboard[key] == thing) + return + + clear_blackboard_key(key) + set_blackboard_key(key, thing) + /** * Sets the key at index thing to the passed value * diff --git a/code/datums/components/listen_and_repeat.dm b/code/datums/components/listen_and_repeat.dm index 9ffee682972..bd311118dc0 100644 --- a/code/datums/components/listen_and_repeat.dm +++ b/code/datums/components/listen_and_repeat.dm @@ -82,7 +82,7 @@ if(!LAZYLEN(speech_buffer)) // what? well whatever let's just move on return - controller.set_blackboard_key(BB_EXPORTABLE_STRING_BUFFER_LIST, speech_buffer.Copy()) + controller.override_blackboard_key(BB_EXPORTABLE_STRING_BUFFER_LIST, speech_buffer.Copy()) #undef MAX_SPEECH_BUFFER_SIZE #undef RADIO_IGNORE_CHANCE diff --git a/code/datums/elements/haunted.dm b/code/datums/elements/haunted.dm index d678083dd19..04f985c0d89 100644 --- a/code/datums/elements/haunted.dm +++ b/code/datums/elements/haunted.dm @@ -23,7 +23,6 @@ QDEL_NULL(master.ai_controller) REMOVE_TRAIT(master, TRAIT_MOVE_FLYING, ELEMENT_TRAIT(type)) master.RemoveElement(/datum/element/movetype_handler) - return ..() /atom/movable/proc/make_haunted(source, color) //if not haunted, make haunted if(!HAS_TRAIT(src, TRAIT_HAUNTED)) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_migration.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_migration.dm index c7bee5a36e9..27fdb25ee22 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_migration.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_migration.dm @@ -10,32 +10,29 @@ /datum/ai_planning_subtree/carp_migration /datum/ai_planning_subtree/carp_migration/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - . = ..() - // If there's a rift nearby take a ride, then cancel everything else because it's not valid any more - var/obj/effect/temp_visual/lesser_carp_rift/entrance/rift = locate(/obj/effect/temp_visual/lesser_carp_rift/entrance) in orange(controller.pawn, CARP_PORTAL_SEARCH_RANGE) - if (rift) + for(var/obj/effect/temp_visual/lesser_carp_rift/entrance/rift in orange(controller.pawn, CARP_PORTAL_SEARCH_RANGE)) controller.queue_behavior(/datum/ai_behavior/travel_towards_atom, get_turf(rift)) return SUBTREE_RETURN_FINISH_PLANNING - var/list/migration_points = controller.blackboard[BB_CARP_MIGRATION_PATH] - if (!length(migration_points)) - return - + // We have a destination, try to approach it var/turf/moving_to = controller.blackboard[BB_CARP_MIGRATION_TARGET] - - // If we don't have a target or are close enough to it, pick a new one - if (isnull(moving_to) || get_dist(controller.pawn, moving_to) <= CARP_DESTINATION_SEARCH_RANGE) - controller.queue_behavior(/datum/ai_behavior/find_next_carp_migration_step, BB_CARP_MIGRATION_PATH, BB_CARP_MIGRATION_TARGET) + if(!isnull(moving_to)) + var/turf/next_step = get_step_towards(controller.pawn, moving_to) + // Attempt to teleport around if we're blocked + if(next_step.is_blocked_turf(exclude_mobs = TRUE)) + controller.queue_behavior(/datum/ai_behavior/make_carp_rift/towards/unvalidated, BB_CARP_RIFT, BB_CARP_MIGRATION_TARGET) + controller.queue_behavior(/datum/ai_behavior/attack_obstructions/carp, BB_CARP_MIGRATION_TARGET) + controller.queue_behavior(/datum/ai_behavior/step_towards_turf, BB_CARP_MIGRATION_TARGET) + // We've gotten close enough to it, clear it so we can select a new point (or do nothing) + if(get_dist(controller.pawn, moving_to) <= CARP_DESTINATION_SEARCH_RANGE) + controller.clear_blackboard_key(BB_CARP_MIGRATION_TARGET) return SUBTREE_RETURN_FINISH_PLANNING - var/turf/next_step = get_step_towards(controller.pawn, moving_to) - if (next_step.is_blocked_turf(exclude_mobs = TRUE)) - controller.queue_behavior(/datum/ai_behavior/make_carp_rift/towards/unvalidated, BB_CARP_RIFT, BB_CARP_MIGRATION_TARGET) - controller.queue_behavior(/datum/ai_behavior/attack_obstructions/carp, BB_CARP_MIGRATION_TARGET) - controller.queue_behavior(/datum/ai_behavior/step_towards_turf, BB_CARP_MIGRATION_TARGET) - - return SUBTREE_RETURN_FINISH_PLANNING + // We have a path to follow but no destination, select one + if(length(controller.blackboard[BB_CARP_MIGRATION_PATH])) + controller.queue_behavior(/datum/ai_behavior/find_next_carp_migration_step, BB_CARP_MIGRATION_PATH, BB_CARP_MIGRATION_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING /** * # Find next carp migration step @@ -45,14 +42,13 @@ /datum/ai_behavior/find_next_carp_migration_step/perform(seconds_per_tick, datum/ai_controller/controller, path_key, target_key) var/list/blackboard_points = controller.blackboard[path_key] - var/list/potential_migration_points = blackboard_points.Copy() - while (length(potential_migration_points)) - var/turf/potential_destination = popleft(potential_migration_points) - if (!isnull(potential_destination) && get_dist(controller.pawn, potential_destination) > CARP_DESTINATION_SEARCH_RANGE) - controller.set_blackboard_key(target_key, potential_destination) + for(var/turf/migration_point as anything in blackboard_points) + // By the end of this loop we will either have a valid migration point set, or an empty list in our blackboard + blackboard_points -= migration_point + if(get_dist(controller.pawn, migration_point) > CARP_DESTINATION_SEARCH_RANGE) + controller.set_blackboard_key(target_key, migration_point) finish_action(controller, succeeded = TRUE) return - controller.set_blackboard_key(path_key, potential_migration_points.Copy()) finish_action(controller, succeeded = FALSE)