Refactor var/can_be_held to an element (#96917)

## About The Pull Request

We were doing a lot of mental gymnastics in a bunch of other places, so
let's change this wonky var to a streamlined element that will rely on
the same signals that a lot of stuff was already using/accounting for in
its own signal handling pathways, instead of being a weird coverage gap.
This patch should also make the whole "checking if someone is attempting
to pick a mob up" thing make a lot more sense and use a unified proc
instead of spot-checking whatever random things it wants to spot-check.
## Why It's Good For The Game

I didn't know this was a thing until I looked at #96873 and it made me
sad because literally everything else involving mob drag-and-drop is
already signal-based except this weird stinker that relied on proc
overrides. Never mind that now, let's use nice traits to avoid
typecasting and elements to avoid duplicating code. It should also be
much cleaner to add holdability to a mob isntead of having to do
`can_be_held = FALSE` as a weird behavior (at least one instance had
this non-necessarily). All this really is is just middleware on the
extant /mob/living code but still making it in proper lockstep with the
other signalling procs.

I did port over raptor code faithfully but I'm not 100% sure if it was
meant to be like this? Regardless, that's how it is.
## Changelog
🆑
refactor: Picking up mobs has been altered a bit, please report any bugs
or glitches.
/🆑
This commit is contained in:
san7890
2026-07-13 16:57:47 +02:00
committed by GitHub
parent 02b6286fee
commit cb535cdfa6
30 changed files with 112 additions and 52 deletions
@@ -188,6 +188,9 @@
///Called on user, from base of /datum/strippable_item/try_(un)equip() (atom/target, obj/item/equipping?)
#define COMSIG_TRY_STRIP "try_strip"
#define COMPONENT_CANT_STRIP (1<<0)
///Called when a mob's strip menu is attempting to be opened,from base /datum/element/strippable/proc/mouse_drop_onto (datum/source, atom/over, mob/user)
#define COMSIG_MOB_STRIP_MENU_OPEN "mob_strip_menu_open"
#define COMPONENT_BLOCK_STRIP_MENU_OPEN (1<<0)
///From /datum/component/face_decal/splat/Initialize()
#define COMSIG_MOB_HIT_BY_SPLAT "hit_by_splat"
///From /obj/item/gun/proc/check_botched()
@@ -1,3 +1,8 @@
/// Sent to the parent before even attempting to dump items, from base of /datum/storage/dump_content_at(): (datum/storage/storage, atom/over, mob/user)
#define COMSIG_STORAGE_DUMP_PRE_TRANSFER "storage_dump_pre_transfer"
/// Return to stop the dump before it even has a chance of starting
#define CANCEL_STORAGE_DUMP (1<<0)
/// Sent when /datum/storage/dump_content_at(): (obj/item/storage_source, mob/user)
#define COMSIG_STORAGE_DUMP_CONTENT "storage_dump_contents"
/// Return to stop the standard dump behavior.
@@ -5,6 +10,7 @@
/// Sent after dumping into some other storage object: (atom/dest_object, mob/user)
#define COMSIG_STORAGE_DUMP_POST_TRANSFER "storage_dump_into_storage"
/// Sent before storing an item (obj/item/being_stored, mob/user, force, messages)
#define COMSIG_ATOM_PRE_STORED_ITEM "atom_pre_storing_item"
/// Return to block the item from being stored.
+50
View File
@@ -0,0 +1,50 @@
/datum/element/can_be_held
element_flags = ELEMENT_BESPOKE
argument_hash_start_idx = 2
/datum/element/can_be_held/Attach(datum/source)
. = ..()
if(!isliving(source))
return ELEMENT_INCOMPATIBLE
RegisterSignal(source, COMSIG_MOUSEDROP_ONTO, PROC_REF(on_mousedrop_onto))
RegisterSignal(source, COMSIG_MOB_STRIP_MENU_OPEN, PROC_REF(on_strip_menu_open))
RegisterSignal(source, COMSIG_STORAGE_DUMP_PRE_TRANSFER, PROC_REF(on_attempt_storage_dump))
/datum/element/can_be_held/Detach(datum/source)
UnregisterSignal(source, list(COMSIG_MOUSEDROP_ONTO, COMSIG_MOB_STRIP_MENU_OPEN, COMSIG_STORAGE_DUMP_PRE_TRANSFER))
return ..()
/// Used to determine the "intent" of the action that the user mob is trying to employ on the target.
/datum/element/can_be_held/proc/trying_to_hold_mob(mob/living/user, mob/living/target)
return isliving(user) && user.grab_state == GRAB_AGGRESSIVE && user.pulling == target
/// Handles the mob being dropped onto the user mob.
/datum/element/can_be_held/proc/on_mousedrop_onto(datum/source, atom/over, mob/user)
SIGNAL_HANDLER
if(!trying_to_hold_mob(user, source))
return
INVOKE_ASYNC(source, TYPE_PROC_REF(/mob/living, mob_try_pickup), user)
return COMPONENT_CANCEL_MOUSEDROP_ONTO
/datum/element/can_be_held/proc/on_strip_menu_open(datum/source, atom/over, mob/user)
SIGNAL_HANDLER
if(!trying_to_hold_mob(user, source))
return
INVOKE_ASYNC(source, TYPE_PROC_REF(/mob/living, mob_try_pickup), user)
return COMPONENT_BLOCK_STRIP_MENU_OPEN
/datum/element/can_be_held/proc/on_attempt_storage_dump(datum/source, atom/over, mob/user)
SIGNAL_HANDLER
if(!trying_to_hold_mob(user, source))
return
INVOKE_ASYNC(source, TYPE_PROC_REF(/mob/living, mob_try_pickup), user)
return CANCEL_STORAGE_DUMP
+3 -6
View File
@@ -36,6 +36,9 @@
/datum/element/strippable/proc/mouse_drop_onto(datum/source, atom/over, mob/user)
SIGNAL_HANDLER
if(SEND_SIGNAL(source, COMSIG_MOB_STRIP_MENU_OPEN, over, user) & COMPONENT_BLOCK_STRIP_MENU_OPEN)
return
if (user == source)
return
if (over != user)
@@ -57,12 +60,6 @@
if (!isnull(should_strip_proc_path) && !call(source, should_strip_proc_path)(user))
return
// Snowflake for mob scooping
if (isliving(source))
var/mob/living/mob = source
if (mob.can_be_held && (user.grab_state == GRAB_AGGRESSIVE) && (user.pulling == source))
return
var/datum/strip_menu/strip_menu = LAZYACCESS(strip_menus, source)
if (isnull(strip_menu))
+3 -5
View File
@@ -795,6 +795,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
/datum/storage/proc/on_mousedrop_onto(datum/source, atom/over_object, mob/user)
SIGNAL_HANDLER
if(SEND_SIGNAL(parent, COMSIG_STORAGE_DUMP_PRE_TRANSFER, src, over_object, user) & CANCEL_STORAGE_DUMP)
return COMPONENT_CANCEL_MOUSEDROP_ONTO
if(ismecha(user.loc) || user.incapacitated || !user.canUseStorage())
return NONE
@@ -816,11 +819,6 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
if(!user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING))
return NONE
if(isliving(parent) && user.pulling == parent)
var/mob/living/as_living = parent
if(as_living.can_be_held)
return
parent.add_fingerprint(user)
INVOKE_ASYNC(src, PROC_REF(open_storage), user)
return COMPONENT_CANCEL_MOUSEDROP_ONTO
@@ -696,7 +696,7 @@
for(var/mob/living/victim in microwave_contents)
if(victim.electrocute_act(shock_damage = 100, source = src, siemens_coeff = 1, flags = SHOCK_NOGLOVES))
successful_shock = TRUE
if(victim.stat == DEAD) //This is mostly so humans that can_be_held don't get gibbed from one microwave run alone, but mice become burnt messes
if(victim.stat == DEAD) //This is mostly so humans that have the can_be_held element don't get gibbed from one microwave run alone, but mice become burnt messes
victim.gib()
muck()
if(successful_shock) //We only want to give feedback once, regardless of how many mobs got shocked
@@ -9,7 +9,6 @@
layer = BELOW_MOB_LAYER
anchored = FALSE
health = 35
can_be_held = TRUE
maxHealth = 35
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 7.8, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 2)
path_image_color = "#80dae7"
@@ -93,6 +92,7 @@
our_screwdriver = new(src)
our_rods = new(src, our_rods::max_amount)
set_color(toolbox_color)
AddElement(/datum/element/can_be_held)
START_PROCESSING(SSobj, src)
/mob/living/basic/bot/repairbot/proc/set_color(new_color)
@@ -46,7 +46,6 @@
lighting_cutoff_red = 30
lighting_cutoff_green = 35
lighting_cutoff_blue = 25
can_be_held = TRUE
worn_slot_flags = ITEM_SLOT_HEAD
inhand_holder_type = /obj/item/mob_holder/drone
/// `TRUE` if we have picked our visual appearance, `FALSE` otherwise (default)
@@ -155,6 +154,8 @@
listener.RegisterSignal(src, COMSIG_LIVING_DEATH, TYPE_PROC_REF(/datum/alarm_listener, prevent_alarm_changes))
listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, TYPE_PROC_REF(/datum/alarm_listener, allow_alarm_changes))
AddElement(/datum/element/can_be_held)
/mob/living/basic/drone/med_hud_set_health()
set_hud_image_state(DIAG_HUD, "huddiag[RoundDiagBar(health/maxHealth)]")
@@ -36,7 +36,6 @@
mob_biotypes = MOB_ORGANIC|MOB_BUG
density = FALSE
gold_core_spawnable = FRIENDLY_SPAWN
can_be_held = TRUE
held_w_class = WEIGHT_CLASS_TINY
environment_smash = ENVIRONMENT_SMASH_NONE
habitable_atmos = null
@@ -71,6 +70,7 @@
AddComponent(/datum/component/obeys_commands, pet_commands)
AddElement(/datum/element/swabable, CELL_LINE_TABLE_QUEEN_BEE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
AddElement(/datum/element/basic_allergenic_attack, allergen = BUGS, allergen_chance = 33, histamine_add = 5)
AddElement(/datum/element/can_be_held)
/mob/living/basic/bee/mob_pickup(mob/living/picker)
if(flags_1 & HOLOGRAM_1)
@@ -18,7 +18,6 @@
health = 15
maxHealth = 15
mob_size = MOB_SIZE_SMALL
can_be_held = TRUE
density = FALSE
gold_core_spawnable = FRIENDLY_SPAWN
speak_emote = list("sniffles", "twitches")
@@ -55,6 +54,7 @@
AddElement(/datum/element/ai_retaliate)
AddElement(/datum/element/pet_bonus, "hop")
AddElement(/datum/element/animal_variety, icon_prefix, pick("brown", "black", "white"), TRUE)
AddElement(/datum/element/can_be_held)
if(prob(20)) // bunny
name = "bunny"
@@ -78,6 +78,8 @@ GLOBAL_LIST_EMPTY(raptor_population)
var/datum/raptor_inheritance/inherited_stats = null
/// Current happiness value of the raptor
var/happiness_percentage = 0
/// The ability for this raptor to be picked up and held. Defaults to FALSE as it's meant to be in lockstep with the element being added/removed.
var/could_be_held = FALSE
/mob/living/basic/raptor/Initialize(mapload, datum/raptor_color/color_type, datum/raptor_inheritance/passed_stats)
. = ..()
@@ -283,6 +285,16 @@ GLOBAL_LIST_EMPTY(raptor_population)
return pick_weight(prob_list)
/// Updates the presence of the can_be_held element based on what we want from the raptor
/mob/living/basic/raptor/proc/update_holdability(bool)
if(bool && !could_be_held)
AddElement(/datum/element/can_be_held)
could_be_held = TRUE
if(!bool && could_be_held)
RemoveElement(/datum/element/can_be_held)
could_be_held = FALSE
/mob/living/basic/raptor/proc/on_picked_up(mob/living/basic/raptor/source, mob/living/user, obj/item/mob_holder/holder)
SIGNAL_HANDLER
// Our inventory code sucks so we have to do this
@@ -364,16 +376,16 @@ GLOBAL_LIST_EMPTY(raptor_population)
base_pixel_w = initial(base_pixel_w)
mob_size = initial(mob_size)
can_be_held = initial(can_be_held)
density = initial(density)
move_resist = initial(move_resist)
can_breed = initial(can_breed)
update_holdability(initial(could_be_held))
if (new_stage == RAPTOR_ADULT)
// Adults need to be tamed with skill rather than snacks
qdel(GetComponent(/datum/component/tameable))
else // Make us teeny-tiny
can_be_held = TRUE
update_holdability(TRUE)
density = FALSE
can_breed = FALSE
move_resist = MOVE_RESIST_DEFAULT
@@ -389,7 +401,7 @@ GLOBAL_LIST_EMPTY(raptor_population)
var/obj/item/mob_holder/holder = null
if (istype(loc, /obj/item/mob_holder))
holder = loc
if (!can_be_held)
if (!could_be_held)
holder.release()
holder = null
@@ -128,7 +128,7 @@ GLOBAL_LIST_INIT(raptor_colors, init_raptor_colors())
// Purple raptors never "fully" grow up, and remain usable as backpacks
/datum/raptor_color/purple/setup_adult(mob/living/basic/raptor/raptor)
raptor.can_be_held = TRUE
raptor.update_holdability(TRUE)
raptor.density = FALSE
raptor.move_resist = MOVE_RESIST_DEFAULT
raptor.held_w_class = WEIGHT_CLASS_BULKY
@@ -24,7 +24,6 @@
response_harm_simple = "kick"
mobility_flags = MOBILITY_FLAGS_REST_CAPABLE_DEFAULT
gold_core_spawnable = FRIENDLY_SPAWN
can_be_held = TRUE
ai_controller = /datum/ai_controller/basic_controller/cat
held_state = "cat2"
attack_verb_continuous = "claws"
@@ -91,6 +90,7 @@
AddElement(/datum/element/ai_retaliate)
AddElement(/datum/element/pet_bonus, "purr", /datum/mood_event/pet_animal)
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW)
AddElement(/datum/element/can_be_held)
add_cell_sample()
add_verb(src, /mob/living/proc/toggle_resting)
add_traits(list(TRAIT_CATLIKE_GRACE, TRAIT_VENTCRAWLER_ALWAYS, TRAIT_WOUND_LICKER, TRAIT_COLORBLIND), INNATE_TRAIT)
@@ -27,7 +27,6 @@
response_harm_simple = "kick"
speak_emote = list("barks", "woofs")
faction = list(FACTION_NEUTRAL)
can_be_held = TRUE
ai_controller = /datum/ai_controller/basic_controller/dog
// The dog attack pet command can raise melee attack above 0
attack_verb_continuous = "bites"
@@ -74,6 +73,7 @@
AddElement(/datum/element/pet_bonus, "woof")
AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW)
AddElement(/datum/element/unfriend_attacker, untamed_reaction = "%SOURCE% fixes %TARGET% with a look of betrayal.")
AddElement(/datum/element/can_be_held)
var/static/list/food_types = list(
/obj/item/food/meat/slab/human/mutant/skeleton,
/obj/item/stack/sheet/bone,
+1 -1
View File
@@ -19,7 +19,6 @@
response_harm_continuous = "kicks"
response_harm_simple = "kick"
gold_core_spawnable = FRIENDLY_SPAWN
can_be_held = TRUE
held_state = "fox"
melee_damage_lower = 5
melee_damage_upper = 5
@@ -58,6 +57,7 @@
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW)
AddElement(/datum/element/tiny_mob_hunter, MOB_SIZE_SMALL)
AddElement(/datum/element/ai_retaliate)
AddElement(/datum/element/can_be_held)
/datum/ai_controller/basic_controller/fox
blackboard = list(
+1 -1
View File
@@ -10,7 +10,6 @@ GLOBAL_DATUM(cargo_sloth, /mob/living/basic/sloth)
speak_emote = list("yawns")
can_be_held = TRUE
held_state = "sloth"
response_help_continuous = "pets"
@@ -53,6 +52,7 @@ GLOBAL_DATUM(cargo_sloth, /mob/living/basic/sloth)
AddElement(/datum/element/pet_bonus, "ssmile")
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW)
AddElement(/datum/element/ai_retaliate)
AddElement(/datum/element/can_be_held)
AddComponent(/datum/component/tree_climber)
if(!mapload || !isnull(GLOB.cargo_sloth) || !is_station_level(z))
@@ -19,7 +19,6 @@
speed = 6
verb_say = "gurgles"
verb_ask = "gurgles curiously"
can_be_held = TRUE
verb_exclaim = "gurgles loudly"
verb_yell = "gurgles loudly"
worn_slot_flags = ITEM_SLOT_HEAD
@@ -28,6 +27,8 @@
ai_controller = /datum/ai_controller/basic_controller/snail
/// What do we turn into if effected by a regal rat?
var/minion_path = /mob/living/basic/snail/angry
/// Are we able to be held by a player?
var/should_be_holdable = TRUE
/mob/living/basic/snail/Initialize(mapload)
. = ..()
@@ -53,6 +54,9 @@
if (minion_path)
AddElement(/datum/element/regal_rat_minion, converted_path = minion_path, success_balloon = "gurgle", pet_commands = GLOB.regal_rat_minion_commands)
if(should_be_holdable)
AddElement(/datum/element/can_be_held)
/mob/living/basic/snail/proc/on_entered(datum/source, obj/effect/decal/cleanable/food/salt/potential_salt)
SIGNAL_HANDLER
if(istype(potential_salt))
@@ -105,7 +109,7 @@
melee_damage_lower = 5
melee_damage_upper = 8
obj_damage = 8
can_be_held = FALSE
should_be_holdable = FALSE
minion_path = null
ai_controller = /datum/ai_controller/basic_controller/snail/trash
@@ -26,7 +26,6 @@
response_harm_simple = "kick"
gold_core_spawnable = FRIENDLY_SPAWN
faction = list(FACTION_NEUTRAL)
can_be_held = FALSE
health = 100
maxHealth = 100
light_range = 1.5 // Bioluminescence!
@@ -200,7 +200,6 @@
icon_state = "maint_spider"
icon_living = "maint_spider"
icon_dead = "maint_spider_dead"
can_be_held = TRUE
mob_size = MOB_SIZE_TINY
held_w_class = WEIGHT_CLASS_TINY
worn_slot_flags = ITEM_SLOT_HEAD
@@ -234,3 +233,4 @@
AddElement(/datum/element/ai_retaliate)
AddComponent(/datum/component/obeys_commands, pet_commands)
AddElement(/datum/element/tiny_mob_hunter)
AddElement(/datum/element/can_be_held)
@@ -19,7 +19,6 @@
response_help_simple = "pet"
verb_say = "chips"
verb_ask = "chips curiously"
can_be_held = TRUE
verb_exclaim = "chips loudly"
verb_yell = "chips loudly"
faction = list(FACTION_NEUTRAL)
@@ -47,6 +46,7 @@
AddComponent(/datum/component/tameable, food_types = eatable_food, tame_chance = 70, bonus_tame_chance = 0)
ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(eatable_food))
AddElement(/datum/element/wears_collar)
AddElement(/datum/element/can_be_held)
AddComponent(/datum/component/obeys_commands, pet_commands)
if(can_breed)
add_breeding_component()
@@ -22,7 +22,6 @@
response_harm_continuous = "splats"
response_harm_simple = "splat"
can_be_held = TRUE
held_w_class = WEIGHT_CLASS_TINY
held_lh = 'icons/mob/inhands/animal_item_lefthand.dmi'
held_rh = 'icons/mob/inhands/animal_item_righthand.dmi'
@@ -35,6 +34,7 @@
. = ..()
add_traits(list(TRAIT_NODROWN, TRAIT_SWIMMER, TRAIT_VENTCRAWLER_ALWAYS), INNATE_TRAIT)
AddElement(/datum/element/swabable, CELL_LINE_TABLE_AXOLOTL, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
AddElement(/datum/element/can_be_held)
/datum/ai_controller/basic_controller/axolotl
ai_traits = PASSIVE_AI_FLAGS
@@ -10,7 +10,6 @@
health = 1
maxHealth = 1
speed = 1.25
can_be_held = TRUE
gold_core_spawnable = FRIENDLY_SPAWN
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
@@ -50,6 +49,7 @@
. = ..()
AddElement(/datum/element/death_drops, /obj/effect/decal/cleanable/insectguts)
AddElement(/datum/element/swabable, cockroach_cell_line, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 7)
AddElement(/datum/element/can_be_held)
AddComponent( \
/datum/component/squashable, \
squash_chance = 50, \
+1 -1
View File
@@ -31,7 +31,6 @@
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
gold_core_spawnable = FRIENDLY_SPAWN
can_be_held = TRUE
held_w_class = WEIGHT_CLASS_TINY
worn_slot_flags = ITEM_SLOT_HEAD
head_icon = 'icons/mob/clothing/head/pets_head.dmi'
@@ -60,6 +59,7 @@
AddElement(/datum/element/venomous, poison_type, poison_per_bite)
AddElement(/datum/element/ai_retaliate)
AddElement(/datum/element/swabable, CELL_LINE_TABLE_FROG, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
AddElement(/datum/element/can_be_held)
if (minion_type)
AddElement(/datum/element/regal_rat_minion, converted_path = minion_type, success_balloon = "ribbit", pet_commands = GLOB.regal_rat_minion_commands)
@@ -32,7 +32,6 @@
gold_core_spawnable = FRIENDLY_SPAWN
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
can_be_held = TRUE
held_w_class = WEIGHT_CLASS_TINY
held_lh = 'icons/mob/inhands/animal_item_lefthand.dmi'
held_rh = 'icons/mob/inhands/animal_item_righthand.dmi'
@@ -60,6 +59,7 @@
. = ..()
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
AddElement(/datum/element/pet_bonus, "tongue")
AddElement(/datum/element/can_be_held)
AddElement(/datum/element/basic_eating, heal_amt = 5, food_types = edibles)
ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(edibles))
@@ -16,7 +16,6 @@
maxHealth = 25
speed = 1.25
gold_core_spawnable = FRIENDLY_SPAWN
can_be_held = TRUE
worn_slot_flags = ITEM_SLOT_HEAD
verb_say = "flutters"
@@ -60,6 +59,7 @@
ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(food_types))
AddElement(/datum/element/ai_retaliate)
AddElement(/datum/element/pet_bonus, "squeak")
AddElement(/datum/element/can_be_held)
add_verb(src, /mob/living/proc/toggle_resting)
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
@@ -11,7 +11,6 @@
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
@@ -78,6 +77,7 @@
AddElement(/datum/element/connect_loc, loc_connections)
make_tameable()
AddComponent(/datum/component/swarming, 16, 16) //max_x, max_y
AddElement(/datum/element/can_be_held)
/mob/living/basic/mouse/proc/make_tameable()
if (HAS_TRAIT(src, TRAIT_TAMED))
+5 -14
View File
@@ -1984,14 +1984,11 @@ GLOBAL_LIST_EMPTY(fire_appearances)
..()
update_z(new_turf?.z)
/mob/living/mouse_drop_receive(atom/dropping, atom/user, params)
var/mob/living/U = user
if(isliving(dropping))
var/mob/living/M = dropping
if(M.can_be_held && U.pulling == M)
M.mob_try_pickup(U)//blame kevinz
return//dont open the mobs inventory if you are picking them up
return ..()
/mob/living/proc/set_name()
if(identifier == 0)
identifier = rand(1, 999)
name = "[name] ([identifier])"
real_name = name
/mob/living/proc/mob_pickup(mob/living/user)
var/obj/item/mob_holder/holder = new inhand_holder_type(get_turf(src), src, held_state, head_icon, held_lh, held_rh, worn_slot_flags)
@@ -1999,12 +1996,6 @@ GLOBAL_LIST_EMPTY(fire_appearances)
user.visible_message(span_warning("[user] scoops up [src]!"))
user.put_in_hands(holder)
/mob/living/proc/set_name()
if(identifier == 0)
identifier = rand(1, 999)
name = "[name] ([identifier])"
real_name = name
/mob/living/proc/mob_try_pickup(mob/living/user, instant=FALSE)
if(!ishuman(user) && (user.mob_size <= mob_size || user.num_hands == 0))
if (!user.num_hands)
@@ -178,8 +178,6 @@
///used for database logging
var/last_words
///whether this can be picked up and held.
var/can_be_held = FALSE
/// The w_class of the holder when held.
var/held_w_class = WEIGHT_CLASS_NORMAL
///if it can be held, can it be equipped to any slots? (think pAI's on head)
+1 -1
View File
@@ -1,5 +1,4 @@
/mob/living/silicon/pai
can_be_held = TRUE
can_buckle_to = FALSE
density = FALSE
desc = "A generic pAI hard-light holographics emitter."
@@ -203,6 +202,7 @@
/mob/living/silicon/pai/Initialize(mapload)
. = ..()
AddComponent(/datum/component/holographic_nature)
AddElement(/datum/element/can_be_held)
if(istype(loc, /obj/item/modular_computer))
give_messenger_ability()
START_PROCESSING(SSfastprocess, src)
+1
View File
@@ -1576,6 +1576,7 @@
#include "code\datums\elements\bump_click.dm"
#include "code\datums\elements\burn_when_item_ignition.dm"
#include "code\datums\elements\can_barricade.dm"
#include "code\datums\elements\can_be_held.dm"
#include "code\datums\elements\can_shatter.dm"
#include "code\datums\elements\caseless.dm"
#include "code\datums\elements\chain_lightning_attack.dm"