mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-18 21:53:22 +00:00
* Fixes AI behavior with breaking cuffs and resisting aggressive grabs (#80328) ## About The Pull Request Makes it so that ai's recognize they're in a do_after after resisting, preventing them from processing and interrupting the do_after while they're in a condition that necessitates it. If it gets interrupted then they'll process as normal, or if they finish they'll be free. ## Why It's Good For The Game Monkeys can now resist things that they should've been, such as aggressive grabs or cuffs, instead of having their ai completely freeze when they're cuffed. ## Changelog 🆑 fix: ai can now tell if it is in a do_after for resisting and will not interrupt it. monkeys also now don't freeze up when aggressively grabbed and will resist out of those and cuffs. /🆑 * Fixes AI behavior with breaking cuffs and resisting aggressive grabs --------- Co-authored-by: Diamond_ <novadiamonddigger@gmail.com>
197 lines
6.7 KiB
Plaintext
197 lines
6.7 KiB
Plaintext
/*
|
|
AI controllers are a datumized form of AI that simulates the input a player would otherwise give to a mob. What this means is that these datums
|
|
have ways of interacting with a specific mob and control it.
|
|
*/
|
|
///OOK OOK OOK
|
|
|
|
/datum/ai_controller/monkey
|
|
movement_delay = 0.4 SECONDS
|
|
planning_subtrees = list(
|
|
/datum/ai_planning_subtree/generic_resist,
|
|
/datum/ai_planning_subtree/monkey_combat,
|
|
/datum/ai_planning_subtree/generic_hunger,
|
|
/datum/ai_planning_subtree/generic_play_instrument,
|
|
/datum/ai_planning_subtree/monkey_shenanigans,
|
|
)
|
|
blackboard = list(
|
|
BB_MONKEY_AGGRESSIVE = FALSE,
|
|
BB_MONKEY_BEST_FORCE_FOUND = 0,
|
|
BB_MONKEY_ENEMIES = list(),
|
|
BB_MONKEY_BLACKLISTITEMS = list(),
|
|
BB_MONKEY_PICKUPTARGET = null,
|
|
BB_MONKEY_PICKPOCKETING = FALSE,
|
|
BB_MONKEY_DISPOSING = FALSE,
|
|
BB_MONKEY_TARGET_DISPOSAL = null,
|
|
BB_MONKEY_CURRENT_ATTACK_TARGET = null,
|
|
BB_MONKEY_GUN_NEURONS_ACTIVATED = FALSE,
|
|
BB_MONKEY_GUN_WORKED = TRUE,
|
|
BB_SONG_LINES = MONKEY_SONG,
|
|
BB_RESISTING = FALSE,
|
|
)
|
|
idle_behavior = /datum/idle_behavior/idle_monkey
|
|
|
|
/datum/ai_controller/monkey/process(seconds_per_tick)
|
|
|
|
var/mob/living/living_pawn = src.pawn
|
|
|
|
if(!length(living_pawn.do_afters) && living_pawn.ai_controller.blackboard[BB_RESISTING])
|
|
living_pawn.ai_controller.set_blackboard_key(BB_RESISTING, FALSE)
|
|
|
|
if(living_pawn.ai_controller.blackboard[BB_RESISTING])
|
|
return
|
|
|
|
. = ..()
|
|
|
|
/datum/ai_controller/monkey/New(atom/new_pawn)
|
|
var/static/list/control_examine = list(
|
|
ORGAN_SLOT_EYES = span_monkey("eyes have a primal look in them."),
|
|
)
|
|
AddElement(/datum/element/ai_control_examine, control_examine)
|
|
return ..()
|
|
|
|
/datum/ai_controller/monkey/pun_pun
|
|
movement_delay = 0.7 SECONDS //pun pun moves slower so the bartender can keep track of them
|
|
planning_subtrees = list(
|
|
/datum/ai_planning_subtree/generic_resist,
|
|
/datum/ai_planning_subtree/monkey_combat,
|
|
/datum/ai_planning_subtree/generic_hunger,
|
|
/datum/ai_planning_subtree/generic_play_instrument,
|
|
/datum/ai_planning_subtree/punpun_shenanigans,
|
|
)
|
|
idle_behavior = /datum/idle_behavior/idle_monkey/pun_pun
|
|
|
|
/datum/ai_controller/monkey/angry
|
|
|
|
/datum/ai_controller/monkey/angry/TryPossessPawn(atom/new_pawn)
|
|
. = ..()
|
|
if(. & AI_CONTROLLER_INCOMPATIBLE)
|
|
return
|
|
pawn = new_pawn
|
|
set_blackboard_key(BB_MONKEY_AGGRESSIVE, TRUE) //Angry cunt
|
|
set_trip_mode(mode = FALSE)
|
|
|
|
/datum/ai_controller/monkey/TryPossessPawn(atom/new_pawn)
|
|
if(!isliving(new_pawn))
|
|
return AI_CONTROLLER_INCOMPATIBLE
|
|
|
|
var/mob/living/living_pawn = new_pawn
|
|
living_pawn.AddElement(/datum/element/relay_attackers)
|
|
RegisterSignal(new_pawn, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked))
|
|
RegisterSignal(new_pawn, COMSIG_LIVING_START_PULL, PROC_REF(on_startpulling))
|
|
RegisterSignal(new_pawn, COMSIG_LIVING_TRY_SYRINGE, PROC_REF(on_try_syringe))
|
|
RegisterSignal(new_pawn, COMSIG_CARBON_CUFF_ATTEMPTED, PROC_REF(on_attempt_cuff))
|
|
RegisterSignal(new_pawn, COMSIG_MOB_MOVESPEED_UPDATED, PROC_REF(update_movespeed))
|
|
|
|
movement_delay = living_pawn.cached_multiplicative_slowdown
|
|
return ..() //Run parent at end
|
|
|
|
/datum/ai_controller/monkey/UnpossessPawn(destroy)
|
|
|
|
UnregisterSignal(pawn, list(
|
|
COMSIG_ATOM_WAS_ATTACKED,
|
|
COMSIG_LIVING_START_PULL,
|
|
COMSIG_LIVING_TRY_SYRINGE,
|
|
COMSIG_CARBON_CUFF_ATTEMPTED,
|
|
COMSIG_MOB_MOVESPEED_UPDATED,
|
|
))
|
|
|
|
return ..() //Run parent at end
|
|
|
|
/datum/ai_controller/monkey/on_sentience_lost()
|
|
. = ..()
|
|
set_trip_mode(mode = TRUE)
|
|
|
|
/datum/ai_controller/monkey/able_to_run()
|
|
var/mob/living/living_pawn = pawn
|
|
|
|
if(living_pawn.incapacitated(IGNORE_RESTRAINTS | IGNORE_GRAB | IGNORE_STASIS) || living_pawn.stat > CONSCIOUS)
|
|
return FALSE
|
|
return ..()
|
|
|
|
/datum/ai_controller/monkey/proc/set_trip_mode(mode = TRUE)
|
|
var/mob/living/carbon/regressed_monkey = pawn
|
|
var/brain = regressed_monkey.get_organ_slot(ORGAN_SLOT_BRAIN)
|
|
if(istype(brain, /obj/item/organ/internal/brain/primate)) // In case we are a monkey AI in a human brain by who was previously controlled by a client but it now not by some marvel
|
|
var/obj/item/organ/internal/brain/primate/monkeybrain = brain
|
|
monkeybrain.tripping = mode
|
|
|
|
///re-used behavior pattern by monkeys for finding a weapon
|
|
/datum/ai_controller/monkey/proc/TryFindWeapon()
|
|
var/mob/living/living_pawn = pawn
|
|
|
|
if(!(locate(/obj/item) in living_pawn.held_items))
|
|
set_blackboard_key(BB_MONKEY_BEST_FORCE_FOUND, 0)
|
|
|
|
if(blackboard[BB_MONKEY_GUN_NEURONS_ACTIVATED] && (locate(/obj/item/gun) in living_pawn.held_items))
|
|
// We have a gun, what could we possibly want?
|
|
return FALSE
|
|
|
|
var/obj/item/weapon
|
|
var/list/nearby_items = list()
|
|
for(var/obj/item/item in oview(2, living_pawn))
|
|
nearby_items += item
|
|
|
|
for(var/obj/item/item in living_pawn.held_items) // If we've got some garbage in out hands thats going to stop us from effectivly attacking, we should get rid of it.
|
|
if(item.force < 2)
|
|
living_pawn.dropItemToGround(item)
|
|
|
|
weapon = GetBestWeapon(src, nearby_items, living_pawn.held_items)
|
|
|
|
var/pickpocket = FALSE
|
|
for(var/mob/living/carbon/human/human in oview(5, living_pawn))
|
|
var/obj/item/held_weapon = GetBestWeapon(src, human.held_items + weapon, living_pawn.held_items)
|
|
if(held_weapon == weapon) // It's just the same one, not a held one
|
|
continue
|
|
pickpocket = TRUE
|
|
weapon = held_weapon
|
|
|
|
if(!weapon || (weapon in living_pawn.held_items))
|
|
return FALSE
|
|
|
|
if(weapon.force < 2) // our bite does 2 damage on avarage, no point in settling for anything less
|
|
return FALSE
|
|
|
|
set_blackboard_key(BB_MONKEY_PICKUPTARGET, weapon)
|
|
set_movement_target(type, weapon)
|
|
if(pickpocket)
|
|
queue_behavior(/datum/ai_behavior/monkey_equip/pickpocket)
|
|
else
|
|
queue_behavior(/datum/ai_behavior/monkey_equip/ground)
|
|
return TRUE
|
|
|
|
///Reactive events to being hit
|
|
/datum/ai_controller/monkey/proc/retaliate(mob/living/living_mob)
|
|
// just to be safe
|
|
if(QDELETED(living_mob))
|
|
return
|
|
|
|
add_blackboard_key_assoc(BB_MONKEY_ENEMIES, living_mob, MONKEY_HATRED_AMOUNT)
|
|
|
|
/datum/ai_controller/monkey/proc/on_attacked(datum/source, mob/attacker)
|
|
SIGNAL_HANDLER
|
|
if(prob(MONKEY_RETALIATE_PROB))
|
|
retaliate(attacker)
|
|
|
|
/datum/ai_controller/monkey/proc/on_startpulling(datum/source, atom/movable/puller, state, force)
|
|
SIGNAL_HANDLER
|
|
var/mob/living/living_pawn = pawn
|
|
if(!IS_DEAD_OR_INCAP(living_pawn) && prob(MONKEY_PULL_AGGRO_PROB)) // nuh uh you don't pull me!
|
|
retaliate(living_pawn.pulledby)
|
|
return TRUE
|
|
|
|
/datum/ai_controller/monkey/proc/on_try_syringe(datum/source, mob/user)
|
|
SIGNAL_HANDLER
|
|
// chance of monkey retaliation
|
|
if(prob(MONKEY_SYRINGE_RETALIATION_PROB))
|
|
retaliate(user)
|
|
|
|
/datum/ai_controller/monkey/proc/on_attempt_cuff(datum/source, mob/user)
|
|
SIGNAL_HANDLER
|
|
// chance of monkey retaliation
|
|
if(prob(MONKEY_CUFF_RETALIATION_PROB))
|
|
retaliate(user)
|
|
|
|
/datum/ai_controller/monkey/proc/update_movespeed(mob/living/pawn)
|
|
SIGNAL_HANDLER
|
|
movement_delay = pawn.cached_multiplicative_slowdown
|