diff --git a/code/modules/mob/living/inhand_holder.dm b/code/modules/mob/living/inhand_holder.dm
new file mode 100644
index 0000000000..6a2308b621
--- /dev/null
+++ b/code/modules/mob/living/inhand_holder.dm
@@ -0,0 +1,84 @@
+//Generic system for picking up mobs.
+//Currently works for head and hands.
+/obj/item/clothing/head/mob_holder
+ name = "bugged mob"
+ desc = "Yell at coderbrush."
+ icon = null
+ icon_state = ""
+ flags_1 = DROPDEL_1
+ var/mob/living/held_mob
+ var/can_head = TRUE
+ var/destroying = FALSE
+
+/obj/item/clothing/head/mob_holder/Initialize(mapload, mob/living/M, _worn_state, head_icon, lh_icon, rh_icon, _can_head = TRUE)
+ . = ..()
+ can_head = _can_head
+ if(head_icon)
+ alternate_worn_icon = head_icon
+ if(_worn_state)
+ item_state = _worn_state
+ if(lh_icon)
+ lefthand_file = lh_icon
+ if(rh_icon)
+ righthand_file = rh_icon
+ if(!can_head)
+ slot_flags = NONE
+ deposit(M)
+
+/obj/item/clothing/head/mob_holder/Destroy()
+ destroying = TRUE
+ if(held_mob)
+ release(FALSE)
+ return ..()
+
+/obj/item/clothing/head/mob_holder/proc/deposit(mob/living/L)
+ if(!istype(L))
+ return FALSE
+ L.setDir(SOUTH)
+ update_visuals(L)
+ held_mob = L
+ L.forceMove(src)
+ name = L.name
+ desc = L.desc
+ return TRUE
+
+/obj/item/clothing/head/mob_holder/proc/update_visuals(mob/living/L)
+ appearance = L.appearance
+
+/obj/item/clothing/head/mob_holder/proc/release(del_on_release = TRUE)
+ if(!held_mob)
+ if(del_on_release && !destroying)
+ qdel(src)
+ return FALSE
+ if(isliving(loc))
+ var/mob/living/L = loc
+ to_chat(L, "[held_mob] wriggles free!")
+ L.dropItemToGround(src)
+ held_mob.forceMove(get_turf(src))
+ held_mob.reset_perspective()
+ held_mob.setDir(SOUTH)
+ held_mob.visible_message("[held_mob] uncurls!")
+ held_mob = null
+ if(del_on_release && !destroying)
+ qdel(src)
+ return TRUE
+
+/obj/item/clothing/head/mob_holder/relaymove()
+ release()
+
+/obj/item/clothing/head/mob_holder/container_resist()
+ release()
+
+/obj/item/clothing/head/mob_holder/drone/deposit(mob/living/L)
+ . = ..()
+ if(!isdrone(L))
+ qdel(src)
+ name = "drone (hiding)"
+ desc = "This drone is scared and has curled up into a ball!"
+
+/obj/item/clothing/head/mob_holder/drone/update_visuals(mob/living/L)
+ var/mob/living/simple_animal/drone/D = L
+ if(!D)
+ return ..()
+ icon = 'icons/mob/drone.dmi'
+ icon_state = "[D.visualAppearence]_hat"
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 9b47a8c66b..fc9a7a5a17 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1064,3 +1064,31 @@
/mob/living/onTransitZ(old_z,new_z)
..()
update_z(new_z)
+
+/mob/living/MouseDrop(mob/over)
+ . = ..()
+ var/mob/living/user = usr
+ if(!istype(over) || !istype(user))
+ return
+ if(!over.Adjacent(src) || (user != src) || !canUseTopic(over))
+ return
+ if(can_be_held)
+ mob_try_pickup(over)
+
+/mob/living/proc/mob_pickup(mob/living/L)
+ return
+
+/mob/living/proc/mob_try_pickup(mob/living/user)
+ if(!ishuman(user))
+ return
+ if(user.get_active_held_item())
+ to_chat(user, "Your hands are full!")
+ return FALSE
+ if(buckled)
+ to_chat(user, "[src] is buckled to something!")
+ return FALSE
+ user.visible_message("[user] starts trying to scoop up [src]!")
+ if(!do_after(user, 20, target = src))
+ return FALSE
+ mob_pickup(user)
+ return TRUE
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 6990262409..904e9b9c21 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -81,4 +81,5 @@
var/list/obj/effect/proc_holder/abilities = list()
- var/registered_z
\ No newline at end of file
+ var/registered_z
+ var/can_be_held = FALSE //whether this can be picked up and held.
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 924ab615b8..91541fccf1 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -11,6 +11,7 @@
health = 500
maxHealth = 500
layer = BELOW_MOB_LAYER
+ can_be_held = TRUE
var/network = "SS13"
var/obj/machinery/camera/current = null
@@ -57,7 +58,10 @@
var/canholo = TRUE
var/obj/item/card/id/access_card = null
var/chassis = "repairbot"
- var/list/possible_chassis = list("cat", "mouse", "monkey", "corgi", "fox", "repairbot", "rabbit")
+ var/list/possible_chassis = list("cat" = TRUE, "mouse" = TRUE, "monkey" = TRUE, "corgi" = FALSE, "fox" = FALSE, "repairbot" = TRUE, "rabbit" = TRUE) //assoc value is whether it can be picked up.
+ var/static/item_head_icon = 'icons/mob/pai_item_head.dmi'
+ var/static/item_lh_icon = 'icons/mob/pai_item_lh.dmi'
+ var/static/item_rh_icon = 'icons/mob/pai_item_rh.dmi'
var/emitterhealth = 20
var/emittermaxhealth = 20
diff --git a/code/modules/mob/living/silicon/pai/pai_shell.dm b/code/modules/mob/living/silicon/pai/pai_shell.dm
index 8a3121166e..dad7d710e7 100644
--- a/code/modules/mob/living/silicon/pai/pai_shell.dm
+++ b/code/modules/mob/living/silicon/pai/pai_shell.dm
@@ -68,9 +68,12 @@
lay_down()
/mob/living/silicon/pai/proc/choose_chassis()
+ if(!isturf(loc) && loc != card)
+ to_chat(src, "You can not change your holochassis composite while not on the ground or in your card!")
+ return FALSE
var/choice = input(src, "What would you like to use for your holochassis composite?") as null|anything in possible_chassis
if(!choice)
- return 0
+ return FALSE
chassis = choice
icon_state = "[chassis]"
if(resting)
@@ -103,3 +106,16 @@
/mob/living/silicon/pai/movement_delay()
. = ..()
. += 1 //A bit slower than humans, so they're easier to smash
+
+/mob/living/silicon/pai/mob_pickup(mob/living/L)
+ var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, chassis, item_head_icon, item_lh_icon, item_rh_icon)
+ if(!L.put_in_hands(holder))
+ qdel(holder)
+ else
+ L.visible_message("[L] scoops up [src]!")
+
+/mob/living/silicon/pai/mob_try_pickup(mob/living/user)
+ if(!possible_chassis[chassis])
+ to_chat(user, "[src]'s current form isn't able to be carried!")
+ return FALSE
+ return ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index adc88c5633..4330b58411 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -32,6 +32,7 @@
var/obj/item/inventory_back
var/nofur = 0 //Corgis that have risen past the material plane of existence.
gold_core_spawnable = FRIENDLY_SPAWN
+ can_be_held = TRUE
/mob/living/simple_animal/pet/dog/pug
name = "\improper pug"
@@ -121,7 +122,12 @@
..()
update_corgi_fluff()
-
+/mob/living/simple_animal/pet/dog/corgi/mob_pickup(mob/living/L)
+ var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, "corgi", null, 'icons/mob/pets_held_lh.dmi', 'icons/mob/pets_held_rh.dmi', FALSE)
+ if(!L.put_in_hands(holder))
+ qdel(holder)
+ else
+ L.visible_message("[L] scoops up [src]!")
/mob/living/simple_animal/pet/dog/corgi/Topic(href, href_list)
if(usr.stat)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index ea159a5749..5266f44e98 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -49,6 +49,7 @@
dextrous = TRUE
dextrous_hud_type = /datum/hud/dextrous/drone
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
+ can_be_held = TRUE
var/staticChoice = "static"
var/list/staticChoices = list("static", "blank", "letter", "animal")
var/picked = FALSE //Have we picked our visual appearence (+ colour if applicable)
@@ -67,7 +68,6 @@
var/seeStatic = 1 //Whether we see static instead of mobs
var/visualAppearence = MAINTDRONE //What we appear as
var/hacked = FALSE //If we have laws to destroy the station
- var/can_be_held = TRUE //if assholes can pick us up
var/flavortext = \
"\nDO NOT INTERFERE WITH THE ROUND AS A DRONE OR YOU WILL BE DRONE BANNED\n"+\
"Drones are a ghost role that are allowed to fix the station and build things. Interfering with the round as a drone is against the rules.\n"+\
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index 20e25e3a18..0ef3250e74 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -4,8 +4,6 @@
//DRONES AS ITEMS//
///////////////////
//Drone shells
-//Drones as hats
-
//DRONE SHELL
/obj/item/drone_shell
@@ -62,45 +60,3 @@
D.admin_spawned = admin_spawned
D.key = user.key
qdel(src)
-
-
-//DRONE HOLDER
-/obj/item/clothing/head/drone_holder//Only exists in someones hand.or on their head
- name = "drone (hiding)"
- desc = "This drone is scared and has curled up into a ball."
- icon = 'icons/mob/drone.dmi'
- icon_state = "drone_maint_hat"
- var/mob/living/simple_animal/drone/drone //stored drone
-
-/obj/item/clothing/head/drone_holder/proc/uncurl()
- if(!drone)
- return
-
- if(isliving(loc))
- var/mob/living/L = loc
- to_chat(L, "[drone] is trying to escape!")
- if(!do_after(drone, 50, target = L))
- return
- L.dropItemToGround(src)
-
- contents -= drone
- drone.forceMove(drop_location())
- drone.reset_perspective()
- drone.setDir(SOUTH )//Looks better
- drone.visible_message("[drone] uncurls!")
- drone = null
- qdel(src)
-
-
-/obj/item/clothing/head/drone_holder/relaymove()
- uncurl()
-
-/obj/item/clothing/head/drone_holder/container_resist(mob/living/user)
- uncurl()
-
-
-/obj/item/clothing/head/drone_holder/proc/updateVisualAppearence(mob/living/simple_animal/drone/D)
- if(!D)
- return
- icon_state = "[D.visualAppearence]_hat"
- . = icon_state
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index df67c720b4..6d87563ae9 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -29,7 +29,6 @@
if("Nothing")
return
-
/mob/living/simple_animal/drone/attack_hand(mob/user)
if(ishuman(user))
if(stat == DEAD || status_flags & GODMODE || !can_be_held)
@@ -49,11 +48,8 @@
return
to_chat(user, "You pick [src] up.")
drop_all_held_items()
- var/obj/item/clothing/head/drone_holder/DH = new /obj/item/clothing/head/drone_holder(src)
- DH.updateVisualAppearence(src)
- DH.drone = src
+ var/obj/item/clothing/head/mob_holder/drone/DH = new(get_turf(src), src)
user.put_in_hands(DH)
- forceMove(DH)
/mob/living/simple_animal/drone/proc/try_reactivate(mob/living/user)
var/mob/dead/observer/G = get_ghost()
diff --git a/icons/mob/monkey_held.dmi b/icons/mob/monkey_held.dmi
new file mode 100644
index 0000000000..6a9eb8aac7
Binary files /dev/null and b/icons/mob/monkey_held.dmi differ
diff --git a/icons/mob/mouse_held.dmi b/icons/mob/mouse_held.dmi
new file mode 100644
index 0000000000..92a8c03bfb
Binary files /dev/null and b/icons/mob/mouse_held.dmi differ
diff --git a/icons/mob/pai_item_head.dmi b/icons/mob/pai_item_head.dmi
new file mode 100644
index 0000000000..2803e06f20
Binary files /dev/null and b/icons/mob/pai_item_head.dmi differ
diff --git a/icons/mob/pai_item_lh.dmi b/icons/mob/pai_item_lh.dmi
new file mode 100644
index 0000000000..5f825053f2
Binary files /dev/null and b/icons/mob/pai_item_lh.dmi differ
diff --git a/icons/mob/pai_item_rh.dmi b/icons/mob/pai_item_rh.dmi
new file mode 100644
index 0000000000..7e0919afbd
Binary files /dev/null and b/icons/mob/pai_item_rh.dmi differ
diff --git a/icons/mob/pets_held_lh.dmi b/icons/mob/pets_held_lh.dmi
new file mode 100644
index 0000000000..6b2db6e9c2
Binary files /dev/null and b/icons/mob/pets_held_lh.dmi differ
diff --git a/icons/mob/pets_held_rh.dmi b/icons/mob/pets_held_rh.dmi
new file mode 100644
index 0000000000..55246b7e15
Binary files /dev/null and b/icons/mob/pets_held_rh.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 60c6f1abcc..bafb0406ee 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1734,6 +1734,7 @@
#include "code\modules\mob\living\damage_procs.dm"
#include "code\modules\mob\living\death.dm"
#include "code\modules\mob\living\emote.dm"
+#include "code\modules\mob\living\inhand_holder.dm"
#include "code\modules\mob\living\life.dm"
#include "code\modules\mob\living\living.dm"
#include "code\modules\mob\living\living_defense.dm"