diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm
index 14f0a665882..59063c214df 100644
--- a/code/game/objects/effects/effect_system/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/effects_smoke.dm
@@ -347,3 +347,14 @@
/datum/effect_system/smoke_spread/bad/green
effect_type = /obj/effect/particle_effect/smoke/bad/green
+
+/////////////////////////////////////////////
+// Quick smoke
+/////////////////////////////////////////////
+
+/obj/effect/particle_effect/smoke/quick
+ lifetime = 1
+ opaque = FALSE
+
+/datum/effect_system/smoke_spread/quick
+ effect_type = /obj/effect/particle_effect/smoke/quick
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 21e3be6408a..ae1fdf139a9 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -21,6 +21,8 @@
icon_state = "pwig"
inhand_icon_state = "pwig"
+#define RABBIT_CD_TIME 30 SECONDS
+
/obj/item/clothing/head/that
name = "top-hat"
desc = "It's an amish looking hat."
@@ -28,6 +30,37 @@
inhand_icon_state = "that"
dog_fashion = /datum/dog_fashion/head
throwforce = 1
+ /// Cooldown for how often we can pull rabbits out of here
+ COOLDOWN_DECLARE(rabbit_cooldown)
+
+/obj/item/clothing/head/that/attackby(obj/item/hitby_item, mob/user, params)
+ . = ..()
+ if(istype(hitby_item, /obj/item/gun/magic/wand))
+ abracadabra(hitby_item, user)
+
+/obj/item/clothing/head/that/proc/abracadabra(obj/item/hitby_wand, mob/magician)
+ if(!COOLDOWN_FINISHED(src, rabbit_cooldown))
+ to_chat("You can't find another rabbit in [src]! Seems another hasn't gotten lost in there yet...")
+ return
+
+ COOLDOWN_START(src, rabbit_cooldown, RABBIT_CD_TIME)
+ playsound(get_turf(src), 'sound/weapons/emitter.ogg', 70)
+ do_smoke(range=1, location=src, smoke_type=/obj/effect/particle_effect/smoke/quick)
+
+ if(prob(10))
+ magician.visible_message("[magician] taps [src] with [hitby_wand], then reaches in and pulls out a bu- wait, those are bees!", "You tap [src] with your [hitby_wand.name] and pull out... BEES!")
+ var/wait_how_many_bees_did_that_guy_pull_out_of_his_hat = rand(4, 8)
+ for(var/b in 1 to wait_how_many_bees_did_that_guy_pull_out_of_his_hat)
+ var/mob/living/simple_animal/hostile/poison/bees/barry = new(get_turf(magician))
+ barry.target = magician
+ if(prob(20))
+ barry.say(pick("BUZZ BUZZ", "PULLING A RABBIT OUT OF A HAT IS A TIRED TROPE", "I DIDN'T ASK TO BEE HERE"), forced = "bee hat")
+ else
+ magician.visible_message("[magician] taps [src] with [hitby_wand], then reaches in and pulls out a bunny! Cute!", "You tap [src] with your [hitby_wand.name] and pull out a cute bunny!")
+ var/mob/living/simple_animal/chicken/rabbit/bunbun = new(get_turf(magician))
+ bunbun.mob_try_pickup(magician, instant=TRUE)
+
+#undef RABBIT_CD_TIME
/obj/item/clothing/head/canada
name = "striped red tophat"
diff --git a/code/modules/holiday/easter.dm b/code/modules/holiday/easter.dm
index ecdd6d9a419..e2c14524ce3 100644
--- a/code/modules/holiday/easter.dm
+++ b/code/modules/holiday/easter.dm
@@ -51,6 +51,7 @@
layMessage = list("hides an egg.","scampers around suspiciously.","begins making a huge racket.","begins shuffling.")
pet_bonus = TRUE
pet_bonus_emote = "hops around happily!"
+ can_be_held = TRUE
/mob/living/simple_animal/chicken/rabbit/space
icon_prefix = "s_rabbit"
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 00816a45189..711d7095d4b 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -76,9 +76,7 @@
var/list/L
for(var/i in 1 to held_items.len)
if(!held_items[i])
- if(!L)
- L = list()
- L += i
+ LAZYADD(L, i)
return L
/mob/proc/get_held_index_of_item(obj/item/I)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 6525015e785..3f5eb79e21c 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1387,20 +1387,21 @@
name = "[name] ([numba])"
real_name = name
-/mob/living/proc/mob_try_pickup(mob/living/user)
+/mob/living/proc/mob_try_pickup(mob/living/user, instant=FALSE)
if(!ishuman(user))
return
- if(user.get_active_held_item())
+ if(!user.get_empty_held_indexes())
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]!", \
- "You start trying to scoop up [src]...", null, null, src)
- to_chat(src, "[user] starts trying to scoop you up!")
- if(!do_after(user, 20, target = src))
- return FALSE
+ if(!instant)
+ user.visible_message("[user] starts trying to scoop up [src]!", \
+ "You start trying to scoop up [src]...", null, null, src)
+ to_chat(src, "[user] starts trying to scoop you up!")
+ if(!do_after(user, 2 SECONDS, target = src))
+ return FALSE
mob_pickup(user)
return TRUE
diff --git a/code/modules/mob/living/silicon/pai/pai_shell.dm b/code/modules/mob/living/silicon/pai/pai_shell.dm
index 8c2e52109ae..0b048140e23 100644
--- a/code/modules/mob/living/silicon/pai/pai_shell.dm
+++ b/code/modules/mob/living/silicon/pai/pai_shell.dm
@@ -128,7 +128,7 @@
set_light(0)
to_chat(src, "You disable your integrated light.")
-/mob/living/silicon/pai/mob_try_pickup(mob/living/user)
+/mob/living/silicon/pai/mob_try_pickup(mob/living/user, instant=FALSE)
if(!possible_chassis[chassis])
to_chat(user, "[src]'s current form isn't able to be carried!")
return FALSE