From 4f8b9f24183c8d7223eb3f447b9ecf5204963c0b Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:17:12 +0200 Subject: [PATCH] Makes tendrils less out for blood, cleans up The Thing's code (#96332) ## About The Pull Request I didn't realize that default aggro range for mobs is 9, so tendrils would try to attack you with their whips and spikes despite you being completely out of their range, which looks pretty funny. I've fixed this by separating out aggro ***grab*** range and aggro sustain ranges, lowering latter to 5 for tendrils, and adding checks for target distance for both abilities it has. The Thing also had a similar behavior but used rather jank code for that (which I don't think even worked), so I've modified it to use the new system as well. ## Why It's Good For The Game Stationary mobs probably shouldn't try to attack mobs completely out of their reach ## Changelog :cl: fix: Tendrils no longer try to attack you when you're out of their reach code: Cleaned up The Thing's aggro code /:cl: --- code/__DEFINES/ai/ai_blackboard.dm | 2 ++ .../basic_ai_behaviors/targeting.dm | 19 ++++++++++++++----- .../basic_subtrees/simple_find_target.dm | 4 ---- .../mob/living/basic/boss/thing/thing_ai.dm | 5 +++-- .../basic/lavaland/tendril/tendril_actions.dm | 4 +++- .../basic/lavaland/tendril/tendril_ai.dm | 9 +++++++-- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 660a4e3c82c..fdd8de59206 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -10,6 +10,8 @@ #define BB_FOOD_TARGET "bb_food_target" ///How close a mob must be for us to select it as a target, if that is less than how far we can maintain it as a target #define BB_AGGRO_RANGE "BB_aggro_range" +///If defined, mobs will use this distance instead of default aggro range to locate new targets +#define BB_AGGRO_GRAB_RANGE "BB_aggro_grab_range" ///are we hungry? determined by the udder component #define BB_CHECK_HUNGRY "BB_check_hungry" ///are we ready to breed? diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm index b2aaaa23578..ce46d4c1ab9 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm @@ -12,6 +12,8 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/ var/vision_range = 9 /// Blackboard key for aggro range, uses vision range if not specified var/aggro_range_key = BB_AGGRO_RANGE + /// Range in which we can acquire a new target + var/aggro_grab_range_key = BB_AGGRO_GRAB_RANGE /// Blackboard key for the target priority strategy var/priority_strategy_key = BB_TARGET_PRIORITY_STRATEGY /// If we have a priority strategy set, how often do we refresh our target search? @@ -34,7 +36,12 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/ if((!priority_strategy || controller.blackboard[BB_BASIC_MOB_TARGET_REFRESH_COOLDOWN] > world.time) && current_target && targeting_strategy.can_attack(living_mob, current_target, vision_range)) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED - var/aggro_range = controller.blackboard[aggro_range_key] || vision_range + var/aggro_range = vision_range + if(isnull(current_target) && !isnull(controller.blackboard[aggro_grab_range_key])) + aggro_range = controller.blackboard[aggro_grab_range_key] + else if(!isnull(controller.blackboard[aggro_range_key])) + aggro_range = controller.blackboard[aggro_range_key] + controller.clear_blackboard_key(target_key) // If we're using a field rn, just don't do anything yeah? @@ -87,7 +94,12 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/ return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/find_potential_targets/proc/failed_to_find_anyone(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) - var/aggro_range = controller.blackboard[aggro_range_key] || vision_range + var/aggro_range = vision_range + if(!isnull(controller.blackboard[aggro_grab_range_key])) + aggro_range = controller.blackboard[aggro_grab_range_key] + else if(!isnull(controller.blackboard[aggro_range_key])) + aggro_range = controller.blackboard[aggro_range_key] + // takes the larger between our range() input and our implicit hearers() input (world.view) aggro_range = max(aggro_range, ROUND_UP(max(getviewsize(world.view)) / 2)) // Alright, here's the interesting bit @@ -187,6 +199,3 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/ if(length(priority_targets)) return ..(controller, priority_targets) return ..() - -/datum/ai_behavior/find_potential_targets/bigger_range - vision_range = 16 diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm index 9824d41f823..57fb22b4a95 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm @@ -22,9 +22,5 @@ /datum/ai_planning_subtree/simple_find_target/to_flee target_key = BB_BASIC_MOB_FLEE_TARGET -/datum/ai_planning_subtree/simple_find_target/increased_range - target_behavior = /datum/ai_behavior/find_potential_targets/bigger_range - /datum/ai_planning_subtree/simple_find_target/hunt strategy_key = BB_HUNT_TARGETING_STRATEGY - diff --git a/code/modules/mob/living/basic/boss/thing/thing_ai.dm b/code/modules/mob/living/basic/boss/thing/thing_ai.dm index be6033ec2b2..e8956cac2b1 100644 --- a/code/modules/mob/living/basic/boss/thing/thing_ai.dm +++ b/code/modules/mob/living/basic/boss/thing/thing_ai.dm @@ -5,14 +5,15 @@ BB_THETHING_ATTACKMODE = TRUE, //Whether we are using our melee abilities right now BB_THETHING_NOAOE = TRUE, // Restricts us to only melee abilities BB_THETHING_LASTAOE = null, // Last AOE ability key executed - BB_AGGRO_RANGE = 6, //lets not execute hearers for a 16 tile radius + BB_AGGRO_RANGE = 16, + BB_AGGRO_GRAB_RANGE = 6, ) ai_movement = /datum/ai_movement/basic_avoidance // dont need anything better because the arena is a square lol idle_behavior = null planning_subtrees = list( /datum/ai_planning_subtree/escape_captivity, - /datum/ai_planning_subtree/simple_find_target/increased_range, //aggros at 6, sees 16 tiles + /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/thing_boss_aoe, /datum/ai_planning_subtree/thing_boss_melee, ) diff --git a/code/modules/mob/living/basic/lavaland/tendril/tendril_actions.dm b/code/modules/mob/living/basic/lavaland/tendril/tendril_actions.dm index ba4bb3b219d..1a2272fd85b 100644 --- a/code/modules/mob/living/basic/lavaland/tendril/tendril_actions.dm +++ b/code/modules/mob/living/basic/lavaland/tendril/tendril_actions.dm @@ -266,6 +266,8 @@ cooldown_time = 10 SECONDS melee_cooldown_time = 0 shared_cooldown = NONE + /// Range in which we create spikes + var/spike_range = 7 /// Health threshold at which we reduce the amount of empty spots on the ground var/health_threshold = 0.3 @@ -288,7 +290,7 @@ if (as_living.health / as_living.maxHealth <= health_threshold) reduced_spawns = TRUE - for (var/turf/open/target_turf in oview(7, owner_turf)) + for (var/turf/open/target_turf in oview(spike_range, owner_turf)) if (sqrt((target_turf.x - owner_turf.x) ** 2 + (target_turf.y - owner_turf.y) ** 2) > 9.5) // big circle is a lie continue diff --git a/code/modules/mob/living/basic/lavaland/tendril/tendril_ai.dm b/code/modules/mob/living/basic/lavaland/tendril/tendril_ai.dm index 77da7086dfa..5da4fcedf28 100644 --- a/code/modules/mob/living/basic/lavaland/tendril/tendril_ai.dm +++ b/code/modules/mob/living/basic/lavaland/tendril/tendril_ai.dm @@ -2,6 +2,8 @@ blackboard = list( BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_TARGET_MINIMUM_STAT = HARD_CRIT, + BB_AGGRO_RANGE = 9, // Keeps an eye on you even if you flee + BB_AGGRO_GRAB_RANGE = 5, // Only aggros if you get real close and personal ) planning_subtrees = list( @@ -22,7 +24,8 @@ ability_key = BB_TENDRIL_LASH /datum/ai_planning_subtree/use_mob_ability/tendril_lash/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - if (!controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]) + var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + if (isnull(target) || get_dist(controller.pawn, target) > /obj/projectile/tentacle_lash::range) return FALSE return ..() @@ -30,6 +33,8 @@ ability_key = BB_TENDRIL_SPIKES /datum/ai_planning_subtree/use_mob_ability/tendril_spikes/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - if (!controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]) + var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + var/datum/action/cooldown/mob_cooldown/tendril_cross_spikes/ability = controller.blackboard[ability_key] + if (isnull(target) || !istype(ability) || get_dist(controller.pawn, target) > ability.spike_range) return FALSE return ..()