Files
Bubberstation/code/datums/ai/generic/generic_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

99 lines
4.3 KiB
Plaintext

/**
* Generic Instrument Subtree, For your pawn playing instruments
*
* Requires at least a living mob that can hold items.
*
* relevant blackboards:
* * BB_SONG_INSTRUMENT - set by this subtree, is the song datum the pawn plays music from.
* * BB_SONG_LINES - not set by this subtree, is the song loaded into the song datum.
*/
/datum/ai_planning_subtree/generic_play_instrument/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/obj/item/instrument/song_player = controller.blackboard[BB_SONG_INSTRUMENT]
if(!song_player)
controller.queue_behavior(/datum/ai_behavior/find_and_set/in_hands, BB_SONG_INSTRUMENT, /obj/item/instrument)
return //we can't play a song since we do not have an instrument
var/list/parsed_song_lines = splittext(controller.blackboard[BB_SONG_LINES], "\n")
popleft(parsed_song_lines) //remove BPM as it is parsed out
if(!compare_list(song_player.song.lines, parsed_song_lines) || !song_player.song.repeat)
controller.queue_behavior(/datum/ai_behavior/setup_instrument, BB_SONG_INSTRUMENT, BB_SONG_LINES)
if(!song_player.song.playing) //we may stop playing if we weren't playing before, were setting up dk theme, or ran out of repeats (also causing setup behavior)
controller.queue_behavior(/datum/ai_behavior/play_instrument, BB_SONG_INSTRUMENT)
/datum/ai_planning_subtree/generic_play_instrument/end_planning
/datum/ai_planning_subtree/generic_play_instrument/end_planning/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
. = ..()
if (controller.blackboard_key_exists(BB_SONG_INSTRUMENT))
return SUBTREE_RETURN_FINISH_PLANNING // Don't plan anything else if we're playing an instrument
/**
* Generic Resist Subtree, resist if it makes sense to!
*
* Requires nothing beyond a living pawn, makes sense on a good amount of mobs since anything can get buckled.
*
* relevant blackboards:
* * None!
*/
/datum/ai_planning_subtree/generic_resist/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(SHOULD_RESIST(living_pawn) && SPT_PROB(RESIST_SUBTREE_PROB, seconds_per_tick))
controller.queue_behavior(/datum/ai_behavior/resist) //BRO IM ON FUCKING FIRE BRO
return SUBTREE_RETURN_FINISH_PLANNING //IM NOT DOING ANYTHING ELSE BUT EXTINGUISH MYSELF, GOOD GOD HAVE MERCY.
/**
* Generic Hunger Subtree,
*
* Requires at least a living mob that can hold items.
*
* 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
next_eat = world.time + rand(0, 30 SECONDS)
controller.set_blackboard_key(BB_NEXT_HUNGRY, next_eat)
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/food_or_drink/to_eat, BB_FOOD_TARGET, /obj/item, 2)
return SUBTREE_RETURN_FINISH_PLANNING
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))