diff --git a/code/modules/clothing/under/accessories/accessory_vr.dm b/code/modules/clothing/under/accessories/accessory_vr.dm
index d70e7c0df6f..5a4a910e5e2 100644
--- a/code/modules/clothing/under/accessories/accessory_vr.dm
+++ b/code/modules/clothing/under/accessories/accessory_vr.dm
@@ -493,7 +493,14 @@
/obj/item/clothing/accessory/collar/shock/bluespace/relaymove(var/mob/living/user,var/direction)
return //For some reason equipping this item was triggering this proc, putting the wearer inside of the collars belly for some reason.
-/obj/item/clothing/accessory/collar/shock/bluespace/attackby(var/obj/item/device/assembly/signaler/component, mob/user as mob)
+/obj/item/clothing/accessory/collar/shock/bluespace/attackby(var/obj/item/component, mob/user as mob)
+ if (component.has_tool_quality(TOOL_WRENCH))
+ to_chat(user, "You crack the bluespace crystal [src].")
+ var/turf/T = get_turf(src)
+ new /obj/item/clothing/accessory/collar/shock/bluespace/malfunctioning(T)
+ user.drop_from_inventory(src)
+ qdel(src)
+ return
if (!istype(component,/obj/item/device/assembly/signaler))
..()
return
@@ -517,7 +524,14 @@
target_size = 1
on = 1
-/obj/item/clothing/accessory/collar/shock/bluespace/modified/attackby(var/obj/item/device/assembly/signaler/component, mob/user as mob)
+/obj/item/clothing/accessory/collar/shock/bluespace/modified/attackby(var/obj/item/component, mob/user as mob)
+ if (component.has_tool_quality(TOOL_WRENCH))
+ to_chat(user, "You crack the bluespace crystal [src], the attached signaler disconnects.")
+ var/turf/T = get_turf(src)
+ new /obj/item/clothing/accessory/collar/shock/bluespace/malfunctioning(T)
+ user.drop_from_inventory(src)
+ qdel(src)
+ return
if (!istype(component,/obj/item/device/assembly/signaler))
..()
return
@@ -625,6 +639,141 @@
s.start()
return
+//bluespace collar malfunctioning (random size)
+
+/obj/item/clothing/accessory/collar/shock/bluespace/malfunctioning
+ name = "Bluespace collar"
+ desc = "A collar that can manipulate the size of the wearer, and can be modified when unequiped. It has a crack on the crystal."
+ icon_state = "collar_size_malf"
+ item_state = "collar_size"
+ overlay_state = "collar_size"
+ target_size = 1
+ on = 1
+ var/currently_shrinking = 0
+
+/obj/item/clothing/accessory/collar/shock/bluespace/malfunctioning/attackby(var/obj/item/component, mob/user as mob)
+ if (!istype(component,/obj/item/device/assembly/signaler))
+ ..()
+ return
+ to_chat(user, "The signaler doesn't respond to the connection attempt [src].")
+ return
+
+/obj/item/clothing/accessory/collar/shock/bluespace/malfunctioning/attack_self(mob/user as mob, flag1)
+ if(!istype(user, /mob/living/carbon/human))
+ return
+ user.set_machine(src)
+ var/dat = {"
+ Frequency/Code for collar:
+ Frequency:
+ -
+ - [format_frequency(frequency)]
+ +
+ +
+
+ Code:
+ -
+ - [code]
+ +
+ +
+
+ Tag:
+ Set tag
+
+ Size:
+ Input Disabled!
+ "}
+ user << browse(dat, "window=radio")
+ onclose(user, "radio")
+ return
+
+/obj/item/clothing/accessory/collar/shock/bluespace/malfunctioning/Topic(href, href_list)
+ if(usr.stat || usr.restrained())
+ return
+ if(((istype(usr, /mob/living/carbon/human) && ((!( ticker ) || (ticker && ticker.mode != "monkey")) && usr.contents.Find(src))) || (usr.contents.Find(master) || (in_range(src, usr) && istype(loc, /turf)))))
+ usr.set_machine(src)
+ if(href_list["freq"])
+ var/new_frequency = sanitize_frequency(frequency + text2num(href_list["freq"]))
+ set_frequency(new_frequency)
+ if(href_list["tag"])
+ var/str = copytext(reject_bad_text(tgui_input_text(usr,"Tag text?","Set tag","",MAX_NAME_LEN)),1,MAX_NAME_LEN)
+ if(!str || !length(str))
+ to_chat(usr,"[name]'s tag set to be blank.")
+ name = initial(name)
+ desc = initial(desc)
+ else
+ to_chat(usr,"You set the [name]'s tag to '[str]'.")
+ name = initial(name) + " ([str])"
+ desc = initial(desc) + " The tag says \"[str]\"."
+ else
+ if(href_list["code"])
+ code += text2num(href_list["code"])
+ code = round(code)
+ code = min(100, code)
+ code = max(1, code)
+ if(!( master ))
+ if(istype(loc, /mob))
+ attack_self(loc)
+ else
+ for(var/mob/M in viewers(1, src))
+ if(M.client)
+ attack_self(M)
+ else
+ if(istype(master.loc, /mob))
+ attack_self(master.loc)
+ else
+ for(var/mob/M in viewers(1, master))
+ if(M.client)
+ attack_self(M)
+ else
+ usr << browse(null, "window=radio")
+ return
+ return
+
+/obj/item/clothing/accessory/collar/shock/bluespace/malfunctioning/receive_signal(datum/signal/signal)
+ if(!signal)
+ return
+ target_size = (rand(25,200)) /100
+ if(on)
+ var/mob/M = null
+ if(ismob(loc))
+ M = loc
+ if(ismob(loc.loc))
+ M = loc.loc // This is about as terse as I can make my solution to the whole 'collar won't work when attached as accessory' thing.
+ var/mob/living/carbon/human/H = M
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ if(!H.resizable)
+ H.visible_message("The space around [H] compresses for a moment but then nothing happens.","The space around you distorts but nothing happens to you.")
+ return
+ if (target_size < 0.25)
+ H.visible_message("The collar on [H] flickers, but fizzles out.","Your collar flickers, but is not powerful enough to shrink you that small.")
+ return
+ if(currently_shrinking == 0)
+ if(!(world.time - last_activated > 10 SECONDS))
+ to_chat(M, "\The [src] flickers. It seems to be recharging.")
+ return
+ last_activated = world.time
+ original_size = H.size_multiplier
+ currently_shrinking = 1
+ H.resize(target_size, ignore_prefs = FALSE) //In case someone else tries to put it on you.
+ H.visible_message("The space around [H] distorts as they change size!","The space around you distorts as you change size!")
+ log_admin("Admin [key_name(M)]'s size was altered by a bluespace collar.")
+ s.set_up(3, 1, M)
+ s.start()
+ else if(currently_shrinking == 1)
+ if(original_size == null)
+ H.visible_message("The space around [H] twists and turns for a moment but then nothing happens.","The space around you distorts but stay the same size.")
+ return
+ last_activated = world.time
+ H.resize(original_size, ignore_prefs = FALSE)
+ original_size = null
+ currently_shrinking = 0
+ H.visible_message("The space around [H] distorts as they return to their original size!","The space around you distorts as you return to your original size!")
+ log_admin("Admin [key_name(M)]'s size was altered by a bluespace collar.")
+ to_chat(M, "\The [src] flickers. It is now recharging and will be ready again in ten seconds.")
+ s.set_up(3, 1, M)
+ s.start()
+ return
+
//Machete Holsters
/obj/item/clothing/accessory/holster/machete
name = "machete sheath"
diff --git a/code/modules/vore/resizing/sizegun_slow_vr.dm b/code/modules/vore/resizing/sizegun_slow_vr.dm
index 648c0f91c7e..9a993e7a872 100644
--- a/code/modules/vore/resizing/sizegun_slow_vr.dm
+++ b/code/modules/vore/resizing/sizegun_slow_vr.dm
@@ -3,7 +3,7 @@
/obj/item/device/slow_sizegun
name = "gradual size gun"
- desc = "A highly advanced ray gun, designed for progressive and gradual changing of size."
+ desc = "A highly advanced ray gun, designed for progressive and gradual changing of size. Size trading can be toggled on via alt-clicking."
icon = 'icons/obj/gun_vr.dmi'
icon_state = "sizegun-old-0"
var/base_icon_state = "sizegun-old"
@@ -17,6 +17,7 @@
var/dorm_size = TRUE
var/size_increment = 0.01
var/current_target
+ var/trading = 0
/obj/item/device/slow_sizegun/update_icon()
icon_state = "[base_icon_state]-[sizeshift_mode]"
@@ -50,6 +51,9 @@
if(unresizable)
return TRUE
+ if(trading == 1 && !(user.resizable))
+ return TRUE
+
if(!(target.has_large_resize_bounds()) && (target.size_multiplier >= RESIZE_MAXIMUM) && sizeshift_mode == SIZE_GROW)
return TRUE
@@ -62,6 +66,18 @@
if(target.size_multiplier <= RESIZE_MINIMUM_DORMS && sizeshift_mode == SIZE_SHRINK)
return TRUE
+ if(trading == 1 && !(user.has_large_resize_bounds()) && (user.size_multiplier >= RESIZE_MAXIMUM) && sizeshift_mode == SIZE_GROW)
+ return TRUE
+
+ if(trading == 1 && user.size_multiplier >= RESIZE_MAXIMUM_DORMS && sizeshift_mode == SIZE_GROW)
+ return TRUE
+
+ if(trading == 1 && !(user.has_large_resize_bounds()) && (user.size_multiplier <= RESIZE_MINIMUM) && sizeshift_mode == SIZE_SHRINK)
+ return TRUE
+
+ if(trading == 1 && user.size_multiplier <= RESIZE_MINIMUM_DORMS && sizeshift_mode == SIZE_SHRINK)
+ return TRUE
+
return FALSE
/obj/item/device/slow_sizegun/afterattack(atom/target, mob/user, proximity_flag)
@@ -81,6 +97,7 @@
return
var/mob/living/L = target
+ var/mob/living/U = user
if(get_dist(target, user) > beam_range)
to_chat(user, span("warning", "You are too far away from \the [target] to affect it. Get closer."))
@@ -100,6 +117,9 @@
if(!(L.resizable))
unresizable = TRUE
+ if(trading == 1 && !(user.resizable))
+ unresizable = TRUE
+
if(unresizable)
to_chat(user, span("warning", "\the [target] is immune to resizing."))
@@ -119,14 +139,25 @@
var/active_hand = user.get_active_hand()
- while(!should_stop(target, user, active_hand))
- stoplag(3)
+ if (trading == 0)
+ while(!should_stop(target, user, active_hand))
+ stoplag(3)
- if(sizeshift_mode == SIZE_SHRINK)
- L.resize((L.size_multiplier - size_increment), uncapped = L.has_large_resize_bounds(), aura_animation = FALSE)
- else if(sizeshift_mode == SIZE_GROW)
- L.resize((L.size_multiplier + size_increment), uncapped = L.has_large_resize_bounds(), aura_animation = FALSE)
+ if(sizeshift_mode == SIZE_SHRINK)
+ L.resize((L.size_multiplier - size_increment), uncapped = L.has_large_resize_bounds(), aura_animation = FALSE)
+ else if(sizeshift_mode == SIZE_GROW)
+ L.resize((L.size_multiplier + size_increment), uncapped = L.has_large_resize_bounds(), aura_animation = FALSE)
+ if (trading == 1)
+ while(!should_stop(target, user, active_hand))
+ stoplag(3)
+
+ if(sizeshift_mode == SIZE_SHRINK)
+ L.resize((L.size_multiplier - size_increment), uncapped = L.has_large_resize_bounds(), aura_animation = FALSE)
+ U.resize((U.size_multiplier + size_increment), uncapped = U.has_large_resize_bounds(), aura_animation = FALSE)
+ else if(sizeshift_mode == SIZE_GROW)
+ L.resize((L.size_multiplier + size_increment), uncapped = L.has_large_resize_bounds(), aura_animation = FALSE)
+ U.resize((U.size_multiplier - size_increment), uncapped = U.has_large_resize_bounds(), aura_animation = FALSE)
busy = FALSE
current_target = null
@@ -219,3 +250,13 @@
/obj/item/device/slow_sizegun/proc/color_box(list/box_segments, new_color, new_time)
for(var/i in box_segments)
animate(i, color = new_color, time = new_time)
+
+//Alt click to activate size trading
+
+/obj/item/device/slow_sizegun/AltClick(mob/user)
+ if (trading == 0)
+ trading = 1
+ to_chat(user, span("notice", "\The [src] will now trade your targets size for your own."))
+ else
+ trading = 0
+ to_chat(user, span("notice", "\The [src] will no longer trade your targets size for your own."))
diff --git a/code/modules/vore/resizing/sizegun_vr.dm b/code/modules/vore/resizing/sizegun_vr.dm
index c5fc1f3648e..982d5185f98 100644
--- a/code/modules/vore/resizing/sizegun_vr.dm
+++ b/code/modules/vore/resizing/sizegun_vr.dm
@@ -26,11 +26,20 @@
/obj/item/weapon/gun/energy/sizegun/New()
..()
verbs += PROC_REF(select_size)
+ verbs += PROC_REF(spin_dial)
/obj/item/weapon/gun/energy/sizegun/attack_self(mob/user)
. = ..()
select_size()
+/obj/item/weapon/gun/energy/sizegun/proc/spin_dial()
+ set name = "Spin Size Dial"
+ set category = "Object"
+ set src in view(1)
+
+ size_set_to = (rand(25,200)) /100
+ usr.visible_message("\The [usr] spins the size dial to a random value!","You spin the dial to a random value!")
+
/obj/item/weapon/gun/energy/sizegun/consume_next_projectile()
. = ..()
var/obj/item/projectile/beam/sizelaser/G = .
diff --git a/icons/inventory/accessory/item_vr.dmi b/icons/inventory/accessory/item_vr.dmi
index de59e5e17d2..5a85d7bb33a 100644
Binary files a/icons/inventory/accessory/item_vr.dmi and b/icons/inventory/accessory/item_vr.dmi differ