diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index fd30ac7e590..076efefc7d5 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -161,6 +161,7 @@ #define BB_DOG_ORDER_MODE "BB_DOG_ORDER_MODE" #define BB_DOG_PLAYING_DEAD "BB_DOG_PLAYING_DEAD" #define BB_DOG_HARASS_TARGET "BB_DOG_HARASS_TARGET" +#define BB_DOG_HARASS_FRUSTRATION "BB_DOG_HARASS_FRUSTRATION" /// Basically, what is our vision/hearing range for picking up on things to fetch/ #define AI_DOG_VISION_RANGE 10 @@ -171,7 +172,9 @@ /// After being ordered to heel, we spend this long chilling out #define AI_DOG_HEEL_DURATION 20 SECONDS /// After either being given a verbal order or a pointing order, ignore further of each for this duration -#define AI_DOG_COMMAND_COOLDOWN 2 SECONDS +#define AI_DOG_COMMAND_COOLDOWN 2 SECONDS +/// If the dog is set to harass someone but doesn't bite them for this long, give up +#define AI_DOG_HARASS_FRUSTRATE_TIME 50 SECONDS // dog command modes (what pointing at something/someone does depending on the last order the dog heard) /// Don't do anything (will still react to stuff around them though) diff --git a/code/datums/ai/dog/dog_behaviors.dm b/code/datums/ai/dog/dog_behaviors.dm index c4cd2176c43..76f11a9cae1 100644 --- a/code/datums/ai/dog/dog_behaviors.dm +++ b/code/datums/ai/dog/dog_behaviors.dm @@ -45,6 +45,8 @@ /datum/ai_behavior/simple_equip/finish_action(datum/ai_controller/controller, success) . = ..() controller.blackboard[BB_FETCH_TARGET] = null + if(!success) + controller.blackboard[BB_FETCH_DELIVER_TO] = null /datum/ai_behavior/simple_equip/proc/pickup_item(datum/ai_controller/controller, obj/item/target) var/atom/pawn = controller.pawn @@ -82,6 +84,7 @@ /datum/ai_behavior/deliver_item/finish_action(datum/ai_controller/controller, success) . = ..() + controller.blackboard[BB_FETCH_TARGET] = null controller.blackboard[BB_FETCH_DELIVER_TO] = null /// Actually drop the fetched item to the target @@ -98,7 +101,7 @@ controller.pawn.visible_message(span_notice("[controller.pawn] delivers [carried_item] to [return_target].")) carried_item.forceMove(get_turf(return_target)) - controller.blackboard -= BB_SIMPLE_CARRY_ITEM + controller.blackboard[BB_SIMPLE_CARRY_ITEM] = null return TRUE /// This behavior involves either eating a snack we can reach, or begging someone holding a snack @@ -184,21 +187,34 @@ finish_action(controller, TRUE) return + if(!controller.blackboard[BB_DOG_HARASS_FRUSTRATION]) + controller.blackboard[BB_DOG_HARASS_FRUSTRATION] = world.time + else if(controller.blackboard[BB_DOG_HARASS_FRUSTRATION] + AI_DOG_HARASS_FRUSTRATE_TIME < world.time) // if we haven't actually bit them in a while, give up + living_pawn.visible_message(span_danger("[living_pawn] yawns and seems to lose interest in harassing [harass_target].")) + finish_action(controller, FALSE) + return + // subtypes of this behavior can change behavior for how eager/averse the pawn is to attack the target as opposed to falling back/making noise/getting help if(in_range(living_pawn, living_target)) attack(controller, living_target) - else if(DT_PROB(50, delta_time)) + else if(DT_PROB(15, delta_time)) living_pawn.manual_emote("[pick("barks", "growls", "stares")] menacingly at [harass_target]!") + if(DT_PROB(40, delta_time)) + playsound(living_pawn, pick('sound/creatures/dog/growl1.ogg', 'sound/creatures/dog/growl2.ogg'), 50, TRUE, -1) /datum/ai_behavior/harass/finish_action(datum/ai_controller/controller, succeeded) . = ..() controller.blackboard[BB_DOG_HARASS_TARGET] = null + controller.blackboard[BB_DOG_HARASS_FRUSTRATION] = null /// A proc representing when the mob is pushed to actually attack the target. Again, subtypes can be used to represent different attacks from different animals, or it can be some other generic behavior /datum/ai_behavior/harass/proc/attack(datum/ai_controller/controller, mob/living/living_target) var/mob/living/living_pawn = controller.pawn if(!istype(living_pawn)) return + + controller.blackboard[BB_DOG_HARASS_FRUSTRATION] = world.time + // make sure the pawn gets some temporary strength boost to actually attack the target instead of pathetically nuzzling them. var/old_melee_lower = living_pawn.melee_damage_lower var/old_melee_upper = living_pawn.melee_damage_upper diff --git a/code/datums/ai/dog/dog_controller.dm b/code/datums/ai/dog/dog_controller.dm index 744bf3891de..646bf6d2d50 100644 --- a/code/datums/ai/dog/dog_controller.dm +++ b/code/datums/ai/dog/dog_controller.dm @@ -7,7 +7,9 @@ BB_FETCH_IGNORE_LIST = list(),\ BB_DOG_ORDER_MODE = DOG_COMMAND_NONE,\ BB_DOG_PLAYING_DEAD = FALSE,\ - BB_DOG_HARASS_TARGET = null) + BB_DOG_HARASS_TARGET = null,\ + BB_DOG_HARASS_FRUSTRATION = null,\ + BB_VISION_RANGE = AI_DOG_VISION_RANGE) ai_movement = /datum/ai_movement/jps planning_subtrees = list(/datum/ai_planning_subtree/dog) @@ -202,7 +204,7 @@ var/command if(findtext(spoken_text, "heel") || findtext(spoken_text, "sit") || findtext(spoken_text, "stay")) command = COMMAND_HEEL - else if(findtext(spoken_text, "fetch") || findtext(spoken_text, "get it")) + else if(findtext(spoken_text, "fetch")) command = COMMAND_FETCH else if(findtext(spoken_text, "attack") || findtext(spoken_text, "sic")) command = COMMAND_ATTACK diff --git a/code/datums/ai/oldhostile/hostile_tameable.dm b/code/datums/ai/oldhostile/hostile_tameable.dm index 1e64280eb45..97fa31cb0d7 100644 --- a/code/datums/ai/oldhostile/hostile_tameable.dm +++ b/code/datums/ai/oldhostile/hostile_tameable.dm @@ -174,7 +174,7 @@ pawn.visible_message(span_notice("[pawn] [blackboard[BB_HOSTILE_ATTACK_WORD]] at [commander]'s command, and [pawn.p_they()] stop[pawn.p_s()] obediently, awaiting further orders.")) blackboard[BB_HOSTILE_ORDER_MODE] = HOSTILE_COMMAND_NONE CancelActions() - // fetch: whatever the commander points to, try and bring it back + // follow: whatever the commander points to, try and bring it back if(COMMAND_FOLLOW) pawn.visible_message(span_notice("[pawn] [blackboard[BB_HOSTILE_ATTACK_WORD]] at [commander]'s command, and [pawn.p_they()] follow[pawn.p_s()] slightly in anticipation.")) CancelActions() diff --git a/sound/attributions.txt b/sound/attributions.txt index e177646b780..4fe5ad2ad95 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -27,3 +27,5 @@ can_shake.ogg adapted from https://freesound.org/people/mcmast/sounds/456703/ splatter.ogg adapted from https://freesound.org/people/Rocktopus/sounds/233418/ hohoho.ogg and hehe.ogg are cut from a recording by Nanakisan on freesound: https://freesound.org/people/Nanakisan/sounds/253534/ mbox_full.ogg and mbox_end.ogg make use of The Ragtime Drummer by James Lent, in the public domain + +growl1.ogg and growl2.ogg in /sound/creatures/dog are adapted from Glitchedtones's Freesound shih-tzu uploads https://freesound.org/people/Glitchedtones/ diff --git a/sound/creatures/dog/growl1.ogg b/sound/creatures/dog/growl1.ogg new file mode 100644 index 00000000000..06ec30f12f0 Binary files /dev/null and b/sound/creatures/dog/growl1.ogg differ diff --git a/sound/creatures/dog/growl2.ogg b/sound/creatures/dog/growl2.ogg new file mode 100644 index 00000000000..804bd8150aa Binary files /dev/null and b/sound/creatures/dog/growl2.ogg differ