Files
Bubberstation/code/datums/ai/monkey/monkey_subtrees.dm
MrMelbert c080b83c41 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

<img width="656" height="185" alt="image"
src="https://github.com/user-attachments/assets/8b3a6ac1-ae2c-41a0-919f-b471ad93bb0f"
/>

## 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

🆑 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. 
/🆑
2025-11-08 01:32:46 +01:00

113 lines
5.0 KiB
Plaintext

/datum/ai_planning_subtree/monkey_shenanigans/SelectBehaviors(datum/ai_controller/monkey/controller, seconds_per_tick)
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])
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/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
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)
var/mob/living/living_pawn = controller.pawn
var/list/enemies = controller.blackboard[BB_MONKEY_ENEMIES]
if((HAS_TRAIT(controller.pawn, TRAIT_PACIFISM)) || (!length(enemies) && !controller.blackboard[BB_MONKEY_AGGRESSIVE])) //Pacifist, or we have no enemies and we're not pissed
living_pawn.set_combat_mode(FALSE)
return
if(!controller.blackboard[BB_MONKEY_CURRENT_ATTACK_TARGET])
controller.queue_behavior(/datum/ai_behavior/monkey_set_combat_target, BB_MONKEY_CURRENT_ATTACK_TARGET, BB_MONKEY_ENEMIES)
living_pawn.set_combat_mode(FALSE)
return SUBTREE_RETURN_FINISH_PLANNING
var/mob/living/selected_enemy = controller.blackboard[BB_MONKEY_CURRENT_ATTACK_TARGET]
if(QDELETED(selected_enemy))
living_pawn.set_combat_mode(FALSE)
return
if(!selected_enemy.stat) //He's up, get him!
if(living_pawn.health < MONKEY_FLEE_HEALTH) //Time to skeddadle
controller.queue_behavior(/datum/ai_behavior/monkey_flee)
return SUBTREE_RETURN_FINISH_PLANNING //I'm running fuck you guys
if(controller.TryFindWeapon()) //Getting a weapon is higher priority if im not fleeing.
return SUBTREE_RETURN_FINISH_PLANNING
if(controller.blackboard[BB_MONKEY_RECRUIT_COOLDOWN] < world.time)
controller.queue_behavior(/datum/ai_behavior/recruit_monkeys, BB_MONKEY_CURRENT_ATTACK_TARGET)
return
if(SPT_PROB(ismonkey(living_pawn) ? 25 : 10, seconds_per_tick))
controller.queue_behavior(/datum/ai_behavior/battle_screech/monkey)
controller.queue_behavior(/datum/ai_behavior/monkey_attack_mob, BB_MONKEY_CURRENT_ATTACK_TARGET)
return SUBTREE_RETURN_FINISH_PLANNING
//by this point we have a target but they're down, let's try dumpstering this loser
living_pawn.set_combat_mode(FALSE)
if(!controller.blackboard[BB_MONKEY_TARGET_DISPOSAL])
controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_MONKEY_TARGET_DISPOSAL, /obj/machinery/disposal, MONKEY_ENEMY_VISION)
return
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