Files
Alexis 21b4095dfd [MDB IGNORE] [IDB IGNORE] Upstream Sync - 04/17/2026 (#5453)
Upstream 04/17/2026

fixes https://github.com/Bubberstation/Bubberstation/issues/5549

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com>
Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com>
Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com>
Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com>
Co-authored-by: loganuk <fakeemail123@aol.com>
Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com>
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com>
Co-authored-by: Isratosh <Isratosh@hotmail.com>
Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com>
Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com>
Co-authored-by: Alexander V. <volas@ya.ru>
Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com>
Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Tim <timothymtorres@gmail.com>
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com>
Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com>
Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com>
Co-authored-by: Josh <josh.adam.powell@gmail.com>
Co-authored-by: Josh Powell <josh.powell@softwire.com>
Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com>
Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com>
Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com>
Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
2026-05-16 00:56:00 +02:00

493 lines
18 KiB
Plaintext

/mob/living/basic/mouse
name = "mouse"
desc = "This cute little guy just loves the taste of insulated electrical cables. Isn't he adorable?"
icon_state = "mouse_gray"
icon_living = "mouse_gray"
icon_dead = "mouse_gray_dead"
held_state = "mouse_gray"
maxHealth = 5
health = 5
density = FALSE
pass_flags = PASSTABLE|PASSGRILLE|PASSMOB
mob_size = MOB_SIZE_TINY
can_be_held = TRUE
held_w_class = WEIGHT_CLASS_TINY
mob_biotypes = MOB_ORGANIC|MOB_BEAST
gold_core_spawnable = FRIENDLY_SPAWN
faction = list(FACTION_RAT, FACTION_MAINT_CREATURES)
butcher_results = list(/obj/item/food/meat/slab/mouse = 1)
speak_emote = list("squeaks")
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "gently pushes aside"
response_disarm_simple = "gently push aside"
response_harm_continuous = "splats"
response_harm_simple = "splat"
ai_controller = /datum/ai_controller/basic_controller/mouse
/// What color our mouse is. Brown, gray and white - leave blank for random.
var/body_color
/// Does this mouse contribute to the ratcap?
var/contributes_to_ratcap = TRUE
/// Probability that, if we successfully bite a shocked cable, that we will die to it.
var/cable_zap_prob = 85
///list of pet commands we follow
var/static/list/pet_commands = list(
/datum/pet_command/idle,
/datum/pet_command/free,
/datum/pet_command/follow/start_active,
/datum/pet_command/perform_trick_sequence,
)
/datum/emote/mouse
abstract_type = /datum/emote/mouse
mob_type_allowed_typecache = /mob/living/basic/mouse
mob_type_blacklist_typecache = list()
/datum/emote/mouse/squeak
key = "squeak"
key_third_person = "squeaks"
message = "squeak!"
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
vary = TRUE
sound = 'sound/mobs/non-humanoids/mouse/mousesqueek.ogg'
/mob/living/basic/mouse/Initialize(mapload, tame = FALSE, new_body_color)
. = ..()
if(contributes_to_ratcap)
SSmobs.cheeserats |= src
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
if(tame)
ADD_TRAIT(src, TRAIT_TAMED, INNATE_TRAIT)
if(!isnull(new_body_color))
body_color = new_body_color
if(isnull(body_color))
body_color = pick("brown", "gray", "white")
held_state = "mouse_[body_color]" // not handled by variety element
AddElement(/datum/element/animal_variety, "mouse", body_color, FALSE)
AddElement(/datum/element/swabable, CELL_LINE_TABLE_MOUSE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 10)
AddComponent(/datum/component/squeak, list('sound/mobs/non-humanoids/mouse/mousesqueek.ogg' = 1), 100, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) //as quiet as a mouse or whatever
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
)
AddComponent(/datum/component/obeys_commands, pet_commands)
AddElement(/datum/element/connect_loc, loc_connections)
make_tameable()
AddComponent(/datum/component/swarming, 16, 16) //max_x, max_y
/mob/living/basic/mouse/proc/make_tameable()
if (HAS_TRAIT(src, TRAIT_TAMED))
add_faction(FACTION_NEUTRAL)
else
var/static/list/food_types = list(/obj/item/food/cheese)
AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 100)
AddElement(/datum/element/regal_rat_minion, converted_path = /mob/living/basic/mouse/rat, pet_commands = GLOB.regal_rat_minion_commands)
/mob/living/basic/mouse/Destroy()
SSmobs.cheeserats -= src
return ..()
/mob/living/basic/mouse/examine(mob/user)
. = ..()
var/sameside = user.faction_check_atom(src, exact_match = TRUE)
if(isregalrat(user))
if(sameside)
. += span_notice("This rat serves under you.")
else
. += span_warning("This peasant serves a different king! Strike [p_them()] down!")
else if(user != src && ismouse(user))
if(sameside)
. += span_notice("You both serve the same king.")
else
. += span_warning("This fool serves a different king!")
/// Kills the rat and changes its icon state to be splatted (bloody).
/mob/living/basic/mouse/proc/splat()
icon_dead = "mouse_[body_color]_splat"
adjust_health(maxHealth)
// On revival, re-add the mouse to the ratcap, or block it if we're at it
/mob/living/basic/mouse/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE)
if(!contributes_to_ratcap)
return ..()
var/aheal_included = full_heal_flags & HEAL_ADMIN
var/cap = CONFIG_GET(number/ratcap)
if(!aheal_included && !ckey && length(SSmobs.cheeserats) >= cap)
visible_message(span_warning("[src] twitches, but does not continue moving \
due to the overwhelming rodent population on the station!"))
return
. = ..()
if(stat != DEAD)
SSmobs.cheeserats |= src
// On death, remove the mouse from the ratcap, and turn it into an item if applicable
/mob/living/basic/mouse/death(gibbed)
SSmobs.cheeserats -= src
// Rats with a mind will not turn into a lizard snack on death
if(mind)
return ..()
// Call parent with gibbed = TRUE, becuase we're getting rid of the body
. = ..(TRUE)
// Now if we were't ACTUALLY gibbed, spawn the dead mouse
if(!gibbed)
var/make_a_corpse = TRUE
var/place_to_make_corpse = loc
var/must_equip = FALSE
var/equip_slot
var/mob/holding_mob
var/obj/item/mob_holder/found_holder
if(istype(loc, /obj/item/mob_holder))//If our mouse is dying in place holder we want to put the dead mouse where the place holder was
found_holder = loc
place_to_make_corpse = found_holder.loc
if(istype(found_holder.loc,/mob/living/carbon))
holding_mob = found_holder.loc
place_to_make_corpse = get_turf(holding_mob)
equip_slot = holding_mob.get_slot_by_item(found_holder)
if(equip_slot == ITEM_SLOT_HANDS || equip_slot == ITEM_SLOT_RPOCKET || equip_slot == ITEM_SLOT_LPOCKET)
must_equip = TRUE
if(istype(found_holder.loc, /obj/machinery/microwave))//Microwaves gib things that die when cooked, so we don't need to make a dead body too
make_a_corpse = FALSE
if(make_a_corpse)
var/obj/item/food/deadmouse/mouse = new(place_to_make_corpse)
mouse.copy_corpse(src)
if(HAS_TRAIT(src, TRAIT_BEING_SHOCKED))
mouse.desc = "They're toast."
mouse.add_atom_colour("#3A3A3A", FIXED_COLOUR_PRIORITY)
found_holder?.release(FALSE)
if(must_equip)
if(equip_slot == ITEM_SLOT_HANDS)
holding_mob.dropItemToGround(found_holder)
holding_mob.equip_to_slot(mouse,equip_slot)
qdel(src)
/mob/living/basic/mouse/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
. = ..()
if(!.)
return
if(!proximity_flag)
return
if(istype(attack_target, /obj/item/food/cheese))
try_consume_cheese(attack_target)
return TRUE
if(istype(attack_target, /obj/structure/cable))
try_bite_cable(attack_target)
return TRUE
/// Signal proc for [COMSIG_ATOM_ENTERED]. Sends a lil' squeak to chat when someone walks over us.
/mob/living/basic/mouse/proc/on_entered(datum/source, atom/movable/entered)
SIGNAL_HANDLER
if(ishuman(entered) && stat == CONSCIOUS)
to_chat(entered, span_notice("[icon2html(src, entered)] Squeak!"))
/// Called when a mouse is hand-fed some cheese, it will stop being afraid of humans
/mob/living/basic/mouse/tamed(mob/living/tamer, obj/item/food/cheese/cheese)
. = ..()
new /obj/effect/temp_visual/heart(loc)
add_faction(FACTION_NEUTRAL)
try_consume_cheese(cheese)
ai_controller.CancelActions() // Interrupt any current fleeing
/// Attempts to consume a piece of cheese, causing a few effects.
/mob/living/basic/mouse/proc/try_consume_cheese(obj/item/food/cheese/cheese)
// Royal cheese will evolve us into a regal rat
if(istype(cheese, /obj/item/food/cheese/royal))
visible_message(
span_warning("[src] devours [cheese]! They morph into something... greater!"),
span_notice("You devour [cheese], and start morphing into something... greater!"),
)
evolve_into_regal_rat()
qdel(cheese)
return
var/cap = CONFIG_GET(number/ratcap)
// Normal cheese will either heal us
if(prob(90) || health < maxHealth)
visible_message(
span_notice("[src] nibbles [cheese]."),
span_notice("You nibble [cheese][health < maxHealth ? ", restoring your health" : ""].")
)
adjust_health(-maxHealth)
// Or, if we're at full health, there's a 10% chance that normal cheese will spawn a new mouse
// ...if the rat cap allows us, that is
else if(length(SSmobs.cheeserats) >= cap)
visible_message(
span_warning("[src] carefully eats [cheese], hiding it from the [cap] mice on the station!"),
span_notice("You carefully nibble [cheese], hiding it from the [cap] other mice on board the station.")
)
else
visible_message(
span_notice("[src] nibbles through [cheese], attracting another mouse!"),
span_notice("You nibble through [cheese], attracting another mouse!")
)
create_a_new_rat()
qdel(cheese)
/// Evolves this rat into a regal rat
/mob/living/basic/mouse/proc/evolve_into_regal_rat()
var/mob/living/basic/regal_rat/controlled/regalrat = new(loc)
mind?.transfer_to(regalrat)
INVOKE_ASYNC(regalrat, TYPE_PROC_REF(/atom/movable, say), "RISE, MY SUBJECTS! SCREEEEEEE!")
qdel(src)
/// Creates a new mouse based on this mouse's subtype.
/mob/living/basic/mouse/proc/create_a_new_rat()
new /mob/living/basic/mouse(loc, HAS_TRAIT(src, TRAIT_TAMED))
/// Biting into a cable will cause a mouse to get shocked and die if applicable. Or do nothing if they're lucky.
/mob/living/basic/mouse/proc/try_bite_cable(obj/structure/cable/cable)
if(cable.avail() && !HAS_TRAIT(src, TRAIT_SHOCKIMMUNE) && prob(cable_zap_prob))
visible_message(
span_warning("[src] chews through \the [cable]. It's toast!"),
span_userdanger("As you bite deeply into [cable], you suddenly realize this may have been a bad idea."),
span_hear("You hear electricity crack."),
)
// Finely toasted
ADD_TRAIT(src, TRAIT_BEING_SHOCKED, TRAIT_GENERIC)
// Unfortunately we can't check the return value of electrocute_act before displaying a message,
// as it's possible the damage from electrocution results in our hunter being deleted.
// But what are the odds of the shock failing? Hahaha...
electrocute_act(maxHealth * 2, cable, flags = SHOCK_SUPPRESS_MESSAGE)
else
visible_message(
span_warning("[src] chews through \the [cable]."),
span_notice("You chew through \the [cable]."),
)
playsound(cable, 'sound/effects/sparks/sparks2.ogg', 100, TRUE)
cable.deconstruct()
/mob/living/basic/mouse/white
body_color = "white"
icon_state = "mouse_white"
held_state = "mouse_white"
/mob/living/basic/mouse/gray
body_color = "gray"
icon_state = "mouse_gray"
/mob/living/basic/mouse/brown
body_color = "brown"
icon_state = "mouse_brown"
held_state = "mouse_brown"
//TOM IS ALIVE! SQUEEEEEEEE~K :)
/mob/living/basic/mouse/brown/tom
name = "Tom"
desc = "Jerry the cat is not amused."
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "gently pushes aside"
response_disarm_simple = "gently push aside"
response_harm_continuous = "splats"
response_harm_simple = "splat"
gold_core_spawnable = NO_SPAWN
contributes_to_ratcap = FALSE
/mob/living/basic/mouse/brown/tom/make_tameable()
ADD_TRAIT(src, TRAIT_TAMED, INNATE_TRAIT)
return ..()
/mob/living/basic/mouse/brown/tom/Initialize(mapload)
. = ..()
// Tom fears no cable.
ADD_TRAIT(src, TRAIT_SHOCKIMMUNE, INNATE_TRAIT)
AddElement(/datum/element/pet_bonus, "squeak")
/mob/living/basic/mouse/brown/tom/create_a_new_rat()
new /mob/living/basic/mouse/brown(loc, HAS_TRAIT(src, TRAIT_TAMED)) // dominant gene
/mob/living/basic/mouse/rat
name = "rat"
desc = "They're a nasty, ugly, evil, disease-ridden rodent with anger issues."
gold_core_spawnable = HOSTILE_SPAWN
melee_damage_lower = 3
melee_damage_upper = 5
obj_damage = 5
maxHealth = 15
health = 15
ai_controller = /datum/ai_controller/basic_controller/mouse/rat
/mob/living/basic/mouse/rat/make_tameable()
return // Unlike in real life, space rats are horrible creatures who don't like you
/mob/living/basic/mouse/rat/create_a_new_rat()
new /mob/living/basic/mouse/rat(loc)
/// Mice turn into food when they die
/obj/item/food/deadmouse
name = "dead mouse"
desc = "They look like somebody dropped the bass on it. A lizard's favorite meal."
icon = 'icons/mob/simple/animal.dmi'
icon_state = "mouse_gray_dead"
bite_consumption = 3
eatverbs = list("devour")
food_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtypes = GORE | MEAT | RAW
decomp_req_handle = TRUE
ant_attracting = FALSE
decomp_type = /obj/item/food/deadmouse/moldy
var/body_color = "gray"
var/critter_type = /mob/living/basic/mouse
/obj/item/food/deadmouse/Initialize(mapload)
. = ..()
AddElement(/datum/element/swabable, CELL_LINE_TABLE_MOUSE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 10)
RegisterSignal(src, COMSIG_ATOM_ON_LAZARUS_INJECTOR, PROC_REF(use_lazarus))
/obj/item/food/deadmouse/grind_results()
return list(/datum/reagent/blood = 20, /datum/reagent/consumable/liquidgibs = 5)
/// Copy properties from an imminently dead mouse
/obj/item/food/deadmouse/proc/copy_corpse(mob/living/basic/mouse/dead_critter)
body_color = dead_critter.body_color
critter_type = dead_critter.type
name = dead_critter.name
icon_state = dead_critter.icon_dead
/obj/item/food/deadmouse/examine(mob/user)
. = ..()
if (reagents?.has_reagent(/datum/reagent/yuck) || reagents?.has_reagent(/datum/reagent/fuel))
. += span_warning("[p_Theyre()] dripping with fuel and smells terrible.")
///Spawn a new mouse from this dead mouse item when hit by a lazarus injector and conditions are met.
/obj/item/food/deadmouse/proc/use_lazarus(datum/source, obj/item/lazarus_injector/injector, mob/user)
SIGNAL_HANDLER
if(injector.revive_type != SENTIENCE_ORGANIC)
balloon_alert(user, "invalid creature!")
return
var/mob/living/basic/mouse/revived_critter = new critter_type (drop_location(), FALSE, body_color)
revived_critter.name = name
revived_critter.lazarus_revive(user, injector.malfunctioning)
injector.expend(revived_critter, user)
qdel(src)
return LAZARUS_INJECTOR_USED
/obj/item/food/deadmouse/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers)
var/mob/living/living_user = user
if(istype(living_user) && attacking_item.get_sharpness() && living_user.combat_mode)
if(!isturf(loc))
balloon_alert(user, "can't butcher here!")
return
balloon_alert(user, "butchering...")
if(!do_after(user, 0.75 SECONDS, src))
balloon_alert(user, "interrupted!")
return
loc.balloon_alert(user, "butchered")
new /obj/item/food/meat/slab/mouse(loc)
qdel(src)
return
return ..()
/obj/item/food/deadmouse/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isnull(reagents) || !interacting_with.is_open_container())
return NONE
// is_open_container will not return truthy if target.reagents doesn't exist
var/datum/reagents/target_reagents = interacting_with.reagents
var/trans_amount = reagents.maximum_volume - reagents.total_volume * (4 / 3)
if(target_reagents.has_reagent(/datum/reagent/fuel) && target_reagents.trans_to(src, trans_amount))
to_chat(user, span_notice("You dip [src] into [interacting_with]."))
return ITEM_INTERACT_SUCCESS
/obj/item/food/deadmouse/moldy
name = "moldy dead mouse"
desc = "A dead rodent, consumed by mold and rot. There is a slim chance that a lizard might still eat it."
icon_state = "mouse_gray_dead"
food_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/mold = 10)
foodtypes = GORE | MEAT | RAW | GROSS
preserved_food = TRUE
/obj/item/food/deadmouse/moldy/grind_results()
return list(/datum/reagent/blood = 20, /datum/reagent/consumable/liquidgibs = 5, /datum/reagent/consumable/mold = 10)
/// The mouse AI controller
/datum/ai_controller/basic_controller/mouse
blackboard = list( // Always cowardly
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, // Use this to find people to run away from
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
BB_BASIC_MOB_FLEE_DISTANCE = 3,
BB_SONG_LINES = MOUSE_SONG,
)
ai_traits = PASSIVE_AI_FLAGS
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
// Try to speak, because it's cute
/datum/ai_planning_subtree/random_speech/mouse,
// Follow the boss's orders
/datum/ai_planning_subtree/pet_planning,
// Look for and execute hunts for cheese even if someone is looking at us
/datum/ai_planning_subtree/find_and_hunt_target/look_for_cheese,
// Next priority is to try and appreoach a keyboard
/datum/ai_planning_subtree/approach_synthesizer,
// And play it if we are near it
/datum/ai_planning_subtree/generic_play_instrument/end_planning,
// Next priority is see if anyone is looking at us
/datum/ai_planning_subtree/simple_find_nearest_target_to_flee,
// Skedaddle
/datum/ai_planning_subtree/flee_target/mouse,
// Otherwise, look for and execute hunts for cabling
/datum/ai_planning_subtree/find_and_hunt_target/look_for_cables,
)
/// Don't look for anything to run away from if you are distracted by being adjacent to cheese
/datum/ai_planning_subtree/flee_target/mouse
/datum/ai_planning_subtree/flee_target/mouse/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/atom/hunted_cheese = controller.blackboard[BB_CURRENT_HUNTING_TARGET]
if (!isnull(hunted_cheese))
return // We see some cheese, which is more important than our life
return ..()
/// AI controller for rats, slightly more complex than mice becuase they attack people
/datum/ai_controller/basic_controller/mouse/rat
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
BB_BASIC_MOB_CURRENT_TARGET = null, // heathen
BB_CURRENT_HUNTING_TARGET = null, // cheese
BB_LOW_PRIORITY_HUNTING_TARGET = null, // cable
BB_OWNER_SELF_HARM_RESPONSES = list(
"*me cleans its whiskers in disapproval.",
"*me squeaks sadly.",
"*me sheds a single small tear."
)
)
ai_traits = DEFAULT_AI_FLAGS | STOP_MOVING_WHEN_PULLED
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
/datum/ai_planning_subtree/escape_captivity,
/datum/ai_planning_subtree/pet_planning,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/attack_obstacle_in_path,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
/datum/ai_planning_subtree/find_and_hunt_target/look_for_cheese,
/datum/ai_planning_subtree/random_speech/mouse,
/datum/ai_planning_subtree/find_and_hunt_target/look_for_cables,
)