From c080b83c41c5a6fb30eb519449e8365200b51ee4 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Fri, 7 Nov 2025 18:32:46 -0600 Subject: [PATCH] Monkey eating glowup (#93759) ## About The Pull Request 1. Monkeys will only seek out food to eat if they are actually hungry, rather than on an arbitrary cooldown. 2. Monkeys will no longer teleport-yoink food out of your hands. Instead, they may get angry at you for stealing their food, and fight you over it. The hungrier the monkey, the more likely they are to fight. 3. Monkeys will discard trash and empty glasses (on the floor) after eating or drinking them. 4. Monkeys can target soup to eat 5. PunPun will no longer seek out drinks if they are hungry. 6. PunPun will now, if the bartender is absent and there are multiple patrons around, attempt to find filled glasses or food to hand out to patrons. 7. Several places that sought edible items no longer include drinking glasses as edible items image ## Why It's Good For The Game PunPun shouldn't be yoinking glasses out of patron's hands - their intended behavior is to serve drinks not steal them Otherwise, monkey eating was a bit jank due to it being some of our oldest ai code. I largely just brought it up to more modern ai standards. ## Changelog :cl: Melbert add: If the bartender is absent, PunPun will serve filled drink glasses to patrons that don't have one. add: PunPun will now ignore filled drinks and items being held when looking for stuff to eat. add: Monkeys can eat soup. add: Monkeys will no longer seek out food if they are not hungry. add: Hungry monkeys might fight you over the food you are holding. The hungrier the monkey, the angrier the monkey. fix: Monkeys can no longer teleport items out of your hands to eat. /:cl: --- code/__DEFINES/ai/ai_blackboard.dm | 4 +- code/__DEFINES/ai/monkey.dm | 8 ++ code/__DEFINES/monkeys.dm | 2 + code/__HELPERS/ai.dm | 12 --- code/datums/ai/generic/find_and_set.dm | 33 ++++++-- code/datums/ai/generic/generic_behaviors.dm | 81 +++++++++++++------ code/datums/ai/generic/generic_subtrees.dm | 36 +++++++-- code/datums/ai/monkey/monkey_controller.dm | 15 +++- code/datums/ai/monkey/monkey_subtrees.dm | 60 +++++++++++--- code/datums/ai/monkey/punpun_subtrees.dm | 22 ----- code/datums/components/grillable.dm | 2 +- code/game/objects/items/tongs.dm | 2 +- .../living/basic/farm_animals/goose/goose.dm | 2 +- .../basic/farm_animals/goose/goose_ai.dm | 2 +- .../organs/internal/stomach/_stomach.dm | 6 +- tgstation.dme | 1 - 16 files changed, 196 insertions(+), 92 deletions(-) delete mode 100644 code/datums/ai/monkey/punpun_subtrees.dm diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index f8392dfc171..cbef7194bc9 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -4,6 +4,8 @@ #define BB_CURRENT_MIN_MOVE_DISTANCE "min_move_distance" ///time until we should next eat, set by the generic hunger subtree #define BB_NEXT_HUNGRY "BB_NEXT_HUNGRY" +///When looking for food, ignore drinks +#define BB_IGNORE_DRINKS "bb_ignore_drinks" ///what we're going to eat next #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 @@ -237,5 +239,3 @@ // Used to hold state without making bigass lists /// For /datum/ai_behavior/find_potential_targets, what if any field are we using currently #define BB_FIND_TARGETS_FIELD(type) "bb_find_targets_field_[type]" - - diff --git a/code/__DEFINES/ai/monkey.dm b/code/__DEFINES/ai/monkey.dm index 833514e2f0f..f11ac96fefe 100644 --- a/code/__DEFINES/ai/monkey.dm +++ b/code/__DEFINES/ai/monkey.dm @@ -15,3 +15,11 @@ #define BB_MONKEY_DISPOSING "BB_monkey_disposing" #define BB_MONKEY_RECRUIT_COOLDOWN "BB_monkey_recruit_cooldown" #define BB_RESISTING "BB_resisting" +/// Monkey is not necessarily a wild animal so it won't resort to fighting over food and such +#define BB_MONKEY_TAMED "BB_monkey_tamed" +/// Chance to give our held item to a nearby mob +#define BB_MONKEY_GIVE_CHANCE "BB_monkey_give_chance" +/// If set, the monkey will prefer this type of object when pressing things +#define BB_MONKEY_PRESS_TYPEPATH "BB_monkey_press_typepath" +/// The item the monkey is currently serving to someone +#define BB_MONKEY_CURRENT_SERVED_ITEM "BB_monkey_current_served_item" diff --git a/code/__DEFINES/monkeys.dm b/code/__DEFINES/monkeys.dm index f487f805d50..a4929bb84dc 100644 --- a/code/__DEFINES/monkeys.dm +++ b/code/__DEFINES/monkeys.dm @@ -30,6 +30,8 @@ #define MONKEY_HATRED_AMOUNT 4 /// amount of aggro to add to an enemy when a monkey is recruited #define MONKEY_RECRUIT_HATED_AMOUNT 2 +/// amount of aggro to add if someone stole the food we wanted +#define MONKEY_FOOD_HATRED_AMOUNT 2 /// probability of reducing aggro by one when the monkey attacks #define MONKEY_HATRED_REDUCTION_PROB 20 diff --git a/code/__HELPERS/ai.dm b/code/__HELPERS/ai.dm index 7e7179c3989..81595c3f8a7 100644 --- a/code/__HELPERS/ai.dm +++ b/code/__HELPERS/ai.dm @@ -28,15 +28,3 @@ top_force = item.force return top_force_item - -///returns if something can be consumed, drink or food -/proc/IsEdible(obj/item/thing) - if(!istype(thing)) - return FALSE - if(IS_EDIBLE(thing)) - return TRUE - if(istype(thing, /obj/item/reagent_containers/cup/glass/drinkingglass)) - var/obj/item/reagent_containers/cup/glass/drinkingglass/glass = thing - if(glass.reagents.total_volume) // The glass has something in it, time to drink the mystery liquid! - return TRUE - return FALSE diff --git a/code/datums/ai/generic/find_and_set.dm b/code/datums/ai/generic/find_and_set.dm index a705c738698..e5b7c720b8b 100644 --- a/code/datums/ai/generic/find_and_set.dm +++ b/code/datums/ai/generic/find_and_set.dm @@ -34,21 +34,42 @@ /** * Variant of find and set that also requires the item to be edible. checks hands too */ -/datum/ai_behavior/find_and_set/edible +/datum/ai_behavior/find_and_set/food_or_drink + var/force_find_drinks = FALSE -/datum/ai_behavior/find_and_set/edible/search_tactic(datum/ai_controller/controller, locate_path, search_range) +/datum/ai_behavior/find_and_set/food_or_drink/search_tactic(datum/ai_controller/controller, locate_path, search_range) var/mob/living/living_pawn = controller.pawn + var/find_drinks = force_find_drinks || controller.blackboard[BB_IGNORE_DRINKS] || FALSE - for(var/atom/held_candidate as anything in living_pawn.held_items) - if(IsEdible(held_candidate)) + for(var/atom/held_candidate in living_pawn.held_items) + if(is_food_or_drink(controller, held_candidate, find_drinks)) return held_candidate - for(var/atom/local_candidate as anything in oview(search_range, controller.pawn)) - if(IsEdible(local_candidate) && istype(local_candidate, locate_path)) + for(var/atom/local_candidate in oview(search_range, controller.pawn)) + if(is_food_or_drink(controller, local_candidate, find_drinks) && istype(local_candidate, locate_path)) return local_candidate return null +/datum/ai_behavior/find_and_set/food_or_drink/proc/is_food_or_drink(datum/ai_controller/controller, obj/item/thing, find_drinks = FALSE) + return is_food(thing) || (find_drinks && is_drink(thing)) + +/datum/ai_behavior/find_and_set/food_or_drink/proc/is_food(obj/item/thing) + if(IS_EDIBLE(thing)) + return TRUE + if(istype(thing, /obj/item/reagent_containers/cup/bowl)) + return thing.reagents.total_volume > 0 + return FALSE + +/datum/ai_behavior/find_and_set/food_or_drink/proc/is_drink(obj/item/thing) + if(istype(thing, /obj/item/reagent_containers/cup/glass)) + return thing.reagents.total_volume > 0 + return FALSE + +/datum/ai_behavior/find_and_set/food_or_drink/to_eat + +/datum/ai_behavior/find_and_set/food_or_drink/to_serve + force_find_drinks = TRUE /** * Variant of find and set that only checks in hands, search range should be excluded for this diff --git a/code/datums/ai/generic/generic_behaviors.dm b/code/datums/ai/generic/generic_behaviors.dm index f6bebaf80b6..da338fa45cb 100644 --- a/code/datums/ai/generic/generic_behaviors.dm +++ b/code/datums/ai/generic/generic_behaviors.dm @@ -91,17 +91,11 @@ set_movement_target(controller, target) /datum/ai_behavior/use_on_object/perform(seconds_per_tick, datum/ai_controller/controller, target_key) - var/mob/living/pawn = controller.pawn - var/obj/item/held_item = pawn.get_item_by_slot(pawn.get_active_hand()) var/atom/target = controller.blackboard[target_key] if(QDELETED(target)) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED - if(held_item) - held_item.melee_attack_chain(pawn, target) - else - controller.ai_interact(target = target, combat_mode = FALSE) - + controller.ai_interact(target = target, combat_mode = FALSE) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED /datum/ai_behavior/give @@ -120,10 +114,14 @@ if(!held_item) //if held_item is null, we pretend that action was successful return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED - if(!target || !isliving(target)) + if(QDELETED(target) || !target.IsReachableBy(pawn)) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/mob/living/living_target = target + if(!isliving(living_target)) // target should reasonably only ever be set to a living mob + stack_trace("Tried to give an item to a non-living target!") + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + var/perform_flags = try_to_give_item(controller, living_target, held_item) if(perform_flags & AI_BEHAVIOR_FAILED) return perform_flags @@ -163,36 +161,73 @@ target.put_in_hands(held_item) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED +/datum/ai_behavior/give/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + controller.clear_blackboard_key(target_key) /datum/ai_behavior/consume + action_cooldown = 2 SECONDS + +/datum/ai_behavior/consume/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hunger_timer_key) + var/mob/living/living_pawn = controller.pawn + var/obj/item/target = controller.blackboard[target_key] + if(QDELETED(target) || !living_pawn.is_holding(target)) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + + controller.ai_interact(target = living_pawn, combat_mode = FALSE) + + return AI_BEHAVIOR_DELAY | (is_content(living_pawn, target) ? AI_BEHAVIOR_SUCCEEDED : AI_BEHAVIOR_FAILED) + +/datum/ai_behavior/consume/finish_action(datum/ai_controller/controller, succeeded, target_key, hunger_timer_key) + . = ..() + if(!succeeded) + return + controller.set_blackboard_key(hunger_timer_key, world.time + rand(12 SECONDS, 60 SECONDS)) + + var/mob/living/living_pawn = controller.pawn + var/obj/item/target = controller.blackboard[target_key] + if(!QDELETED(target) && !DOING_INTERACTION_WITH_TARGET(living_pawn, target)) + controller.clear_blackboard_key(target_key) + living_pawn.dropItemToGround(target) // drops empty drink glasses + for(var/obj/item/trash/trash in living_pawn.held_items) + living_pawn.dropItemToGround(trash) // drops spawned trash items + +/// Check if the target is fully consumed, or being actively consumed, or if we're just bored of eating it +/datum/ai_behavior/consume/proc/is_content(mob/living/living_pawm, obj/item/target) + if(QDELETED(target)) + return TRUE + if(DOING_INTERACTION_WITH_TARGET(living_pawm, target)) + return TRUE + if(target.reagents?.total_volume <= 0) + return TRUE + // Even if we don't finish it all we can randomly decide to be done + return prob(10) + +// navigate to target item and pick it up if we can +/datum/ai_behavior/navigate_to_and_pick_up behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH action_cooldown = 2 SECONDS -/datum/ai_behavior/consume/setup(datum/ai_controller/controller, target_key) +/datum/ai_behavior/navigate_to_and_pick_up/setup(datum/ai_controller/controller, target_key, drop_held = TRUE) . = ..() set_movement_target(controller, controller.blackboard[target_key]) -/datum/ai_behavior/consume/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hunger_timer_key) +/datum/ai_behavior/navigate_to_and_pick_up/setup(datum/ai_controller/controller, target_key, drop_held = TRUE) var/mob/living/living_pawn = controller.pawn var/obj/item/target = controller.blackboard[target_key] if(QDELETED(target)) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED - if(!(target in living_pawn.held_items)) - if(!living_pawn.get_empty_held_indexes() || !living_pawn.put_in_hands(target)) + if(living_pawn.is_holding(target)) // already in hands + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + if(!target.IsReachableBy(living_pawn)) // can't reach it, despite being adjacent + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + if(living_pawn.get_active_held_item()) // something is in our hands already + if(!drop_held || !living_pawn.dropItemToGround(living_pawn.get_active_held_item())) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED - target.melee_attack_chain(living_pawn, living_pawn) - - if(QDELETED(target) || prob(10)) // Even if we don't finish it all we can randomly decide to be done - return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED - - return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED - -/datum/ai_behavior/consume/finish_action(datum/ai_controller/controller, succeeded, target_key, hunger_timer_key) - . = ..() - if(succeeded) - controller.set_blackboard_key(hunger_timer_key, world.time + rand(12 SECONDS, 60 SECONDS)) + controller.ai_interact(target, combat_mode = FALSE) + return AI_BEHAVIOR_DELAY | (target.loc == living_pawn ? AI_BEHAVIOR_SUCCEEDED : AI_BEHAVIOR_FAILED) /** * Drops items in hands, very important for future behaviors that require the pawn to grab stuff diff --git a/code/datums/ai/generic/generic_subtrees.dm b/code/datums/ai/generic/generic_subtrees.dm index 9d5ff8638fc..6fe92668f91 100644 --- a/code/datums/ai/generic/generic_subtrees.dm +++ b/code/datums/ai/generic/generic_subtrees.dm @@ -53,7 +53,13 @@ * relevant blackboards: * * BB_NEXT_HUNGRY - set by this subtree, is when the controller is next hungry */ +/datum/ai_planning_subtree/generic_hunger + /datum/ai_planning_subtree/generic_hunger/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + if(living_pawn.nutrition > NUTRITION_LEVEL_HUNGRY) + return + var/next_eat = controller.blackboard[BB_NEXT_HUNGRY] if(!next_eat) //inits the blackboard timer @@ -63,16 +69,30 @@ if(world.time < next_eat) return + // find food var/atom/food_target = controller.blackboard[BB_FOOD_TARGET] - if(isnull(food_target)) - controller.queue_behavior(/datum/ai_behavior/find_and_set/edible, BB_FOOD_TARGET, /obj/item, 2) - return - - var/mob/living/living_pawn = controller.pawn - if(!length(living_pawn.get_empty_held_indexes()) && !(food_target in living_pawn.held_items)) - controller.queue_behavior(/datum/ai_behavior/drop_item) + controller.queue_behavior(/datum/ai_behavior/find_and_set/food_or_drink/to_eat, BB_FOOD_TARGET, /obj/item, 2) return SUBTREE_RETURN_FINISH_PLANNING - controller.queue_behavior(/datum/ai_behavior/consume, BB_FOOD_TARGET, BB_NEXT_HUNGRY) + if(living_pawn.is_holding(food_target)) + controller.queue_behavior(/datum/ai_behavior/consume, BB_FOOD_TARGET, BB_NEXT_HUNGRY) + // it's been moved since we found it + else if(!isturf(food_target.loc)) + // someone took it. we will fight over it! + if(isliving(food_target.loc) && will_fight_for_food(food_target.loc, living_pawn, controller)) + controller.add_blackboard_key_assoc(BB_MONKEY_ENEMIES, food_target.loc, MONKEY_FOOD_HATRED_AMOUNT) + // eh, find something else + else + controller.clear_blackboard_key(BB_FOOD_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING + else + controller.queue_behavior(/datum/ai_behavior/navigate_to_and_pick_up, BB_FOOD_TARGET, TRUE) return SUBTREE_RETURN_FINISH_PLANNING + +/datum/ai_planning_subtree/generic_hunger/proc/will_fight_for_food(mob/living/thief, mob/living/monkey, datum/ai_controller/controller) + if(controller.blackboard[BB_MONKEY_AGGRESSIVE]) + return TRUE + if(controller.blackboard[BB_MONKEY_TAMED]) + return FALSE + return prob(100 * ((NUTRITION_LEVEL_HUNGRY - monkey.nutrition) / NUTRITION_LEVEL_HUNGRY)) diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm index d7929bf9a8e..18bdb0be26b 100644 --- a/code/datums/ai/monkey/monkey_controller.dm +++ b/code/datums/ai/monkey/monkey_controller.dm @@ -25,6 +25,7 @@ have ways of interacting with a specific mob and control it. BB_MONKEY_GUN_NEURONS_ACTIVATED = FALSE, BB_SONG_LINES = MONKEY_SONG, BB_RESISTING = FALSE, + BB_MONKEY_GIVE_CHANCE = 5, ) idle_behavior = /datum/idle_behavior/idle_monkey @@ -63,12 +64,24 @@ have ways of interacting with a specific mob and control it. planning_subtrees = list( /datum/ai_planning_subtree/generic_resist, /datum/ai_planning_subtree/monkey_combat, + /datum/ai_planning_subtree/serve_food, /datum/ai_planning_subtree/generic_hunger, /datum/ai_planning_subtree/generic_play_instrument, - /datum/ai_planning_subtree/punpun_shenanigans, + /datum/ai_planning_subtree/monkey_shenanigans, ) idle_behavior = /datum/idle_behavior/idle_monkey/pun_pun +/datum/ai_controller/monkey/pun_pun/TryPossessPawn(atom/new_pawn) + . = ..() + if(. & AI_CONTROLLER_INCOMPATIBLE) + return + pawn = new_pawn + set_blackboard_key(BB_IGNORE_DRINKS, TRUE) + set_blackboard_key(BB_MONKEY_TAMED, TRUE) + set_blackboard_key(BB_MONKEY_GIVE_CHANCE, 30) + set_blackboard_key(BB_MONKEY_PRESS_TYPEPATH, /obj/structure/desk_bell) + set_trip_mode(mode = FALSE) + /datum/ai_controller/monkey/angry /datum/ai_controller/monkey/angry/TryPossessPawn(atom/new_pawn) diff --git a/code/datums/ai/monkey/monkey_subtrees.dm b/code/datums/ai/monkey/monkey_subtrees.dm index 9feb69df99c..dc8793ffdfe 100644 --- a/code/datums/ai/monkey/monkey_subtrees.dm +++ b/code/datums/ai/monkey/monkey_subtrees.dm @@ -7,21 +7,22 @@ return if(!controller.blackboard[BB_MONKEY_CURRENT_PRESS_TARGET]) - controller.queue_behavior(/datum/ai_behavior/find_nearby, BB_MONKEY_CURRENT_PRESS_TARGET) - return - - if(prob(50)) + if(controller.blackboard[BB_MONKEY_PRESS_TYPEPATH]) + controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_MONKEY_CURRENT_PRESS_TARGET, controller.blackboard[BB_MONKEY_PRESS_TYPEPATH], 2) + else + controller.queue_behavior(/datum/ai_behavior/find_nearby, BB_MONKEY_CURRENT_PRESS_TARGET) + else if(prob(50)) controller.queue_behavior(/datum/ai_behavior/use_on_object, BB_MONKEY_CURRENT_PRESS_TARGET) return SUBTREE_RETURN_FINISH_PLANNING if(!controller.blackboard[BB_MONKEY_CURRENT_GIVE_TARGET]) - controller.queue_behavior(/datum/ai_behavior/find_and_set/pawn_must_hold_item, BB_MONKEY_CURRENT_GIVE_TARGET, /mob/living, 2) - else - if(prob(5)) - controller.queue_behavior(/datum/ai_behavior/give, BB_MONKEY_CURRENT_GIVE_TARGET) - return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_and_set/pawn_must_hold_item, BB_MONKEY_CURRENT_GIVE_TARGET, /mob/living/carbon/human, 2) + else if(prob(controller.blackboard[BB_MONKEY_GIVE_CHANCE])) + controller.queue_behavior(/datum/ai_behavior/give, BB_MONKEY_CURRENT_GIVE_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING - controller.TryFindWeapon() + if(!controller.blackboard[BB_MONKEY_TAMED]) + controller.TryFindWeapon() ///monkey combat subtree. /datum/ai_planning_subtree/monkey_combat/SelectBehaviors(datum/ai_controller/monkey/controller, seconds_per_tick) @@ -70,3 +71,42 @@ controller.queue_behavior(/datum/ai_behavior/disposal_mob, BB_MONKEY_CURRENT_ATTACK_TARGET, BB_MONKEY_TARGET_DISPOSAL) return SUBTREE_RETURN_FINISH_PLANNING + +/// Finds food or drinks, picks them up, then gives them to nearby humans +/datum/ai_planning_subtree/serve_food + +/datum/ai_planning_subtree/serve_food/SelectBehaviors(datum/ai_controller/monkey/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + var/list/nearby_patrons = list() + for(var/mob/living/carbon/human/human_mob in oview(5, living_pawn)) + if(istype(human_mob.mind?.assigned_role, /datum/job/bartender)) + return // my boss is on duty! + if(human_mob.stat != CONSCIOUS || ismonkey(human_mob)) + continue + if(!human_mob.get_empty_held_indexes()) + continue + nearby_patrons += human_mob + + // Need at least 2 patrons to bother serving (bearing in mind the + if(length(nearby_patrons) < 1) + return + + var/obj/item/serving = controller.blackboard[BB_MONKEY_CURRENT_SERVED_ITEM] + if(QDELETED(serving) || serving.reagents.total_volume <= 0) + controller.queue_behavior(/datum/ai_behavior/find_and_set/food_or_drink/to_serve, BB_MONKEY_CURRENT_SERVED_ITEM, /obj/item, 2) + return + + // we have something to serve, pick a patron and go hand it over + if(living_pawn.is_holding(serving)) + controller.blackboard[BB_MONKEY_CURRENT_GIVE_TARGET] ||= pick(nearby_patrons) + controller.queue_behavior(/datum/ai_behavior/give, BB_MONKEY_CURRENT_GIVE_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING + + // we have something to serve but aren't holding it yet + if(isturf(serving.loc)) + // fetch the drink + controller.queue_behavior(/datum/ai_behavior/navigate_to_and_pick_up, BB_MONKEY_CURRENT_SERVED_ITEM, TRUE) + else + // give up on the dream + controller.clear_blackboard_key(BB_MONKEY_CURRENT_SERVED_ITEM) + return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/datums/ai/monkey/punpun_subtrees.dm b/code/datums/ai/monkey/punpun_subtrees.dm deleted file mode 100644 index 6370393db00..00000000000 --- a/code/datums/ai/monkey/punpun_subtrees.dm +++ /dev/null @@ -1,22 +0,0 @@ -/datum/ai_planning_subtree/punpun_shenanigans/SelectBehaviors(datum/ai_controller/monkey/controller, seconds_per_tick) - - controller.set_trip_mode(mode = FALSE) // pun pun doesn't fuck around - - if(prob(5)) - controller.queue_behavior(/datum/ai_behavior/use_in_hand) - - if(!SPT_PROB(MONKEY_SHENANIGAN_PROB, seconds_per_tick)) - return - - if(!controller.blackboard[BB_MONKEY_CURRENT_PRESS_TARGET]) - controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_MONKEY_CURRENT_PRESS_TARGET, /obj/structure/desk_bell, 2) - else if(prob(50)) - controller.queue_behavior(/datum/ai_behavior/use_on_object, BB_MONKEY_CURRENT_PRESS_TARGET) - return SUBTREE_RETURN_FINISH_PLANNING - - if(!controller.blackboard[BB_MONKEY_CURRENT_GIVE_TARGET]) - controller.queue_behavior(/datum/ai_behavior/find_and_set/pawn_must_hold_item, BB_MONKEY_CURRENT_GIVE_TARGET, /mob/living, 2) - else if(prob(30)) - controller.queue_behavior(/datum/ai_behavior/give, BB_MONKEY_CURRENT_GIVE_TARGET) - return SUBTREE_RETURN_FINISH_PLANNING - diff --git a/code/datums/components/grillable.dm b/code/datums/components/grillable.dm index 34a6675edd6..70507457924 100644 --- a/code/datums/components/grillable.dm +++ b/code/datums/components/grillable.dm @@ -155,7 +155,7 @@ LAZYADD(grilled_food.intrinsic_food_materials, original_food.intrinsic_food_materials) grilled_result.set_custom_materials(original_object.custom_materials) - if(IsEdible(grilled_result) && positive_result) + if(IS_EDIBLE(grilled_result) && positive_result) BLACKBOX_LOG_FOOD_MADE(grilled_result.type) //make space and tranfer reagents if it has any, also let any bad result handle removing or converting the transferred reagents on its own terms if(grilled_result.reagents && original_object.reagents) diff --git a/code/game/objects/items/tongs.dm b/code/game/objects/items/tongs.dm index 3c85cc8c004..a6be04b604f 100644 --- a/code/game/objects/items/tongs.dm +++ b/code/game/objects/items/tongs.dm @@ -81,7 +81,7 @@ if (COOLDOWN_FINISHED(src, clack_cooldown)) click_clack() return ..() - if (!IsEdible(attacked) || attacked.w_class > WEIGHT_CLASS_NORMAL || !isnull(tonged)) + if (!IS_EDIBLE(attacked) || attacked.w_class > WEIGHT_CLASS_NORMAL || !isnull(tonged)) return ..() tonged = attacked attacked.do_pickup_animation(src) diff --git a/code/modules/mob/living/basic/farm_animals/goose/goose.dm b/code/modules/mob/living/basic/farm_animals/goose/goose.dm index 0a34400f161..aa25ca7e9d7 100644 --- a/code/modules/mob/living/basic/farm_animals/goose/goose.dm +++ b/code/modules/mob/living/basic/farm_animals/goose/goose.dm @@ -57,7 +57,7 @@ SIGNAL_HANDLER if (ai_controller?.blackboard[BB_GOOSE_PANICKED]) return COMSIG_MOB_CANCEL_EAT - if (potential_food.has_material_type(/datum/material/plastic) || IsEdible(potential_food)) + if (potential_food.has_material_type(/datum/material/plastic) || IS_EDIBLE(potential_food)) return NONE// Geese only eat FOOD or PLASTIC return COMSIG_MOB_CANCEL_EAT diff --git a/code/modules/mob/living/basic/farm_animals/goose/goose_ai.dm b/code/modules/mob/living/basic/farm_animals/goose/goose_ai.dm index d161145d06b..0ed86b50f7b 100644 --- a/code/modules/mob/living/basic/farm_animals/goose/goose_ai.dm +++ b/code/modules/mob/living/basic/farm_animals/goose/goose_ai.dm @@ -62,7 +62,7 @@ var/list/filtered = list() for (var/obj/item/thing as anything in found) - if (IsEdible(thing) || thing.has_material_type(/datum/material/plastic)) + if (IS_EDIBLE(thing) || thing.has_material_type(/datum/material/plastic)) filtered += thing if(length(filtered)) diff --git a/code/modules/surgery/organs/internal/stomach/_stomach.dm b/code/modules/surgery/organs/internal/stomach/_stomach.dm index c763e32dfd5..996b33afb58 100644 --- a/code/modules/surgery/organs/internal/stomach/_stomach.dm +++ b/code/modules/surgery/organs/internal/stomach/_stomach.dm @@ -333,7 +333,7 @@ if (isliving(nomnom)) // NO VORE ALLOWED return 0 // Yeah maybe don't, if something edible ended up here it should either handle itself or not be digested - if (IsEdible(nomnom)) + if (IS_EDIBLE(nomnom)) return 0 if (HAS_TRAIT(owner, TRAIT_STRONG_STOMACH)) return 10 @@ -521,7 +521,7 @@ /obj/item/organ/stomach/cybernetic/tier2/stomach_acid_power(atom/movable/nomnom) if (isliving(nomnom)) return 0 - if (IsEdible(nomnom)) + if (IS_EDIBLE(nomnom)) return 0 return 20 @@ -537,7 +537,7 @@ /obj/item/organ/stomach/cybernetic/tier3/stomach_acid_power(atom/movable/nomnom) if (isliving(nomnom)) return 0 - if (IsEdible(nomnom)) + if (IS_EDIBLE(nomnom)) return 0 return 35 diff --git a/tgstation.dme b/tgstation.dme index 46e9805a4db..874f9bd1cad 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1031,7 +1031,6 @@ #include "code\datums\ai\monkey\monkey_behaviors.dm" #include "code\datums\ai\monkey\monkey_controller.dm" #include "code\datums\ai\monkey\monkey_subtrees.dm" -#include "code\datums\ai\monkey\punpun_subtrees.dm" #include "code\datums\ai\movement\_ai_movement.dm" #include "code\datums\ai\movement\ai_movement_basic_avoidance.dm" #include "code\datums\ai\movement\ai_movement_complete_stop.dm"