diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 7003e812c9f..c71b1a4acd5 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -85,3 +85,6 @@ #define BB_MOD_IMPLANT "BB_mod_implant" ///Range for a MOD AI controller. #define MOD_AI_RANGE 200 + +///should we skip the faction check for the targetting datum? +#define BB_BASIC_MOB_SKIP_FACTION_CHECK "BB_basic_mob_skip_faction_check" diff --git a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm index 2d553fe4b2f..6133759183d 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm @@ -7,10 +7,15 @@ var/target_key = BB_BASIC_MOB_CURRENT_TARGET /// Blackboard key in which to store selected target's hiding place var/hiding_place_key = BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION + /// do we check for faction? + var/check_faction = FALSE /datum/ai_planning_subtree/target_retaliate/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targetting_datum_key, hiding_place_key) + controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targetting_datum_key, hiding_place_key, check_faction) + +/datum/ai_planning_subtree/target_retaliate/check_faction + check_faction = TRUE /// Places a mob which you can see and who has recently attacked you into some 'run away from this' AI keys /// Can use a different targetting datum than you use to select attack targets @@ -29,20 +34,28 @@ /// How far can we see stuff? var/vision_range = 9 -/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targetting_datum_key, hiding_location_key, check_faction) . = ..() var/mob/living/living_mob = controller.pawn var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] if(!targetting_datum) CRASH("No target datum was supplied in the blackboard for [controller.pawn]") - var/list/enemies_list = controller.blackboard[shitlist_key] - if (!length(enemies_list)) - finish_action(controller, succeeded = FALSE) + + var/list/enemies_list = list() + + for(var/mob/living/potential_target as anything in controller.blackboard[shitlist_key]) + if(!targetting_datum.can_attack(living_mob, potential_target, vision_range, check_faction)) + continue + enemies_list += potential_target + + + if(!length(enemies_list)) + finish_action(controller, succeeded = FALSE, check_faction = check_faction) return if (controller.blackboard[target_key] in enemies_list) // Don't bother changing - finish_action(controller, succeeded = FALSE) + finish_action(controller, succeeded = TRUE, check_faction = check_faction) return var/atom/new_target = pick_final_target(controller, enemies_list) @@ -53,18 +66,15 @@ if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially. controller.set_blackboard_key(hiding_location_key, potential_hiding_location) - finish_action(controller, succeeded = TRUE) - -/// Returns true if this target is valid for attacking based on current conditions -/datum/ai_behavior/target_from_retaliate_list/proc/can_attack_target(mob/living/living_mob, atom/target, datum/targetting_datum/targetting_datum) - if (!target) - return FALSE - if (target == living_mob) - return FALSE - if (!can_see(living_mob, target, vision_range)) - return FALSE - return targetting_datum.can_attack(living_mob, target) + finish_action(controller, succeeded = TRUE, check_faction = check_faction) /// Returns the desired final target from the filtered list of enemies /datum/ai_behavior/target_from_retaliate_list/proc/pick_final_target(datum/ai_controller/controller, list/enemies_list) return pick(enemies_list) + + +/datum/ai_behavior/target_from_retaliate_list/finish_action(datum/ai_controller/controller, succeeded, target_key, check_faction) + . = ..() + if(check_faction) + return + controller.set_blackboard_key(BB_BASIC_MOB_SKIP_FACTION_CHECK, succeeded) diff --git a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm b/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm index 643089bb5ea..43b974219e2 100644 --- a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm +++ b/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm @@ -20,7 +20,12 @@ ///Whether we care for seeing the target or not var/ignore_sight = FALSE -/datum/targetting_datum/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range) +/datum/targetting_datum/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range, check_faction = TRUE) + var/datum/ai_controller/basic_controller/our_controller = living_mob.ai_controller + + if(isnull(our_controller)) + return FALSE + if(isturf(the_target) || !the_target) // bail out on invalids return FALSE @@ -44,9 +49,13 @@ return FALSE if(isliving(the_target)) //Targeting vs living mobs - var/mob/living/L = the_target - if(faction_check(living_mob, L) || (L.stat > stat_attack)) + var/mob/living/living_target = the_target + var/bypass_faction_check = !check_faction || our_controller.blackboard[BB_BASIC_MOB_SKIP_FACTION_CHECK] + if(faction_check(living_mob, living_target) && !bypass_faction_check) return FALSE + if(living_target.stat > stat_attack) + return FALSE + return TRUE if(ismecha(the_target)) //Targeting vs mechas diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm index 83369de8862..c433ec936ad 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm @@ -9,7 +9,7 @@ ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( - /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/target_retaliate/check_faction, /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/find_food, /datum/ai_planning_subtree/targeted_mob_ability/goliath_tentacles, diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm index 7686c12ee3e..9b2972a398f 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm @@ -6,7 +6,7 @@ ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( - /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/target_retaliate/check_faction, /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/use_mob_ability/gaze, /datum/ai_planning_subtree/ranged_skirmish/watcher,