diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm
index 44c5315dbf4..9f07ed53117 100644
--- a/code/__HELPERS/matrices.dm
+++ b/code/__HELPERS/matrices.dm
@@ -18,7 +18,7 @@
speed /= segments
- animate(src, transform = matrices[1], time = speed, loops)
+ animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
diff --git a/code/game/objects/effects/countdown.dm b/code/game/objects/effects/countdown.dm
index eea6b6ba39f..db5414e33d3 100644
--- a/code/game/objects/effects/countdown.dm
+++ b/code/game/objects/effects/countdown.dm
@@ -63,6 +63,12 @@
/obj/effect/countdown/ex_act(severity, target) //immune to explosions
return
+/obj/effect/countdown/singularity_pull()
+ return
+
+/obj/effect/countdown/singularity_act()
+ return
+
/obj/effect/countdown/syndicatebomb
name = "syndicate bomb countdown"
@@ -154,8 +160,14 @@
var/time_left = max(0, (A.death_time - world.time) / 10)
return round(time_left)
-/obj/effect/countdown/singularity_pull()
- return
+/obj/effect/countdown/hourglass
+ name = "hourglass countdown"
+
+/obj/effect/countdown/hourglass/get_value()
+ var/obj/item/hourglass/H = attached_to
+ if(!istype(H))
+ return
+ else
+ var/time_left = max(0, (H.finish_time - world.time) / 10)
+ return round(time_left)
-/obj/effect/countdown/singularity_act()
- return
diff --git a/code/game/objects/items/hourglass.dm b/code/game/objects/items/hourglass.dm
new file mode 100644
index 00000000000..2c5c69eb170
--- /dev/null
+++ b/code/game/objects/items/hourglass.dm
@@ -0,0 +1,82 @@
+#define HOURGLASS_STATES 7 //Remember to update if you change the sprite
+
+/obj/item/hourglass
+ name = "hourglass"
+ desc = "Nanotrasen patented gravity invariant hourglass. Guaranteed to flow perfectly under any conditions."
+ var/obj/effect/countdown/hourglass/countdown
+ var/time = 1 MINUTES
+ var/finish_time //So countdown doesn't need to fiddle with timers
+ var/timing_id //if present we're timing
+ var/hand_activated = TRUE
+ icon = 'icons/obj/hourglass.dmi'
+ icon_state = "hourglass_idle"
+
+/obj/item/hourglass/Initialize(mapload)
+ . = ..()
+ countdown = new(src)
+
+/obj/item/hourglass/attack_self(mob/user)
+ . = ..()
+ if(hand_activated)
+ toggle(user)
+
+/obj/item/hourglass/proc/toggle(mob/user)
+ if(!timing_id)
+ to_chat(user,"You flip the [src]")
+ start()
+ flick("hourglass_flip",src)
+ else
+ to_chat(user,"You stop the [src].") //Sand magically flows back because that's more convinient to use.
+ stop()
+
+/obj/item/hourglass/update_icon()
+ if(timing_id)
+ icon_state = "hourglass_active"
+ else
+ icon_state = "hourglass_idle"
+
+/obj/item/hourglass/proc/start()
+ finish_time = world.time + time
+ timing_id = addtimer(CALLBACK(src, .proc/finish), time, TIMER_STOPPABLE)
+ countdown.start()
+ timing_animation()
+
+/obj/item/hourglass/proc/timing_animation()
+ var/step_time = time / HOURGLASS_STATES
+ animate(src, time = step_time, icon_state = "hourglass_1")
+ for(var/i in 2 to HOURGLASS_STATES)
+ animate(time = step_time, icon_state = "hourglass_[i]")
+
+/obj/item/hourglass/proc/stop()
+ if(timing_id)
+ deltimer(timing_id)
+ timing_id = null
+ countdown.stop()
+ finish_time = null
+ animate(src)
+ update_icon()
+
+/obj/item/hourglass/proc/finish()
+ visible_message("[src] stops.")
+ stop()
+
+/obj/item/hourglass/Destroy()
+ QDEL_NULL(countdown)
+ . = ..()
+
+//Admin events zone.
+/obj/item/hourglass/admin
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ anchored = TRUE
+ hand_activated = FALSE
+
+/obj/item/hourglass/admin/attack_hand(mob/user)
+ . = ..()
+ if(user.client && user.client.holder)
+ toggle(user)
+
+/obj/item/hourglass/admin/attack_ghost(mob/user)
+ if(user.client && user.client.holder)
+ toggle(user)
+
+#undef HOURGLASS_STATES
\ No newline at end of file
diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm
index f4f1b419f91..1f5eca4cb88 100644
--- a/code/modules/vending/games.dm
+++ b/code/modules/vending/games.dm
@@ -6,7 +6,8 @@
products = list(/obj/item/toy/cards/deck = 5,
/obj/item/storage/pill_bottle/dice = 10,
/obj/item/toy/cards/deck/cas = 3,
- /obj/item/toy/cards/deck/cas/black = 3)
+ /obj/item/toy/cards/deck/cas/black = 3,
+ /obj/item/hourglass = 2)
contraband = list(/obj/item/dice/fudge = 9)
refill_canister = /obj/item/vending_refill/games
default_price = 10
diff --git a/icons/obj/hourglass.dmi b/icons/obj/hourglass.dmi
new file mode 100644
index 00000000000..537079f1409
Binary files /dev/null and b/icons/obj/hourglass.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 6028a439c9c..e222f31e259 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -836,6 +836,7 @@
#include "code\game\objects\items\holosign_creator.dm"
#include "code\game\objects\items\holy_weapons.dm"
#include "code\game\objects\items\hot_potato.dm"
+#include "code\game\objects\items\hourglass.dm"
#include "code\game\objects\items\inducer.dm"
#include "code\game\objects\items\kitchen.dm"
#include "code\game\objects\items\latexballoon.dm"