Files
Bubberstation/code/datums/ai/generic/find_and_set.dm

200 lines
7.3 KiB
Plaintext

/**find and set
* Finds an item near themselves, sets a blackboard key as it. Very useful for ais that need to use machines or something.
* if you want to do something more complicated than find a single atom, change the search_tactic() proc
* cool tip: search_tactic() can set lists
*/
/datum/ai_behavior/find_and_set
action_cooldown = 2 SECONDS
/datum/ai_behavior/find_and_set/perform(seconds_per_tick, datum/ai_controller/controller, set_key, locate_path, search_range)
if (controller.blackboard_key_exists(set_key))
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
if(QDELETED(controller.pawn))
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
var/find_this_thing = search_tactic(controller, locate_path, search_range)
if(isnull(find_this_thing))
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
controller.set_blackboard_key(set_key, find_this_thing)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
/datum/ai_behavior/find_and_set/proc/search_tactic(datum/ai_controller/controller, locate_path, search_range = 3)
return locate(locate_path) in oview(search_range, controller.pawn)
/**
* Variant of find and set that fails if the living pawn doesn't hold something
*/
/datum/ai_behavior/find_and_set/pawn_must_hold_item
/datum/ai_behavior/find_and_set/pawn_must_hold_item/search_tactic(datum/ai_controller/controller)
var/mob/living/living_pawn = controller.pawn
if(!living_pawn.get_num_held_items())
return //we want to fail the search if we don't have something held
return ..()
/**
* Variant of find and set that also requires the item to be edible. checks hands too
*/
/datum/ai_behavior/find_and_set/edible
/datum/ai_behavior/find_and_set/edible/search_tactic(datum/ai_controller/controller, locate_path, search_range)
var/mob/living/living_pawn = controller.pawn
for(var/atom/held_candidate as anything in living_pawn.held_items)
if(IsEdible(held_candidate))
return held_candidate
for(var/atom/local_candidate as anything in oview(search_range, controller.pawn))
if(IsEdible(local_candidate) && istype(local_candidate, locate_path))
return local_candidate
return null
/**
* Variant of find and set that only checks in hands, search range should be excluded for this
*/
/datum/ai_behavior/find_and_set/in_hands
/datum/ai_behavior/find_and_set/in_hands/search_tactic(datum/ai_controller/controller, locate_path)
var/mob/living/living_pawn = controller.pawn
return locate(locate_path) in living_pawn.held_items
/datum/ai_behavior/find_and_set/in_hands/given_list
/datum/ai_behavior/find_and_set/in_hands/given_list/search_tactic(datum/ai_controller/controller, locate_paths)
var/list/found = typecache_filter_list(controller.pawn, locate_paths)
if(length(found))
return pick(found)
/**
* Variant of find and set that takes a list of things to find.
*/
/datum/ai_behavior/find_and_set/in_list
/datum/ai_behavior/find_and_set/in_list/search_tactic(datum/ai_controller/controller, locate_paths, search_range)
var/list/found = typecache_filter_list(oview(search_range, controller.pawn), locate_paths)
if(length(found))
return pick(found)
/// Like find_and_set/in_list, but we return the turf location of the item instead of the item itself.
/datum/ai_behavior/find_and_set/in_list/turf_location
/datum/ai_behavior/find_and_set/in_list/turf_location/search_tactic(datum/ai_controller/controller, locate_paths, search_range)
. = ..()
if(isnull(.))
return null
return get_turf(.)
/**
* Variant of find and set which returns an object which can be animated with a staff of change
*/
/datum/ai_behavior/find_and_set/animatable
/datum/ai_behavior/find_and_set/animatable/search_tactic(datum/ai_controller/controller, locate_path, search_range)
var/mob/living/living_pawn = controller.pawn
var/list/nearby_items = list()
for (var/obj/new_friend in oview(search_range, controller.pawn))
if (!isitem(new_friend) && !isstructure(new_friend))
continue
if (is_type_in_list(new_friend, GLOB.animatable_blacklist))
continue
if (living_pawn.see_invisible < new_friend.invisibility)
continue
nearby_items += new_friend
if(nearby_items.len)
return pick(nearby_items)
/**
* Variant of find and set which returns the nearest wall which isn't invulnerable
*/
/datum/ai_behavior/find_and_set/nearest_wall
/datum/ai_behavior/find_and_set/nearest_wall/search_tactic(datum/ai_controller/controller, locate_path, search_range)
var/mob/living/living_pawn = controller.pawn
var/list/nearby_walls = list()
for (var/turf/closed/new_wall in oview(search_range, controller.pawn))
if (isindestructiblewall(new_wall))
continue
nearby_walls += new_wall
if(nearby_walls.len)
return get_closest_atom(/turf/closed/, nearby_walls, living_pawn)
/**
* Variant of find and set which returns corpses who share your faction
*/
/datum/ai_behavior/find_and_set/friendly_corpses
/datum/ai_behavior/find_and_set/friendly_corpses/search_tactic(datum/ai_controller/controller, locate_path, search_range)
var/mob/living/living_pawn = controller.pawn
var/list/nearby_bodies = list()
for (var/mob/living/dead_pal in oview(search_range, controller.pawn))
if (!isturf(dead_pal.loc))
continue
if (!dead_pal.stat || dead_pal.health > 0)
continue
if (living_pawn.see_invisible < dead_pal.invisibility)
continue
if (!living_pawn.faction_check_atom(dead_pal))
continue
nearby_bodies += dead_pal
if (nearby_bodies.len)
return pick(nearby_bodies)
/**
* A variant that looks for a human who is not dead or incapacitated, and has a mind
*/
/datum/ai_behavior/find_and_set/conscious_person
/datum/ai_behavior/find_and_set/conscious_person/search_tactic(datum/ai_controller/controller, locate_path, search_range)
var/list/customers = list()
for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn))
if(IS_DEAD_OR_INCAP(target) || !target.mind)
continue
customers += target
if(customers.len)
return pick(customers)
return null
/datum/ai_behavior/find_and_set/nearby_friends
action_cooldown = 2 SECONDS
/datum/ai_behavior/find_and_set/nearby_friends/search_tactic(datum/ai_controller/controller, locate_path, search_range)
var/atom/friend = locate(/mob/living/carbon/human) in oview(search_range, controller.pawn)
if(isnull(friend))
return null
var/mob/living/living_pawn = controller.pawn
var/potential_friend = living_pawn.faction.Find(REF(friend)) ? friend : null
return potential_friend
/datum/ai_behavior/find_and_set/in_list/turf_types
/datum/ai_behavior/find_and_set/in_list/turf_types/search_tactic(datum/ai_controller/controller, locate_paths, search_range)
var/list/found = RANGE_TURFS(search_range, controller.pawn)
shuffle_inplace(found)
for(var/turf/possible_turf as anything in found)
if(!is_type_in_typecache(possible_turf, locate_paths))
continue
if(can_see(controller.pawn, possible_turf, search_range))
return possible_turf
return null
/datum/ai_behavior/find_and_set/in_list/closest_turf
/datum/ai_behavior/find_and_set/in_list/closest_turf/search_tactic(datum/ai_controller/controller, locate_paths, search_range)
var/list/found = RANGE_TURFS(search_range, controller.pawn)
for(var/turf/possible_turf as anything in found)
if(!is_type_in_typecache(possible_turf, locate_paths) || !can_see(controller.pawn, possible_turf, search_range))
found -= possible_turf
return (length(found)) ? get_closest_atom(/turf, found, controller.pawn) : null