diff --git a/code/game/objects/items/etherealdiscoball.dm b/code/game/objects/items/etherealdiscoball.dm
new file mode 100644
index 00000000000..685e83b8940
--- /dev/null
+++ b/code/game/objects/items/etherealdiscoball.dm
@@ -0,0 +1,73 @@
+/obj/item/etherealballdeployer
+ name = "Portable Ethereal Disco Ball"
+ desc = "Press the button for a deployment of slightly-unethical PARTY!"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "ethdisco"
+
+/obj/item/etherealballdeployer/attack_self(mob/living/carbon/user)
+ .=..()
+ to_chat(user, "You deploy the Ethereal Disco Ball.")
+ new /obj/structure/etherealball(user.loc)
+ qdel(src)
+
+/obj/structure/etherealball
+ name = "Ethereal Disco Ball"
+ desc = "The ethics of this discoball are questionable."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "ethdisco_head_0"
+ anchored = TRUE
+ density = TRUE
+ var/TurnedOn = FALSE
+ var/current_color
+ var/TimerID
+ var/range = 7
+ var/power = 3
+
+/obj/structure/etherealball/Initialize()
+ . = ..()
+ update_icon()
+
+/obj/structure/etherealball/attack_hand(mob/living/carbon/human/user)
+ . = ..()
+ if(TurnedOn)
+ TurnOff()
+ to_chat(user, "You turn the disco ball off!")
+ else
+ TurnOn()
+ to_chat(user, "You turn the disco ball on!")
+
+/obj/structure/etherealball/AltClick(mob/living/carbon/human/user)
+ . = ..()
+ if(anchored)
+ to_chat(user, "You unlock the disco ball.")
+ anchored = FALSE
+ else
+ to_chat(user, "You lock the disco ball.")
+ anchored = TRUE
+
+/obj/structure/etherealball/proc/TurnOn()
+ TurnedOn = TRUE //Same
+ DiscoFever()
+
+/obj/structure/etherealball/proc/TurnOff()
+ TurnedOn = FALSE
+ set_light(0)
+ remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
+ update_icon()
+ if(TimerID)
+ deltimer(TimerID)
+
+/obj/structure/etherealball/proc/DiscoFever()
+ remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
+ current_color = random_color()
+ set_light(range, power, current_color)
+ add_atom_colour("#[current_color]", FIXED_COLOUR_PRIORITY)
+ update_icon()
+ TimerID = addtimer(CALLBACK(src, .proc/DiscoFever), 5, TIMER_STOPPABLE) //Call ourselves every 0.5 seconds to change colors
+
+/obj/structure/etherealball/update_icon()
+ cut_overlays()
+ icon_state = "ethdisco_head_[TurnedOn]"
+ var/mutable_appearance/base_overlay = mutable_appearance(icon, "ethdisco_base")
+ base_overlay.appearance_flags = RESET_COLOR
+ add_overlay(base_overlay)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
index f0c1495281a..7a25e906654 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
@@ -9,3 +9,4 @@
..()
for(var/i in 1 to 10)
new /obj/item/reagent_containers/food/drinks/beer( src )
+ new /obj/item/etherealballdeployer(src)
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 41f326111b4..74110bc2d11 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 7a9a5ee22cf..7c254c51be9 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -793,6 +793,7 @@
#include "code\game\objects\items\dna_injector.dm"
#include "code\game\objects\items\documents.dm"
#include "code\game\objects\items\eightball.dm"
+#include "code\game\objects\items\etherealdiscoball.dm"
#include "code\game\objects\items\extinguisher.dm"
#include "code\game\objects\items\flamethrower.dm"
#include "code\game\objects\items\gift.dm"