Targeting Datums Renamed (and global) (#79513)

## About The Pull Request

[Implements the backend required to make targeting datums
global](https://github.com/tgstation/tgstation/commit/6901ead12e419530b7f646ea21094d4432d7385e)

It's inconsistent with the rest of basic ai for these to have a high
degree of state, plus like, such a waste yaknow?

[Implements
GET_TARGETING_STRATEGY](https://github.com/tgstation/tgstation/commit/d79c29134d03424a9f8bacd64c08cb41775fe8c0)

Regexes used:
new.*(/datum/targetting_datum[^,(]*)\(*\)* -> GET_TARGETING_STRATEGY($1)

Renamed all instances of targetting to targeting (also targetting datum
-> targeting strategy)

I've used GET_TARGETING_STRATEGY at the source where the keys are
actually used, rather then in the listing. This works out just fine.

## Why It's Good For The Game

Not a misspelled name through the whole codebase, very slightly less
memory load for basically no downside (slight cpu cost maybe but not a
significant one.

---------

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
This commit is contained in:
LemonInTheDark
2023-11-09 14:44:24 +00:00
committed by GitHub
co-authored by John Willard
parent c6c1f3a578
commit 9696dd1a1d
155 changed files with 436 additions and 431 deletions
@@ -2,9 +2,9 @@
action_cooldown = 0.2 SECONDS // We gotta check unfortunately often because we're in a race condition with nextmove
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
/datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key)
. = ..()
if(!controller.blackboard_key_exists(targetting_datum_key))
if(!controller.blackboard[targeting_strategy_key])
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
//Hiding location is priority
@@ -14,7 +14,7 @@
set_movement_target(controller, target)
/datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
/datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key)
if (isliving(controller.pawn))
var/mob/living/pawn = controller.pawn
if (world.time < pawn.next_move)
@@ -22,15 +22,15 @@
. = ..()
var/mob/living/basic/basic_mob = controller.pawn
//targetting datum will kill the action if not real anymore
//targeting strategy will kill the action if not real anymore
var/atom/target = controller.blackboard[target_key]
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])
if(!targetting_datum.can_attack(basic_mob, target))
if(!targeting_strategy.can_attack(basic_mob, target))
finish_action(controller, FALSE, target_key)
return
var/hiding_target = targetting_datum.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something!
var/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something!
controller.set_blackboard_key(hiding_location_key, hiding_target)
@@ -40,7 +40,7 @@
basic_mob.melee_attack(target)
/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key)
/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key)
. = ..()
if(!succeeded)
controller.clear_blackboard_key(target_key)
@@ -54,30 +54,30 @@
///do we care about avoiding friendly fire?
var/avoid_friendly_fire = FALSE
/datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
/datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key)
. = ..()
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
if(QDELETED(target))
return FALSE
set_movement_target(controller, target)
/datum/ai_behavior/basic_ranged_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
/datum/ai_behavior/basic_ranged_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key)
var/mob/living/basic/basic_mob = controller.pawn
//targetting datum will kill the action if not real anymore
//targeting strategy will kill the action if not real anymore
var/atom/target = controller.blackboard[target_key]
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])
if(!targetting_datum.can_attack(basic_mob, target, chase_range))
if(!targeting_strategy.can_attack(basic_mob, target, chase_range))
finish_action(controller, FALSE, target_key)
return
var/atom/hiding_target = targetting_datum.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something!
var/atom/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something!
var/atom/final_target = hiding_target ? hiding_target : target
if(!can_see(basic_mob, final_target, required_distance))
return
if(avoid_friendly_fire && check_friendly_in_path(basic_mob, target, targetting_datum))
if(avoid_friendly_fire && check_friendly_in_path(basic_mob, target, targeting_strategy))
adjust_position(basic_mob, target)
return ..()
@@ -85,17 +85,17 @@
basic_mob.RangedAttack(final_target)
return ..() //only start the cooldown when the shot is shot
/datum/ai_behavior/basic_ranged_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key)
/datum/ai_behavior/basic_ranged_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key)
. = ..()
if(!succeeded)
controller.clear_blackboard_key(target_key)
/datum/ai_behavior/basic_ranged_attack/proc/check_friendly_in_path(mob/living/source, atom/target, datum/targetting_datum/targetting_datum)
/datum/ai_behavior/basic_ranged_attack/proc/check_friendly_in_path(mob/living/source, atom/target, datum/targeting_strategy/targeting_strategy)
var/list/turfs_list = calculate_trajectory(source, target)
for(var/turf/possible_turf as anything in turfs_list)
for(var/mob/living/potential_friend in possible_turf)
if(!targetting_datum.can_attack(source, potential_friend))
if(!targeting_strategy.can_attack(source, potential_friend))
return TRUE
return FALSE
@@ -7,16 +7,16 @@
/// Static typecache list of potentially dangerous objs
var/static/list/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha))
/datum/ai_behavior/find_potential_targets/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
/datum/ai_behavior/find_potential_targets/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key)
. = ..()
var/mob/living/living_mob = controller.pawn
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])
if(!targetting_datum)
if(!targeting_strategy)
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
var/atom/current_target = controller.blackboard[target_key]
if (targetting_datum.can_attack(living_mob, current_target, vision_range))
if (targeting_strategy.can_attack(living_mob, current_target, vision_range))
finish_action(controller, succeeded = FALSE)
return
@@ -37,7 +37,7 @@
var/list/filtered_targets = list()
for(var/atom/pot_target in potential_targets)
if(targetting_datum.can_attack(living_mob, pot_target))//Can we attack it?
if(targeting_strategy.can_attack(living_mob, pot_target))//Can we attack it?
filtered_targets += pot_target
continue
@@ -48,7 +48,7 @@
var/atom/target = pick_final_target(controller, filtered_targets)
controller.set_blackboard_key(target_key, target)
var/atom/potential_hiding_location = targetting_datum.find_hidden_mobs(living_mob, target)
var/atom/potential_hiding_location = targeting_strategy.find_hidden_mobs(living_mob, target)
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)
@@ -18,7 +18,7 @@
. = ..()
var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent = controller.blackboard[target_key] || controller.blackboard[BB_ENTRY_VENT_TARGET]
var/mob/living/cached_pawn = controller.pawn
if(HAS_TRAIT(cached_pawn, TRAIT_MOVE_VENTCRAWLING) || !controller.blackboard[BB_CURRENTLY_TARGETTING_VENT] || !is_vent_valid(entry_vent))
if(HAS_TRAIT(cached_pawn, TRAIT_MOVE_VENTCRAWLING) || !controller.blackboard[BB_CURRENTLY_TARGETING_VENT] || !is_vent_valid(entry_vent))
return
if(!cached_pawn.can_enter_vent(entry_vent, provide_feedback = FALSE)) // we're an AI we scoff at feedback
@@ -30,7 +30,7 @@
finish_action(controller, FALSE, target_key)
return
controller.set_blackboard_key(BB_CURRENTLY_TARGETTING_VENT, FALSE) // must be done here because we have a do_after sleep in handle_ventcrawl unfortunately and double dipping could lead to erroneous suicide pill calls.
controller.set_blackboard_key(BB_CURRENTLY_TARGETING_VENT, FALSE) // must be done here because we have a do_after sleep in handle_ventcrawl unfortunately and double dipping could lead to erroneous suicide pill calls.
cached_pawn.handle_ventcrawl(entry_vent)
if(!HAS_TRAIT(cached_pawn, TRAIT_MOVE_VENTCRAWLING)) //something failed and we ARE NOT IN THE VENT even though the earlier check said we were good to go! odd.
finish_action(controller, FALSE, target_key)
@@ -134,5 +134,5 @@
controller.clear_blackboard_key(target_key)
controller.clear_blackboard_key(BB_ENTRY_VENT_TARGET)
controller.clear_blackboard_key(BB_EXIT_VENT_TARGET)
controller.set_blackboard_key(BB_CURRENTLY_TARGETTING_VENT, FALSE) // just in case
controller.set_blackboard_key(BB_CURRENTLY_TARGETING_VENT, FALSE) // just in case
@@ -12,19 +12,19 @@
var/mob/living/pawn = controller.pawn
if (LAZYLEN(pawn.do_afters))
return
controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
/// Attack something which is already adjacent to us without moving
/datum/ai_behavior/basic_melee_attack/opportunistic
action_cooldown = 0.2 SECONDS // We gotta check unfortunately often because we're in a race condition with nextmove
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/basic_melee_attack/opportunistic/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
if (!controller.blackboard_key_exists(targetting_datum_key))
/datum/ai_behavior/basic_melee_attack/opportunistic/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key)
if (!controller.blackboard_key_exists(targeting_strategy_key))
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
return controller.blackboard_key_exists(target_key)
/datum/ai_behavior/basic_melee_attack/opportunistic/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
/datum/ai_behavior/basic_melee_attack/opportunistic/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key)
var/atom/movable/atom_pawn = controller.pawn
if(!atom_pawn.CanReach(controller.blackboard[target_key]))
finish_action(controller, TRUE, target_key) // Don't clear target
@@ -74,7 +74,7 @@
return FALSE
if (basic_mob.see_invisible < object.invisibility)
return FALSE
var/list/whitelist = basic_mob.ai_controller.blackboard[BB_OBSTACLE_TARGETTING_WHITELIST]
var/list/whitelist = basic_mob.ai_controller.blackboard[BB_OBSTACLE_TARGETING_WHITELIST]
if(whitelist && !is_type_in_typecache(object, whitelist))
return FALSE
@@ -1,19 +1,19 @@
/// Add or remove people to our retaliation shitlist just on an arbitrary whim
/datum/ai_planning_subtree/capricious_retaliate
/// Blackboard key which tells us how to select valid targets
var/targetting_datum_key = BB_TARGETTING_DATUM
var/targeting_strategy_key = BB_TARGETING_STRATEGY
/// Whether we should skip checking faction for our decision
var/ignore_faction = TRUE
/datum/ai_planning_subtree/capricious_retaliate/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
. = ..()
controller.queue_behavior(/datum/ai_behavior/capricious_retaliate, targetting_datum_key, ignore_faction)
controller.queue_behavior(/datum/ai_behavior/capricious_retaliate, targeting_strategy_key, ignore_faction)
/// Add or remove people to our retaliation shitlist just on an arbitrary whim
/datum/ai_behavior/capricious_retaliate
action_cooldown = 1 SECONDS
/datum/ai_behavior/capricious_retaliate/perform(seconds_per_tick, datum/ai_controller/controller, targetting_datum_key, ignore_faction)
/datum/ai_behavior/capricious_retaliate/perform(seconds_per_tick, datum/ai_controller/controller, targeting_strategy_key, ignore_faction)
. = ..()
var/atom/pawn = controller.pawn
if (controller.blackboard_key_exists(BB_BASIC_MOB_RETALIATE_LIST))
@@ -35,10 +35,10 @@
var/aggro_range = controller.blackboard[BB_AGGRO_RANGE] || 9
var/list/potential_targets = hearers(aggro_range, get_turf(pawn)) - pawn
if (!length(potential_targets))
failed_targetting(controller, pawn, ignore_faction)
failed_targeting(controller, pawn, ignore_faction)
return
var/datum/targetting_datum/target_helper = controller.blackboard[targetting_datum_key]
var/datum/targeting_strategy/target_helper = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])
var/mob/living/final_target = null
if (ignore_faction)
@@ -49,7 +49,7 @@
final_target = test_target
if (isnull(final_target))
failed_targetting(controller, pawn, ignore_faction)
failed_targeting(controller, pawn, ignore_faction)
return
controller.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, final_target)
@@ -57,7 +57,7 @@
finish_action(controller, TRUE, ignore_faction)
/// Called if we try but fail to target something
/datum/ai_behavior/capricious_retaliate/proc/failed_targetting(datum/ai_controller/controller, atom/pawn, ignore_faction)
/datum/ai_behavior/capricious_retaliate/proc/failed_targeting(datum/ai_controller/controller, atom/pawn, ignore_faction)
finish_action(controller, FALSE, ignore_faction)
pawn.visible_message(span_notice("[pawn] grumbles.")) // We're pissed off but with no outlet to vent our frustration upon
@@ -20,7 +20,7 @@
return SUBTREE_RETURN_FINISH_PLANNING //we gotta get out of here.
/// Try to escape from your current target, without performing any other actions.
/// Reads from some fleeing-specific targetting keys rather than the current mob target.
/// Reads from some fleeing-specific targeting keys rather than the current mob target.
/datum/ai_planning_subtree/flee_target/from_flee_key
target_key = BB_BASIC_MOB_FLEE_TARGET
hiding_place_key = BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION
@@ -15,6 +15,6 @@
controller.queue_behavior(/datum/ai_behavior/travel_towards, BB_ENTRY_VENT_TARGET)
return
controller.set_blackboard_key(BB_CURRENTLY_TARGETTING_VENT, TRUE)
controller.set_blackboard_key(BB_CURRENTLY_TARGETING_VENT, TRUE)
controller.queue_behavior(/datum/ai_behavior/crawl_through_vents, BB_ENTRY_VENT_TARGET)
return SUBTREE_RETURN_FINISH_PLANNING // we are going into this vent... no distractions
@@ -14,30 +14,30 @@
. = ..()
if(!controller.blackboard_key_exists(target_key))
return
controller.queue_behavior(attack_behavior, target_key, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION, max_range, min_range)
controller.queue_behavior(attack_behavior, target_key, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION, max_range, min_range)
/// How often will we try to perform our ranged attack?
/datum/ai_behavior/ranged_skirmish
action_cooldown = 1 SECONDS
/datum/ai_behavior/ranged_skirmish/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, max_range, min_range)
/datum/ai_behavior/ranged_skirmish/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, max_range, min_range)
. = ..()
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
return !QDELETED(target)
/datum/ai_behavior/ranged_skirmish/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, max_range, min_range)
/datum/ai_behavior/ranged_skirmish/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, max_range, min_range)
. = ..()
var/atom/target = controller.blackboard[target_key]
if (QDELETED(target))
finish_action(controller, succeeded = FALSE)
return
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
if(!targetting_datum.can_attack(controller.pawn, target))
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])
if(!targeting_strategy.can_attack(controller.pawn, target))
finish_action(controller, succeeded = FALSE)
return
var/hiding_target = targetting_datum.find_hidden_mobs(controller.pawn, target)
var/hiding_target = targeting_strategy.find_hidden_mobs(controller.pawn, target)
controller.set_blackboard_key(hiding_location_key, hiding_target)
target = hiding_target || target
@@ -8,7 +8,7 @@
. = ..()
if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))
return
controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
if (end_planning)
return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions.
@@ -20,5 +20,5 @@
. = ..()
if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))
return
controller.queue_behavior(ranged_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
controller.queue_behavior(ranged_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions.
@@ -5,11 +5,11 @@
. = ..()
if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING])
return
controller.queue_behavior(/datum/ai_behavior/find_potential_targets/nearest, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
controller.queue_behavior(/datum/ai_behavior/find_potential_targets/nearest, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
/// Find the nearest thing on our list of 'things which have done damage to me' and set it as the flee target
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee
var/targeting_key = BB_TARGETTING_DATUM
var/targeting_key = BB_TARGETING_STRATEGY
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
. = ..()
@@ -18,4 +18,4 @@
controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, BB_BASIC_MOB_CURRENT_TARGET, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key
targeting_key = BB_FLEE_TARGETTING_DATUM
targeting_key = BB_FLEE_TARGETING_STRATEGY
@@ -2,7 +2,7 @@
/datum/ai_planning_subtree/simple_find_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
. = ..()
controller.queue_behavior(/datum/ai_behavior/find_potential_targets, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
controller.queue_behavior(/datum/ai_behavior/find_potential_targets, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
// Prevents finding a target if a human is nearby
/datum/ai_planning_subtree/simple_find_target/not_while_observed
@@ -3,4 +3,4 @@
/datum/ai_planning_subtree/simple_find_wounded_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
. = ..()
controller.queue_behavior(/datum/ai_behavior/find_potential_targets/most_wounded, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
controller.queue_behavior(/datum/ai_behavior/find_potential_targets/most_wounded, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
@@ -2,7 +2,7 @@
/datum/ai_planning_subtree/target_retaliate
operational_datums = list(/datum/element/ai_retaliate, /datum/component/ai_retaliate_advanced)
/// Blackboard key which tells us how to select valid targets
var/targetting_datum_key = BB_TARGETTING_DATUM
var/targeting_strategy_key = BB_TARGETING_STRATEGY
/// Blackboard key in which to store selected target
var/target_key = BB_BASIC_MOB_CURRENT_TARGET
/// Blackboard key in which to store selected target's hiding place
@@ -12,16 +12,16 @@
/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, check_faction)
controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_strategy_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
/// Can use a different targeting strategy than you use to select attack targets
/// Not required if fleeing is the only target behaviour or uses the same target datum
/datum/ai_planning_subtree/target_retaliate/to_flee
targetting_datum_key = BB_FLEE_TARGETTING_DATUM
targeting_strategy_key = BB_FLEE_TARGETING_STRATEGY
target_key = BB_BASIC_MOB_FLEE_TARGET
hiding_place_key = BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION
@@ -34,11 +34,11 @@
/// 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, check_faction)
/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targeting_strategy_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)
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])
if(!targeting_strategy)
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
var/list/shitlist = controller.blackboard[shitlist_key]
@@ -47,13 +47,13 @@
if (!check_faction)
controller.set_blackboard_key(BB_TEMPORARILY_IGNORE_FACTION, TRUE)
if (!QDELETED(existing_target) && (locate(existing_target) in shitlist) && targetting_datum.can_attack(living_mob, existing_target, vision_range))
if (!QDELETED(existing_target) && (locate(existing_target) in shitlist) && targeting_strategy.can_attack(living_mob, existing_target, vision_range))
finish_action(controller, succeeded = TRUE, check_faction = check_faction)
return
var/list/enemies_list = list()
for(var/mob/living/potential_target as anything in shitlist)
if(!targetting_datum.can_attack(living_mob, potential_target, vision_range))
if(!targeting_strategy.can_attack(living_mob, potential_target, vision_range))
continue
enemies_list += potential_target
@@ -65,7 +65,7 @@
var/atom/new_target = pick_final_target(controller, enemies_list)
controller.set_blackboard_key(target_key, new_target)
var/atom/potential_hiding_location = targetting_datum.find_hidden_mobs(living_mob, new_target)
var/atom/potential_hiding_location = targeting_strategy.find_hidden_mobs(living_mob, new_target)
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)
@@ -1,7 +1,7 @@
/// The most basic AI tree which just finds a guy and then runs at them to click them
/datum/ai_controller/basic_controller/simple_hostile
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
)
ai_movement = /datum/ai_movement/basic_avoidance
@@ -14,7 +14,7 @@
/// Find a target, walk at target, attack intervening obstacles
/datum/ai_controller/basic_controller/simple_hostile_obstacles
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
)
ai_movement = /datum/ai_movement/basic_avoidance
@@ -1,18 +1,19 @@
///Datum for basic mobs to define what they can attack.
/datum/targetting_datum
///Datum for basic mobs to define what they can attack.GET_TARGETING_STRATEGY\((/[^,]*)\),
///Global, just like ai_behaviors
/datum/targeting_strategy
///Returns true or false depending on if the target can be attacked by the mob
/datum/targetting_datum/proc/can_attack(mob/living/living_mob, atom/target, vision_range)
/datum/targeting_strategy/proc/can_attack(mob/living/living_mob, atom/target, vision_range)
return
///Returns something the target might be hiding inside of
/datum/targetting_datum/proc/find_hidden_mobs(mob/living/living_mob, atom/target)
/datum/targeting_strategy/proc/find_hidden_mobs(mob/living/living_mob, atom/target)
var/atom/target_hiding_location
if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper))
target_hiding_location = target.loc
return target_hiding_location
/datum/targetting_datum/basic
/datum/targeting_strategy/basic
/// When we do our basic faction check, do we look for exact faction matches?
var/check_factions_exactly = FALSE
/// Whether we care for seeing the target or not
@@ -22,7 +23,7 @@
/// If this blackboard key is TRUE, makes us only target wounded mobs
var/target_wounded_key
/datum/targetting_datum/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range)
/datum/targeting_strategy/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range)
var/datum/ai_controller/basic_controller/our_controller = living_mob.ai_controller
if(isnull(our_controller))
@@ -82,29 +83,29 @@
return FALSE
/// Returns true if the mob and target share factions
/datum/targetting_datum/basic/proc/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)
/datum/targeting_strategy/basic/proc/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)
if (controller.blackboard[BB_ALWAYS_IGNORE_FACTION] || controller.blackboard[BB_TEMPORARILY_IGNORE_FACTION])
return FALSE
return living_mob.faction_check_atom(the_target, exact_match = check_factions_exactly)
/// Subtype more forgiving for items.
/// Careful, this can go wrong and keep a mob hyper-focused on an item it can't lose aggro on
/datum/targetting_datum/basic/allow_items
/datum/targeting_strategy/basic/allow_items
/datum/targetting_datum/basic/allow_items/can_attack(mob/living/living_mob, atom/the_target, vision_range)
/datum/targeting_strategy/basic/allow_items/can_attack(mob/living/living_mob, atom/the_target, vision_range)
. = ..()
if(isitem(the_target))
// trust fall exercise
return TRUE
/// Subtype which searches for mobs of a size relative to ours
/datum/targetting_datum/basic/of_size
/datum/targeting_strategy/basic/of_size
/// If true, we will return mobs which are smaller than us. If false, larger.
var/find_smaller = TRUE
/// If true, we will return mobs which are the same size as us.
var/inclusive = TRUE
/datum/targetting_datum/basic/of_size/can_attack(mob/living/owner, atom/target, vision_range)
/datum/targeting_strategy/basic/of_size/can_attack(mob/living/owner, atom/target, vision_range)
if(!isliving(target))
return FALSE
. = ..()
@@ -119,14 +120,14 @@
return !find_smaller
// This is just using the default values but the subtype makes it clearer
/datum/targetting_datum/basic/of_size/ours_or_smaller
/datum/targeting_strategy/basic/of_size/ours_or_smaller
/datum/targetting_datum/basic/of_size/larger
/datum/targeting_strategy/basic/of_size/larger
find_smaller = FALSE
inclusive = FALSE
/// Makes the mob only attack their own faction. Useful mostly if their attacks do something helpful (e.g. healing touch).
/datum/targetting_datum/basic/same_faction
/datum/targeting_strategy/basic/same_faction
/datum/targetting_datum/basic/same_faction/faction_check(mob/living/living_mob, mob/living/the_target)
/datum/targeting_strategy/basic/same_faction/faction_check(mob/living/living_mob, mob/living/the_target)
return !..() // inverts logic to ONLY target mobs that share a faction
@@ -1,12 +1,12 @@
/// Don't target an atom in our friends list (or turfs), anything else is fair game
/datum/targetting_datum/basic/not_friends
/datum/targeting_strategy/basic/not_friends
/// Stop regarding someone as a valid target once they pass this stat level, setting it to DEAD means you will happily attack corpses
var/attack_until_past_stat = HARD_CRIT
/// If we can try to closed turfs or not
var/attack_closed_turf = FALSE
///Returns true or false depending on if the target can be attacked by the mob
/datum/targetting_datum/basic/not_friends/can_attack(mob/living/living_mob, atom/target, vision_range)
/datum/targeting_strategy/basic/not_friends/can_attack(mob/living/living_mob, atom/target, vision_range)
if(attack_closed_turf && isclosedturf(target))
return TRUE
@@ -16,16 +16,16 @@
return ..()
///friends dont care about factions
/datum/targetting_datum/basic/not_friends/faction_check(mob/living/living_mob, mob/living/the_target)
/datum/targeting_strategy/basic/not_friends/faction_check(mob/living/living_mob, mob/living/the_target)
return FALSE
/datum/targetting_datum/basic/not_friends/attack_closed_turfs
/datum/targeting_strategy/basic/not_friends/attack_closed_turfs
attack_closed_turf = TRUE
/// Subtype that allows us to target items while deftly avoiding attacking our allies. Be careful when it comes to targetting items as an AI could get trapped targetting something it can't destroy.
/datum/targetting_datum/basic/not_friends/allow_items
/// Subtype that allows us to target items while deftly avoiding attacking our allies. Be careful when it comes to targeting items as an AI could get trapped targeting something it can't destroy.
/datum/targeting_strategy/basic/not_friends/allow_items
/datum/targetting_datum/basic/not_friends/allow_items/can_attack(mob/living/living_mob, atom/the_target, vision_range)
/datum/targeting_strategy/basic/not_friends/allow_items/can_attack(mob/living/living_mob, atom/the_target, vision_range)
. = ..()
if(isitem(the_target))
// trust fall exercise
@@ -0,0 +1,29 @@
/**
* Find mobs who are holding the bb configurable object type
*
* This is an extension of basic targeting behaviour, that allows you to
* only target the mob if they have a specific item in their hand.
*
*/
/datum/targeting_strategy/basic/holding_object
/// BB key that holds the target typepath to use
var/target_item_key = BB_TARGET_HELD_ITEM
///Returns true or false depending on if the target can be attacked by the mob
/datum/targeting_strategy/basic/holding_object/can_attack(mob/living/living_mob, atom/target, vision_range)
var/datum/ai_controller/controller = living_mob.ai_controller
var/object_type_path = controller.blackboard[target_item_key]
if (object_type_path == null)
return FALSE // no op
if(!ismob(target))
return FALSE // no hands no problems
// Look at me, type casting like a grown up
var/mob/targetmob = target
// Check if our parent behaviour agrees we can attack this target (we ignore faction by default)
var/can_attack = ..()
if(can_attack && targetmob.is_holding_item_of_type(object_type_path))
return TRUE // they have the item
// No valid target
return FALSE
@@ -1,39 +0,0 @@
/**
* Find mobs who are holding the configurable object type
*
* This is an extension of basic targeting behaviour, that allows you to
* only target the mob if they have a specific item in their hand.
*
*/
/datum/targetting_datum/basic/holding_object
// We will find mobs who are holding this object in their hands
var/object_type_path = null
/**
* Create an instance of the holding object targeting datum
*
* * object_type_path Pass an object type path, this will be compared to the items
* in targets hands to filter the target list.
*/
/datum/targetting_datum/basic/holding_object/New(object_type_path)
if (!ispath(object_type_path))
stack_trace("trying to create an item targeting datum with no valid typepath")
// Leaving object type as null will make this basically a noop
return
src.object_type_path = object_type_path
///Returns true or false depending on if the target can be attacked by the mob
/datum/targetting_datum/basic/holding_object/can_attack(mob/living/living_mob, atom/target, vision_range)
if (object_type_path == null)
return FALSE // no op
if(!ismob(target))
return FALSE // no hands no problems
// Look at me, type casting like a grown up
var/mob/targetmob = target
// Check if our parent behaviour agrees we can attack this target (we ignore faction by default)
var/can_attack = ..()
if(can_attack && targetmob.is_holding_item_of_type(object_type_path))
return TRUE // they have the item
// No valid target
return FALSE