From 2535df375d95819c9061d8656d5a8bd812e28577 Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:38:37 +0200 Subject: [PATCH] Carps, frogs and young lobstrosities now fear the fishing hat! (#85380) ## About The Pull Request Carps, frogs and young lobstrosities now fear legendary anglers wearing the legendary fishing hat and will flee. The item is skill-locked, so only those that have maxxed out the skill can wear it. Differently, adult lobstrosities and megacarps (and suicide frogs, which are used nowhere) do not flee but will still prioritize them over the rest. ## Why It's Good For The Game I'm putting some emphasis on the "fish fear me" _(lobstrosities and frogs aren't exactly fish but it'd been quite boring to only include carps)_ and also making the hat a bit more than just some cosmetic novelty. ## Changelog :cl: add: Carps, frogs and young lobstrosities now fear people wearing fishing hats! Adults and megacarp favour the 'fight' part of the fear reflex however. fix: The hat stabilizer module now inherits the clothing traits of the attached hat. /:cl: --- code/__DEFINES/ai/ai_blackboard.dm | 2 + code/__DEFINES/ai/monsters.dm | 4 ++ code/__DEFINES/basic_mobs.dm | 2 - code/__DEFINES/traits/declarations.dm | 2 + code/_globalvars/traits/_traits.dm | 1 + code/_globalvars/traits/admin_tooling.dm | 1 + .../basic_ai_behaviors/targeting.dm | 12 ++++ .../find_targets_prioritize_traits.dm | 6 ++ .../basic_mobs/basic_subtrees/flee_target.dm | 15 +++++ .../basic_subtrees/simple_attack_target.dm | 9 +++ .../basic_subtrees/simple_find_target.dm | 1 - code/modules/clothing/head/soft_caps.dm | 1 + .../lavaland/lobstrosity/lobstrosity_ai.dm | 55 +++++++++++++------ .../basic/space_fauna/carp/carp_ai_actions.dm | 6 ++ .../space_fauna/carp/carp_ai_rift_actions.dm | 13 ++++- .../space_fauna/carp/carp_controllers.dm | 44 ++++++++++++--- .../living/basic/space_fauna/carp/megacarp.dm | 1 + code/modules/mob/living/basic/vermin/frog.dm | 15 ++++- code/modules/mod/modules/modules_general.dm | 4 +- tgstation.dme | 1 + 20 files changed, 161 insertions(+), 34 deletions(-) create mode 100644 code/datums/ai/basic_mobs/basic_subtrees/find_targets_prioritize_traits.dm diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 97ec38c1c3c..4374288b07c 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -24,6 +24,8 @@ ///the list of interactions we can have with the owner #define BB_INTERACTIONS_WITH_OWNER "BB_interactions_with_owner" +///The trait checked by ai_behavior/find_potential_targets/prioritize_trait to return a target with a trait over the rest. +#define BB_TARGET_PRIORITY_TRAIT "target_priority_trait" /// Store a single or list of emotes at this key #define BB_EMOTE_KEY "BB_emotes" diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index 76fd6c798d5..fb6952eb084 100644 --- a/code/__DEFINES/ai/monsters.dm +++ b/code/__DEFINES/ai/monsters.dm @@ -70,8 +70,12 @@ #define BB_LOBSTROSITY_TARGET_LIMB "BB_lobstrosity_target_limb" /// We increment this counter every time we try to move while dragging an arm and if we go too long we'll give up trying to get out of line of sight and just eat the fingers #define BB_LOBSTROSITY_FINGER_LUST "BB_lobstrosity_finger_lust" +/// Does this carp still target lying mobs even if they aren't stunned, and flee from sary fishermen? #define BB_LOBSTROSITY_NAIVE_HUNTER "BB_lobstrosity_naive_hunter" +/// Does this carp run from scary fishermen? +#define BB_CARPS_FEAR_FISHERMAN "BB_carp_fear_fisherman" + // eyeball keys ///the death glare ability #define BB_GLARE_ABILITY "BB_glare_ability" diff --git a/code/__DEFINES/basic_mobs.dm b/code/__DEFINES/basic_mobs.dm index ae74872cd73..e519fb25240 100644 --- a/code/__DEFINES/basic_mobs.dm +++ b/code/__DEFINES/basic_mobs.dm @@ -70,5 +70,3 @@ GLOBAL_VAR_INIT(gutlunch_count, 0) #define BB_RAPTOR_TROUGH_TARGET "raptor_trough_target" #define MAX_RAPTOR_POP 64 - - diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 3a47fe1ca0a..f918029f870 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -225,6 +225,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_REVEAL_FISH "reveal_fish" ///This trait gets you a list of fishes that can be caught when examining a fishing spot. #define TRAIT_EXAMINE_FISHING_SPOT "examine_fishing_spot" +///lobstrosities and carps will prioritize/flee from those that have this trait (given by the skill-locked hat) +#define TRAIT_SCARY_FISHERMAN "scary_fisherman" ///Trait given to turfs or objects that can be fished from #define TRAIT_FISHING_SPOT "fishing_spot" ///Trait given to mobs that can fish without a rod diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 3c831c4a681..29da0e2fb11 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -60,6 +60,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT" = TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT, "TRAIT_ON_HIT_EFFECT" = TRAIT_ON_HIT_EFFECT, "TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN, + "TRAIT_SCARY_FISHERMAN" = TRAIT_SCARY_FISHERMAN, "TRAIT_SECLUDED_LOCATION" = TRAIT_SECLUDED_LOCATION, "TRAIT_SNOWSTORM_IMMUNE" = TRAIT_SNOWSTORM_IMMUNE, "TRAIT_TELEKINESIS_CONTROLLED" = TRAIT_TELEKINESIS_CONTROLLED, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 7ff9dad994e..5972d3f92ba 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -18,6 +18,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_MOVE_VENTCRAWLING" = TRAIT_MOVE_VENTCRAWLING, "TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN, "TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN, + "TRAIT_SCARY_FISHERMAN" = TRAIT_SCARY_FISHERMAN, "TRAIT_SNOWSTORM_IMMUNE" = TRAIT_SNOWSTORM_IMMUNE, "TRAIT_VOIDSTORM_IMMUNE" = TRAIT_VOIDSTORM_IMMUNE, "TRAIT_WEATHER_IMMUNE" = TRAIT_WEATHER_IMMUNE, 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 4cf04039e85..7673551a653 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm @@ -152,3 +152,15 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/ /// Returns the desired final target from the filtered list of targets /datum/ai_behavior/find_potential_targets/proc/pick_final_target(datum/ai_controller/controller, list/filtered_targets) return pick(filtered_targets) + +/// Targets with the trait specified by the BB_TARGET_PRIORITY_TRAIT blackboard key will be prioritized over the rest. +/datum/ai_behavior/find_potential_targets/prioritize_trait + +/datum/ai_behavior/find_potential_targets/prioritize_trait/pick_final_target(datum/ai_controller/controller, list/filtered_targets) + var/priority_targets = list() + for(var/atom/target as anything in filtered_targets) + if(HAS_TRAIT(target, controller.blackboard[BB_TARGET_PRIORITY_TRAIT])) + priority_targets += target + if(length(priority_targets)) + return pick(priority_targets) + return ..() diff --git a/code/datums/ai/basic_mobs/basic_subtrees/find_targets_prioritize_traits.dm b/code/datums/ai/basic_mobs/basic_subtrees/find_targets_prioritize_traits.dm new file mode 100644 index 00000000000..6c83469960a --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_targets_prioritize_traits.dm @@ -0,0 +1,6 @@ +/// Find something with a specific trait to run from +/datum/ai_planning_subtree/find_target_prioritize_traits + +/datum/ai_planning_subtree/find_target_prioritize_traits/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + . = ..() + controller.queue_behavior(/datum/ai_behavior/find_potential_targets/prioritize_trait, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION, BB_TARGET_PRIORITY_TRAIT) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm index 4a2f5b476c7..3d593286484 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm @@ -12,6 +12,8 @@ var/atom/flee_from = controller.blackboard[target_key] if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING] || QDELETED(flee_from)) return + if(!should_flee(controller, flee_from)) + return var/flee_distance = controller.blackboard[BB_BASIC_MOB_FLEE_DISTANCE] || DEFAULT_BASIC_FLEE_DISTANCE if (get_dist(controller.pawn, flee_from) >= flee_distance) return @@ -19,8 +21,21 @@ controller.queue_behavior(flee_behaviour, target_key, hiding_place_key) return SUBTREE_RETURN_FINISH_PLANNING //we gotta get out of here. +/datum/ai_planning_subtree/flee_target/proc/should_flee(datum/ai_controller/controller, atom/flee_from) + if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING] || QDELETED(flee_from)) + return FALSE + return TRUE + /// Try to escape from your current target, without performing any other actions. /// 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 + +/// A subtype that forces the mob to flee from targets with the scary fisherman trait anyway. +/datum/ai_planning_subtree/flee_target/from_fisherman + +/datum/ai_planning_subtree/flee_target/from_fisherman/should_flee(datum/ai_controller/controller, atom/flee_from) + if (!QDELETED(flee_from) && HAS_TRAIT(flee_from, TRAIT_SCARY_FISHERMAN)) + return TRUE + return ..() diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm index 5b1f5ffbff9..f764568d4ba 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm @@ -22,3 +22,12 @@ return 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. + +/datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman + +/datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/atom/movable/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + if(QDELETED(target)) + return ..() + if(!HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN)) + return ..() 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 1c7d8de9120..42608730f98 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 @@ -12,4 +12,3 @@ if(watcher.stat != DEAD) return return ..() - diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm index 3003e9a76ee..cb0f9033960 100644 --- a/code/modules/clothing/head/soft_caps.dm +++ b/code/modules/clothing/head/soft_caps.dm @@ -169,6 +169,7 @@ clothing_flags = SNUG_FIT resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE dog_fashion = null + clothing_traits = list(TRAIT_SCARY_FISHERMAN) //Fish, carps, lobstrosities and frogs fear me. /obj/item/clothing/head/soft/fishing_hat/Initialize(mapload) . = ..() diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm index 75b64d05120..5ca1ca2cfd5 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm @@ -14,6 +14,7 @@ BB_LOBSTROSITY_FINGER_LUST = 0, BB_LOBSTROSITY_NAIVE_HUNTER = FALSE, BB_BASIC_MOB_FLEE_DISTANCE = 8, + BB_TARGET_PRIORITY_TRAIT = TRAIT_SCARY_FISHERMAN, BB_OWNER_SELF_HARM_RESPONSES = SHRIMP_HARM_RESPONSES, ) ai_traits = PAUSE_DURING_DO_AFTER @@ -24,7 +25,7 @@ /datum/ai_planning_subtree/random_speech/insect, /datum/ai_planning_subtree/hoard_fingers, /datum/ai_planning_subtree/pet_planning, - /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/find_target_prioritize_traits, /datum/ai_planning_subtree/targeted_mob_ability/lobster, /datum/ai_planning_subtree/flee_target/lobster, /datum/ai_planning_subtree/attack_obstacle_in_path, @@ -43,13 +44,14 @@ BB_LOBSTROSITY_FINGER_LUST = 0, BB_LOBSTROSITY_NAIVE_HUNTER = TRUE, BB_BASIC_MOB_FLEE_DISTANCE = 4, + BB_TARGET_PRIORITY_TRAIT = TRAIT_SCARY_FISHERMAN, BB_OWNER_SELF_HARM_RESPONSES = SHRIMP_HARM_RESPONSES, ) planning_subtrees = list( /datum/ai_planning_subtree/random_speech/insect, /datum/ai_planning_subtree/hoard_fingers, /datum/ai_planning_subtree/pet_planning, - /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/find_target_prioritize_traits, /datum/ai_planning_subtree/targeted_mob_ability/lobster, /datum/ai_planning_subtree/flee_target/lobster, /datum/ai_planning_subtree/attack_obstacle_in_path, @@ -100,14 +102,17 @@ melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/lobster /datum/ai_planning_subtree/basic_melee_attack_subtree/lobster/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - if(!isliving(controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET])) + var/atom/movable/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + if(!isliving(target)) return ..() if (!controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) return if (!isnull(controller.blackboard[BB_LOBSTROSITY_TARGET_LIMB])) return + if(controller.blackboard[BB_LOBSTROSITY_NAIVE_HUNTER] && HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN)) + return //juvenile lobstrosities fear me. var/mob/living/living_pawn = controller.pawn - if (DOING_INTERACTION_WITH_TARGET(living_pawn, controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET])) + if (DOING_INTERACTION_WITH_TARGET(living_pawn, target)) return return ..() @@ -118,9 +123,14 @@ if (isnull(target) || !istype(target)) return ..() var/is_vulnerable = FALSE - if(controller.blackboard[BB_LOBSTROSITY_NAIVE_HUNTER] && target.body_position == LYING_DOWN) - is_vulnerable = TRUE - else + if(controller.blackboard[BB_LOBSTROSITY_NAIVE_HUNTER]) + if(HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN)) + //Trigger lobstrosity PTSD. Don't clear the target so we can run away. + controller.set_blackboard_key(BB_BASIC_MOB_STOP_FLEEING, FALSE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED + if(target.body_position == LYING_DOWN) + is_vulnerable = TRUE + if(!is_vulnerable) for (var/trait in controller.blackboard[BB_LOBSTROSITY_EXPLOIT_TRAITS]) if (!HAS_TRAIT(target, trait)) continue @@ -137,9 +147,12 @@ flee_behaviour = /datum/ai_behavior/run_away_from_target/lobster /datum/ai_planning_subtree/flee_target/lobster/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/atom/movable/target = controller.blackboard[target_key] + if(!QDELETED(target) && controller.blackboard[BB_LOBSTROSITY_NAIVE_HUNTER] && HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN)) + return ..() var/datum/action/cooldown/using_action = controller.blackboard[BB_TARGETED_ACTION] if (using_action?.IsAvailable()) - return + return FALSE return ..() /datum/ai_behavior/run_away_from_target/lobster @@ -147,19 +160,23 @@ /datum/ai_behavior/run_away_from_target/lobster/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key) var/atom/target = controller.blackboard[target_key] - if(isnull(target)) + if(QDELETED(target)) return ..() - if(isliving(target)) - var/mob/living/living_target = target - if(controller.blackboard[BB_LOBSTROSITY_NAIVE_HUNTER] && living_target.body_position == LYING_DOWN) + var/is_naive = controller.blackboard[BB_LOBSTROSITY_NAIVE_HUNTER] + var/is_scary = HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN) + + if(!is_naive || !is_scary) //the lobstrosity isn't naive/young and the target isn't a scary fisherman. + if(isliving(target)) + var/mob/living/living_target = target + if(is_naive && living_target.body_position == LYING_DOWN) + controller.set_blackboard_key(BB_BASIC_MOB_STOP_FLEEING, TRUE) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED + for (var/trait in controller.blackboard[BB_LOBSTROSITY_EXPLOIT_TRAITS]) + if (!HAS_TRAIT(target, trait)) + continue controller.set_blackboard_key(BB_BASIC_MOB_STOP_FLEEING, TRUE) return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED - for (var/trait in controller.blackboard[BB_LOBSTROSITY_EXPLOIT_TRAITS]) - if (!HAS_TRAIT(target, trait)) - continue - controller.set_blackboard_key(BB_BASIC_MOB_STOP_FLEEING, TRUE) - return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED var/mob/living/us = controller.pawn if (us.pulling == target) @@ -174,7 +191,9 @@ /datum/ai_planning_subtree/targeted_mob_ability/lobster/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/atom/target = controller.blackboard[target_key] if(QDELETED(target) || in_range(controller.pawn, target)) - return FALSE + return + if(controller.blackboard[BB_LOBSTROSITY_NAIVE_HUNTER] && HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN)) + return return ..() diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm index 71017bd2207..810c4560386 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm @@ -55,6 +55,12 @@ /// This subtype only exists because if you queue multiple of the same action with different arguments it deletes their stored arguments /datum/ai_behavior/find_potential_targets/nearest/magicarp +/datum/ai_behavior/find_potential_targets/nearest/magicarp/pick_final_target(datum/ai_controller/controller, list/enemies_list) + for(var/atom/atom as anything in enemies_list) + if(HAS_TRAIT(atom, TRAIT_SCARY_FISHERMAN)) + enemies_list -= atom + return ..() + /// Then use it on that target /datum/ai_planning_subtree/targeted_mob_ability/magicarp ability_key = BB_MAGICARP_SPELL 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 84b96ae3ce4..da672832a0a 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 @@ -31,6 +31,9 @@ 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] + 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 ..() @@ -42,6 +45,14 @@ /datum/ai_planning_subtree/make_carp_rift/aggressive_teleport 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] + if(QDELETED(target) || !controller.blackboard[BB_CARPS_FEAR_FISHERMAN] || !HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN)) + return ..() + if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) + return + return ..() + /** * # Make carp rift * Make a carp rift somewhere @@ -174,7 +185,7 @@ /datum/ai_planning_subtree/shortcut_to_target_through_carp_rift/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] - if (QDELETED(target)) + if (QDELETED(target) || (controller.blackboard[BB_CARPS_FEAR_FISHERMAN] && HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN))) return var/distance_to_target = get_dist(controller.pawn, target) 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 0befb20987c..4491ef11491 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 @@ -12,24 +12,48 @@ BB_BASIC_MOB_STOP_FLEEING = TRUE, BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, + BB_TARGET_PRIORITY_TRAIT = TRAIT_SCARY_FISHERMAN, + BB_CARPS_FEAR_FISHERMAN = TRUE, ) ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/simple_find_nearest_target_to_flee, + /datum/ai_planning_subtree/find_target_prioritize_traits, + /datum/ai_planning_subtree/make_carp_rift/panic_teleport, + /datum/ai_planning_subtree/flee_target/from_fisherman, + /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/carp_migration, + ) + +///Megacarps. The only difference is that they don't flee from scary fishermen and prioritize them. +/datum/ai_controller/basic_controller/carp/mega + blackboard = list( + BB_BASIC_MOB_STOP_FLEEING = TRUE, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, + BB_TARGET_PRIORITY_TRAIT = TRAIT_SCARY_FISHERMAN, + BB_CARPS_FEAR_FISHERMAN = FALSE, + ) 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, /datum/ai_planning_subtree/find_food, - /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/find_target_prioritize_traits, /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, /datum/ai_planning_subtree/carp_migration, ) - /** * Carp which bites back, but doesn't look for targets. * 'Not hunting targets' includes food (and can rings), because they have been well trained. @@ -39,18 +63,20 @@ BB_BASIC_MOB_STOP_FLEEING = TRUE, BB_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, ) ai_traits = STOP_MOVING_WHEN_PULLED planning_subtrees = list( /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, /datum/ai_planning_subtree/make_carp_rift/panic_teleport, - /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/flee_target/from_fisherman, /datum/ai_planning_subtree/target_retaliate, /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, + /datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman, ) /** @@ -61,12 +87,12 @@ planning_subtrees = list( /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/simple_find_nearest_target_to_flee, + /datum/ai_planning_subtree/find_target_prioritize_traits, /datum/ai_planning_subtree/make_carp_rift/panic_teleport, - /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/flee_target/from_fisherman, /datum/ai_planning_subtree/find_food, /datum/ai_planning_subtree/find_nearest_magicarp_spell_target, /datum/ai_planning_subtree/targeted_mob_ability/magicarp, - /datum/ai_planning_subtree/simple_find_target, /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, @@ -83,17 +109,19 @@ BB_BASIC_MOB_STOP_FLEEING = TRUE, BB_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, ) 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, + /datum/ai_planning_subtree/flee_target/from_fisherman, /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, + /datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman, /datum/ai_planning_subtree/carp_migration, ) diff --git a/code/modules/mob/living/basic/space_fauna/carp/megacarp.dm b/code/modules/mob/living/basic/space_fauna/carp/megacarp.dm index deadeaaa540..d82120a37e0 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/megacarp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/megacarp.dm @@ -24,6 +24,7 @@ ridable_data = /datum/component/riding/creature/megacarp greyscale_config = /datum/greyscale_config/carp_mega butcher_results = list(/obj/item/food/fishmeat/carp = 2, /obj/item/stack/sheet/animalhide/carp = 3) + ai_controller = /datum/ai_controller/basic_controller/carp/mega /mob/living/basic/carp/mega/Initialize(mapload) . = ..() diff --git a/code/modules/mob/living/basic/vermin/frog.dm b/code/modules/mob/living/basic/vermin/frog.dm index a674169dbd5..3a288918dbd 100644 --- a/code/modules/mob/living/basic/vermin/frog.dm +++ b/code/modules/mob/living/basic/vermin/frog.dm @@ -109,6 +109,7 @@ /datum/ai_controller/basic_controller/frog blackboard = list( + BB_BASIC_MOB_STOP_FLEEING = TRUE, //We only flee from scary fishermen. BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, BB_OWNER_SELF_HARM_RESPONSES = list( @@ -122,7 +123,8 @@ planning_subtrees = list( /datum/ai_planning_subtree/target_retaliate, /datum/ai_planning_subtree/random_speech/frog, - /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman, + /datum/ai_planning_subtree/flee_target/from_fisherman, /datum/ai_planning_subtree/go_for_swim, ) @@ -131,11 +133,18 @@ /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/random_speech/frog, /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman, + /datum/ai_planning_subtree/flee_target/from_fisherman, ) /datum/ai_controller/basic_controller/frog/suicide_frog + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, + BB_TARGET_PRIORITY_TRAIT = TRAIT_SCARY_FISHERMAN, //No fear, only hatred. It has nothing to lose + ) + planning_subtrees = list( - /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/find_target_prioritize_traits, /datum/ai_planning_subtree/basic_melee_attack_subtree, ) diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index e14fc483c0b..1928e25eac1 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -712,6 +712,7 @@ attached_hat = hat var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) if(istype(helmet)) + helmet.attach_clothing_traits(attached_hat.clothing_traits) former_flags = helmet.flags_cover former_visor_flags = helmet.visor_flags_cover helmet.flags_cover |= attached_hat.flags_cover @@ -734,11 +735,12 @@ balloon_alert(user, "hat removed") else balloon_alert_to_viewers("the hat falls to the floor!") - attached_hat = null var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) if(istype(helmet)) + helmet.detach_clothing_traits(attached_hat) helmet.flags_cover = former_flags helmet.visor_flags_cover = former_visor_flags + attached_hat = null mod.wearer.update_clothing(mod.slot_flags) /obj/item/mod/module/hat_stabilizer/syndicate diff --git a/tgstation.dme b/tgstation.dme index b2777545da4..9304f051da0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -912,6 +912,7 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\find_food.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_paper_and_write.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_parent.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\find_targets_prioritize_traits.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\flee_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\go_for_swim.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\maintain_distance.dm"