diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index baf166d2a7a..0c682f7d411 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -133,6 +133,9 @@ ///Range for a MOD AI controller. #define MOD_AI_RANGE 200 +///Only target mobs with these traits +#define BB_TARGET_ONLY_WITH_TRAITS "BB_target_only_with_traits" + ///should we skip the faction check for the targeting strategy? #define BB_ALWAYS_IGNORE_FACTION "BB_always_ignore_factions" ///are we in some kind of temporary state of ignoring factions when targeting? can result in volatile results if multiple behaviours touch this diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm index d9e0d1e7fb9..83e514f3270 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm @@ -21,4 +21,5 @@ controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key + target_key = BB_BASIC_MOB_FLEE_TARGET targeting_key = BB_FLEE_TARGETING_STRATEGY 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 42608730f98..759355283ac 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 @@ -1,8 +1,10 @@ /datum/ai_planning_subtree/simple_find_target + /// Variable to store target in + var/target_key = BB_BASIC_MOB_CURRENT_TARGET /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_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets, target_key, 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 @@ -12,3 +14,6 @@ if(watcher.stat != DEAD) return return ..() + +/datum/ai_planning_subtree/simple_find_target/to_flee + target_key = BB_BASIC_MOB_FLEE_TARGET diff --git a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm index 320e6abf0be..709acb8d5e8 100644 --- a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm +++ b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm @@ -88,6 +88,21 @@ // trust fall exercise return TRUE +/datum/targeting_strategy/basic/require_traits + +/datum/targeting_strategy/basic/require_traits/can_attack(mob/living/living_mob, atom/the_target, vision_range) + . = ..() + if (!.) + return FALSE + var/list/required_traits = living_mob.ai_controller.blackboard[BB_TARGET_ONLY_WITH_TRAITS] + if (!length(required_traits)) + return TRUE + + for (var/trait as anything in required_traits) + if (HAS_TRAIT(the_target, trait)) + return TRUE + return FALSE + /// Subtype which searches for mobs of a size relative to ours /datum/targeting_strategy/basic/of_size /// If true, we will return mobs which are smaller than us. If false, larger. diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index bf1abd371aa..cf56a01a684 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -45,6 +45,8 @@ maximum_survivable_temperature = 1500 death_offset_y = -10 + /// If true we will run away from attackers even at full health + var/cowardly = FALSE /// Cytology cells you can swab from this creature var/cell_line = CELL_LINE_TABLE_CARP /// What colour is our 'healing' outline? @@ -89,7 +91,8 @@ if (cell_line) AddElement(/datum/element/swabable, cell_line, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) AddElement(/datum/element/simple_flying) - AddElement(/datum/element/ai_flee_while_injured) + if (!cowardly) + AddElement(/datum/element/ai_flee_while_injured) setup_eating() AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("gnashes"))) @@ -268,8 +271,8 @@ ///Wild carp that just vibe ya know /mob/living/basic/carp/passive - name = "passive carp" - desc = "A timid, sucker-bearing creature that resembles a fish. " + name = "false carp" + desc = "A close relative of the space carp which is entirely toothless and feeds by stealing its cousin's leftovers." icon_state = "base_friend" icon_living = "base_friend" @@ -279,11 +282,19 @@ attack_verb_continuous = "suckers" attack_verb_simple = "suck" - melee_damage_lower = 4 - melee_damage_upper = 4 + melee_damage_lower = 0 + melee_damage_upper = 0 + cowardly = TRUE ai_controller = /datum/ai_controller/basic_controller/carp/passive + gold_core_spawnable = FRIENDLY_SPAWN /mob/living/basic/carp/passive/Initialize(mapload) . = ..() - AddElement(/datum/element/ai_retaliate) + AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(on_attacked))) AddElement(/datum/element/pet_bonus, "bloops happily!") + ADD_TRAIT(src, TRAIT_PACIFISM, INNATE_TRAIT) + +/// If someone slaps one of the school, scatter +/mob/living/basic/carp/passive/proc/on_attacked(mob/living/attacker) + for(var/mob/living/basic/carp/passive/schoolmate in oview(src, 9)) + schoolmate.ai_controller?.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, attacker) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm index f104d3566b3..260dce64bdc 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm @@ -7,18 +7,20 @@ var/datum/ai_behavior/rift_behaviour /// If true we finish planning after this var/finish_planning = FALSE + /// Key to read for flee target + var/target_key = BB_BASIC_MOB_CURRENT_TARGET /datum/ai_planning_subtree/make_carp_rift/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) if (!rift_behaviour) CRASH("Forgot to specify rift behaviour for [src]") - if (!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) + if (!controller.blackboard_key_exists(target_key)) return var/datum/action/cooldown/using_action = controller.blackboard[BB_CARP_RIFT] if (!using_action?.IsAvailable()) return - controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, BB_BASIC_MOB_CURRENT_TARGET) + controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, target_key) if (finish_planning) return SUBTREE_RETURN_FINISH_PLANNING @@ -31,13 +33,17 @@ finish_planning = TRUE /datum/ai_planning_subtree/make_carp_rift/panic_teleport/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/atom/movable/fleeing_from = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + var/atom/movable/fleeing_from = controller.blackboard[target_key] if(!QDELETED(fleeing_from) && controller.blackboard[BB_CARPS_FEAR_FISHERMAN] && HAS_TRAIT(fleeing_from, TRAIT_SCARY_FISHERMAN)) return ..() if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) return return ..() +/datum/ai_planning_subtree/make_carp_rift/panic_teleport/flee_key + target_key = BB_BASIC_MOB_FLEE_TARGET + + /** * # Make carp rift (aggressive) * Plan to teleport towards our target so we can fuck them up @@ -46,7 +52,7 @@ rift_behaviour = /datum/ai_behavior/make_carp_rift/towards/aggressive /datum/ai_planning_subtree/make_carp_rift/aggressive_teleport/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/atom/movable/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + var/atom/movable/target = controller.blackboard[target_key] if(!QDELETED(target) && controller.blackboard[BB_CARPS_FEAR_FISHERMAN] && HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN)) return return ..() diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm index 4491ef11491..ae011f5b14a 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm @@ -106,22 +106,21 @@ */ /datum/ai_controller/basic_controller/carp/passive blackboard = list( - BB_BASIC_MOB_STOP_FLEEING = TRUE, - BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/require_traits, + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, - BB_TARGET_PRIORITY_TRAIT = TRAIT_SCARY_FISHERMAN, BB_CARPS_FEAR_FISHERMAN = TRUE, + BB_TARGET_ONLY_WITH_TRAITS = list(TRAIT_SCARY_FISHERMAN), ) ai_traits = STOP_MOVING_WHEN_PULLED planning_subtrees = list( /datum/ai_planning_subtree/pet_planning, - /datum/ai_planning_subtree/simple_find_nearest_target_to_flee, - /datum/ai_planning_subtree/make_carp_rift/panic_teleport, - /datum/ai_planning_subtree/flee_target/from_fisherman, + /datum/ai_planning_subtree/simple_find_target/to_flee, // This should only find master fishermen because of the targeting strategy + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key, + /datum/ai_planning_subtree/make_carp_rift/panic_teleport/flee_key, + /datum/ai_planning_subtree/flee_target/from_flee_key, /datum/ai_planning_subtree/find_food, - /datum/ai_planning_subtree/attack_obstacle_in_path/carp, - /datum/ai_planning_subtree/shortcut_to_target_through_carp_rift, /datum/ai_planning_subtree/make_carp_rift/aggressive_teleport, - /datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/carp_migration, ) diff --git a/code/modules/mob/living/basic/vermin/crab.dm b/code/modules/mob/living/basic/vermin/crab.dm index 0183be667b8..3c1c9146a06 100644 --- a/code/modules/mob/living/basic/vermin/crab.dm +++ b/code/modules/mob/living/basic/vermin/crab.dm @@ -89,7 +89,6 @@ planning_subtrees = list( /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key, /datum/ai_planning_subtree/flee_target/from_flee_key, - /datum/ai_planning_subtree/target_retaliate/to_flee, /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/crab, diff --git a/icons/mob/simple/carp.dmi b/icons/mob/simple/carp.dmi index 1be59c43ecb..e33b9c7ada8 100644 Binary files a/icons/mob/simple/carp.dmi and b/icons/mob/simple/carp.dmi differ