diff --git a/_maps/fluffy_frontier/templates/reebe.dmm b/_maps/fluffy_frontier/templates/reebe.dmm
new file mode 100644
index 00000000000..5988b75e04e
--- /dev/null
+++ b/_maps/fluffy_frontier/templates/reebe.dmm
@@ -0,0 +1,10766 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"al" = (
+/obj/machinery/telecomms/relay/preset/reebe,
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"bJ" = (
+/obj/machinery/computer/camera_advanced/ratvar{
+ dir = 4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"bN" = (
+/obj/structure/table/bronze,
+/obj/item/clockwork/weapon/brass_sword{
+ pixel_x = -4;
+ pixel_y = 4
+ },
+/obj/item/clockwork/weapon/brass_sword,
+/obj/item/clockwork/weapon/brass_sword{
+ pixel_x = 4;
+ pixel_y = -4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"cg" = (
+/obj/machinery/door/airlock/bronze/clock/glass,
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"cF" = (
+/obj/structure/table/bronze,
+/obj/item/clockwork/replica_fabricator,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"dm" = (
+/obj/structure/chair/bronze{
+ dir = 4
+ },
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"gj" = (
+/obj/structure/table/bronze,
+/obj/item/toy/plush/ratplush,
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"gu" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/suit/clockwork{
+ pixel_x = 4;
+ pixel_y = 4
+ },
+/obj/item/clothing/suit/clockwork,
+/obj/item/clothing/suit/clockwork{
+ pixel_x = -4;
+ pixel_y = -4
+ },
+/obj/item/clothing/head/helmet/clockwork{
+ pixel_x = 4;
+ pixel_y = 4
+ },
+/obj/item/clothing/head/helmet/clockwork,
+/obj/item/clothing/head/helmet/clockwork{
+ pixel_x = -4;
+ pixel_y = -4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"gL" = (
+/obj/structure/table/bronze,
+/obj/effect/mob_spawn/ghost_role/drone/cogscarab,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"hu" = (
+/obj/structure/chair/bronze{
+ dir = 8
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"in" = (
+/obj/structure/table/optable,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"iJ" = (
+/obj/effect/landmark/abscond_marker,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"jN" = (
+/obj/structure/table/bronze,
+/obj/item/clockwork/integration_cog{
+ pixel_x = 4;
+ pixel_y = 4
+ },
+/obj/item/clockwork/integration_cog,
+/obj/item/clockwork/integration_cog{
+ pixel_x = -4;
+ pixel_y = -4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"lj" = (
+/obj/effect/spawner/structure/window/clockwork,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"mg" = (
+/obj/structure/table/bronze,
+/obj/item/clockwork/clockwork_slab,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"mL" = (
+/turf/open/indestructible/reebe_void,
+/area/ruin/powered/reebe/space)
+"nw" = (
+/obj/structure/chair/bronze{
+ dir = 4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"ok" = (
+/obj/structure/fans/tiny/invisible,
+/turf/open/indestructible/reebe_void/void_edge,
+/area/ruin/powered/reebe/space)
+"oH" = (
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"pc" = (
+/obj/structure/destructible/clockwork/the_ark,
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"qI" = (
+/turf/open/indestructible/reebe_void/spawning,
+/area/ruin/powered/reebe/space)
+"sa" = (
+/obj/machinery/computer/operating/clockwork{
+ dir = 1
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"sN" = (
+/obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"tr" = (
+/turf/closed/wall/clockwork/reebe,
+/area/ruin/powered/reebe/city)
+"tU" = (
+/obj/structure/chair/bronze{
+ dir = 1
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"uF" = (
+/obj/structure/table/bronze,
+/obj/item/stack/sheet/bronze/thirty,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"ve" = (
+/obj/effect/servant_blocker,
+/obj/structure/lattice/catwalk/clockwork,
+/turf/open/indestructible/reebe_void/walkable,
+/area/ruin/powered/reebe/city)
+"zN" = (
+/obj/structure/table/bronze,
+/obj/item/clockwork/weapon/brass_spear{
+ pixel_y = 4;
+ pixel_x = -4
+ },
+/obj/item/clockwork/weapon/brass_spear,
+/obj/item/clockwork/weapon/brass_spear{
+ pixel_y = -4;
+ pixel_x = 4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"zR" = (
+/obj/structure/table/bronze,
+/obj/item/storage/medkit/advanced,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"Ao" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/glasses/clockwork/wraith_spectacles,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"AF" = (
+/obj/machinery/door/airlock/bronze/clock,
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"Bv" = (
+/obj/machinery/computer/camera_advanced/ratvar,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"BT" = (
+/obj/effect/landmark/late_cog_portals,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"CE" = (
+/obj/structure/fluff/clockwork/alloy_shards,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"En" = (
+/obj/structure/table/bronze,
+/obj/item/storage/belt/utility/clock{
+ pixel_x = 4;
+ pixel_y = 4
+ },
+/obj/item/storage/belt/utility/clock,
+/obj/item/storage/belt/utility/clock{
+ pixel_x = -4;
+ pixel_y = -4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"EK" = (
+/obj/structure/destructible/clockwork/eminence_beacon,
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"Fq" = (
+/obj/structure/table/bronze,
+/obj/item/radio/intercom/reebe,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"FD" = (
+/obj/effect/landmark/abscond_marker,
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"FK" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/suit/clockwork/cloak,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"FY" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/glasses/clockwork/judicial_visor,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"Gg" = (
+/obj/machinery/door/airlock/bronze/clock/glass,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"HT" = (
+/obj/structure/table/bronze,
+/obj/item/storage/medkit/regular,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"IX" = (
+/obj/structure/fluff/clockwork/alloy_shards/large,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"Kr" = (
+/obj/structure/table/bronze,
+/obj/item/clockwork/weapon/brass_battlehammer{
+ pixel_x = -4;
+ pixel_y = 4
+ },
+/obj/item/clockwork/weapon/brass_battlehammer,
+/obj/item/clockwork/weapon/brass_battlehammer{
+ pixel_x = 4;
+ pixel_y = -4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"Lo" = (
+/obj/machinery/sleeper/clockwork{
+ dir = 8
+ },
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"Mf" = (
+/obj/structure/table/bronze,
+/obj/item/storage/toolbox/brass/surgery,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"Ni" = (
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+"OA" = (
+/obj/structure/fluff/clockwork/alloy_shards/medium_gearbit,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"OL" = (
+/obj/structure/destructible/clockwork/gear_base/stargazer,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"OQ" = (
+/obj/machinery/computer/camera_advanced/ratvar{
+ dir = 8
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"OX" = (
+/obj/machinery/sleeper/clockwork{
+ dir = 8
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"QA" = (
+/obj/structure/fluff/clockwork/alloy_shards/small,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"Ro" = (
+/obj/structure/destructible/clockwork/sigil/transmission,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"Rs" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/gloves/clockwork,
+/obj/item/clothing/gloves/clockwork,
+/obj/item/clothing/gloves/clockwork,
+/obj/item/clothing/gloves/clockwork,
+/obj/item/clothing/gloves/clockwork,
+/obj/item/gun/ballistic/bow/clockwork,
+/obj/item/gun/ballistic/bow/clockwork,
+/obj/item/gun/ballistic/bow/clockwork,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"To" = (
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"TL" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/suit/clockwork/speed,
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"Vi" = (
+/obj/structure/fluff/clockwork/alloy_shards/medium,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"VS" = (
+/turf/open/indestructible/reebe_void/spawning/lattices,
+/area/ruin/powered/reebe/space)
+"WL" = (
+/obj/structure/chair/bronze{
+ dir = 8
+ },
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"Xr" = (
+/obj/structure/chair/bronze{
+ dir = 1
+ },
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"XZ" = (
+/obj/machinery/door/airlock/bronze/clock,
+/turf/open/indestructible/reebe_flooring,
+/area/ruin/powered/reebe/city)
+"ZE" = (
+/obj/structure/table/bronze,
+/obj/item/clockwork/replica_fabricator{
+ pixel_x = 4;
+ pixel_y = 4
+ },
+/obj/item/clockwork/replica_fabricator,
+/obj/item/clockwork/replica_fabricator{
+ pixel_x = -4;
+ pixel_y = -4
+ },
+/turf/open/indestructible/reebe_flooring/flat,
+/area/ruin/powered/reebe/city)
+"ZW" = (
+/obj/structure/fluff/clockwork/alloy_shards,
+/turf/open/indestructible/reebe_flooring/filled,
+/area/ruin/powered/reebe/city)
+
+(1,1,1) = {"
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+"}
+(2,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(3,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(4,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(5,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(6,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(7,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(8,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(9,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(10,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(11,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(12,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(13,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(14,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(15,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(16,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+tr
+tr
+tr
+lj
+lj
+lj
+tr
+tr
+tr
+tr
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(17,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(18,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+BT
+oH
+oH
+oH
+BT
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(19,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+BT
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(20,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+BT
+oH
+oH
+oH
+oH
+oH
+BT
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(21,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+lj
+lj
+tr
+tr
+tr
+XZ
+tr
+tr
+tr
+lj
+lj
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(22,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(23,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(24,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+tr
+lj
+lj
+lj
+tr
+tr
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+tr
+lj
+lj
+lj
+tr
+tr
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(25,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(26,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(27,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+BT
+oH
+BT
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+qI
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+BT
+BT
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(28,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+oH
+BT
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+VS
+VS
+VS
+tr
+lj
+lj
+Gg
+lj
+lj
+tr
+VS
+VS
+VS
+qI
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(29,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+BT
+oH
+oH
+oH
+tr
+oH
+tr
+VS
+VS
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+tr
+lj
+lj
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+lj
+lj
+tr
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+VS
+VS
+tr
+oH
+tr
+oH
+BT
+oH
+BT
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(30,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+BT
+oH
+oH
+oH
+oH
+XZ
+oH
+oH
+oH
+tr
+VS
+qI
+qI
+qI
+qI
+qI
+qI
+tr
+lj
+lj
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+lj
+lj
+tr
+qI
+qI
+qI
+qI
+qI
+qI
+VS
+tr
+oH
+oH
+oH
+XZ
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(31,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+qI
+qI
+qI
+qI
+tr
+tr
+tr
+oH
+oH
+oH
+oH
+OA
+oH
+oH
+oH
+oH
+oH
+oH
+QA
+oH
+oH
+oH
+oH
+oH
+tr
+tr
+tr
+qI
+qI
+qI
+qI
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+BT
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(32,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+lj
+lj
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+qI
+tr
+tr
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+tr
+tr
+qI
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+lj
+lj
+lj
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(33,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+ve
+ve
+oH
+oH
+oH
+ve
+ve
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(34,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+QA
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(35,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+Gg
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+Vi
+oH
+oH
+Gg
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(36,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+tr
+oH
+lj
+oH
+OA
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+IX
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+tr
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(37,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+tr
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+tr
+qI
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(38,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+tr
+tr
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+CE
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+Ni
+Ni
+Ni
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+tr
+tr
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(39,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+tr
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+Ni
+oH
+oH
+oH
+oH
+oH
+ZW
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+IX
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+tr
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(40,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+tr
+tr
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+tr
+tr
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(41,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+tr
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+tr
+qI
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(42,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+qI
+qI
+qI
+tr
+tr
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+OA
+oH
+oH
+oH
+Ni
+oH
+Ni
+tr
+tr
+oH
+tr
+tr
+gj
+tr
+tr
+oH
+tr
+tr
+Ni
+oH
+Ni
+oH
+oH
+Vi
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+tr
+tr
+qI
+qI
+qI
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(43,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+qI
+qI
+qI
+lj
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+Ni
+AF
+Ni
+To
+tr
+Rs
+Ao
+To
+TL
+gu
+tr
+To
+Ni
+AF
+Ni
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+lj
+qI
+qI
+qI
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(44,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+qI
+qI
+qI
+lj
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+Vi
+oH
+Ni
+oH
+Ni
+lj
+Ni
+oH
+To
+tr
+FY
+oH
+oH
+oH
+FK
+tr
+To
+oH
+Ni
+lj
+Ni
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+QA
+oH
+lj
+qI
+qI
+qI
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(45,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+lj
+lj
+tr
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+tr
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+Ni
+AF
+Ni
+To
+oH
+Ni
+cg
+Ni
+oH
+OL
+oH
+Ni
+cg
+Ni
+oH
+To
+Ni
+AF
+Ni
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+tr
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+tr
+lj
+lj
+tr
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(46,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+tr
+To
+oH
+oH
+oH
+uF
+tr
+Kr
+oH
+oH
+oH
+ZE
+tr
+mg
+oH
+oH
+oH
+To
+tr
+oH
+Ni
+oH
+CE
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(47,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+tr
+To
+To
+Ni
+mg
+gL
+tr
+zN
+bN
+Ni
+jN
+En
+tr
+cF
+uF
+Ni
+To
+To
+tr
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(48,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+BT
+oH
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+tr
+tr
+cg
+tr
+tr
+tr
+tr
+lj
+cg
+lj
+tr
+tr
+tr
+tr
+cg
+tr
+tr
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+oH
+oH
+oH
+BT
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(49,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+BT
+oH
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+tr
+Bv
+tU
+Ni
+bJ
+bJ
+tr
+iJ
+oH
+FD
+oH
+iJ
+tr
+Fq
+Fq
+Ni
+Fq
+Fq
+tr
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+BT
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(50,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+tr
+Bv
+Xr
+oH
+WL
+hu
+lj
+oH
+To
+To
+To
+oH
+lj
+hu
+WL
+oH
+WL
+hu
+tr
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(51,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+XZ
+oH
+oH
+oH
+oH
+oH
+oH
+Gg
+oH
+oH
+oH
+ve
+oH
+oH
+IX
+oH
+oH
+Ni
+oH
+oH
+tr
+EK
+To
+oH
+To
+oH
+Ni
+cg
+FD
+To
+pc
+To
+FD
+cg
+Ni
+Ro
+sN
+oH
+To
+al
+tr
+oH
+oH
+Ni
+oH
+oH
+oH
+CE
+oH
+ve
+oH
+oH
+oH
+Gg
+oH
+oH
+oH
+oH
+oH
+oH
+XZ
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(52,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+BT
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+tr
+Bv
+Xr
+oH
+dm
+nw
+lj
+oH
+To
+To
+To
+oH
+lj
+nw
+dm
+oH
+dm
+nw
+tr
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+BT
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(53,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+BT
+oH
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+Ni
+oH
+OA
+oH
+tr
+Bv
+tU
+Ni
+OQ
+OQ
+tr
+iJ
+oH
+FD
+oH
+iJ
+tr
+Fq
+Fq
+Ni
+Fq
+Fq
+tr
+oH
+oH
+oH
+Ni
+oH
+oH
+Vi
+oH
+ve
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(54,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+tr
+tr
+cg
+tr
+tr
+tr
+tr
+lj
+cg
+lj
+tr
+tr
+tr
+tr
+cg
+tr
+tr
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+tr
+oH
+BT
+BT
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(55,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+BT
+oH
+lj
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+tr
+To
+To
+Ni
+uF
+cF
+tr
+zR
+Mf
+Ni
+To
+in
+tr
+gL
+mg
+Ni
+To
+To
+tr
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(56,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+tr
+To
+oH
+oH
+oH
+mg
+tr
+HT
+oH
+oH
+oH
+sa
+tr
+uF
+oH
+oH
+oH
+Ni
+tr
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(57,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+lj
+lj
+tr
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+tr
+oH
+oH
+oH
+ve
+oH
+QA
+QA
+oH
+oH
+Ni
+oH
+Ni
+AF
+Ni
+To
+oH
+Ni
+cg
+Ni
+oH
+To
+oH
+Ni
+cg
+Ni
+oH
+To
+Ni
+AF
+Ni
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+tr
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+tr
+lj
+lj
+tr
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(58,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+qI
+qI
+qI
+lj
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+Ni
+lj
+Ni
+oH
+To
+tr
+To
+oH
+oH
+oH
+To
+tr
+To
+oH
+Ni
+lj
+Ni
+oH
+Ni
+oH
+oH
+oH
+IX
+oH
+oH
+ve
+oH
+oH
+oH
+lj
+qI
+qI
+qI
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(59,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+qI
+qI
+qI
+lj
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+Ni
+AF
+Ni
+To
+tr
+OX
+OX
+To
+OX
+OX
+tr
+To
+Ni
+AF
+Ni
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+lj
+qI
+qI
+qI
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(60,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+qI
+qI
+qI
+tr
+tr
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+Ni
+tr
+tr
+oH
+tr
+tr
+Lo
+tr
+tr
+oH
+tr
+tr
+Ni
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+tr
+tr
+qI
+qI
+qI
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(61,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+tr
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+CE
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+tr
+qI
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(62,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+tr
+tr
+oH
+Vi
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+Ni
+Vi
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+tr
+tr
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(63,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+tr
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+Ni
+oH
+oH
+OA
+oH
+oH
+Ni
+Ni
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+tr
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(64,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+tr
+tr
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+Ni
+Ni
+Ni
+Ni
+Ni
+oH
+oH
+IX
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+tr
+tr
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(65,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+tr
+oH
+oH
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+QA
+oH
+oH
+oH
+ve
+oH
+oH
+oH
+oH
+oH
+tr
+qI
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(66,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+tr
+oH
+lj
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+QA
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+Vi
+oH
+oH
+lj
+oH
+tr
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(67,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+Gg
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+OA
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+Gg
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(68,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+QA
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(69,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+ve
+ve
+oH
+oH
+oH
+ve
+ve
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(70,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+lj
+lj
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+qI
+tr
+tr
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+ve
+ve
+ve
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+tr
+tr
+qI
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+lj
+lj
+lj
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(71,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+qI
+qI
+qI
+qI
+tr
+tr
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+tr
+tr
+qI
+qI
+qI
+qI
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(72,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+BT
+oH
+oH
+oH
+XZ
+oH
+oH
+oH
+tr
+VS
+qI
+qI
+qI
+qI
+qI
+qI
+tr
+lj
+lj
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+lj
+lj
+tr
+qI
+qI
+qI
+qI
+qI
+qI
+VS
+tr
+oH
+oH
+oH
+XZ
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(73,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+oH
+BT
+tr
+oH
+tr
+VS
+VS
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+tr
+lj
+lj
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+lj
+lj
+tr
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+qI
+VS
+VS
+tr
+oH
+tr
+oH
+oH
+oH
+BT
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(74,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+BT
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+VS
+VS
+VS
+tr
+lj
+lj
+Gg
+lj
+lj
+tr
+VS
+VS
+VS
+qI
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+BT
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(75,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+BT
+oH
+oH
+oH
+BT
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+qI
+qI
+qI
+qI
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+qI
+qI
+qI
+qI
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+BT
+oH
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(76,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+BT
+oH
+BT
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(77,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(78,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+tr
+lj
+lj
+lj
+tr
+tr
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+tr
+lj
+lj
+lj
+tr
+tr
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(79,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(80,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(81,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+lj
+lj
+tr
+tr
+tr
+XZ
+tr
+tr
+tr
+lj
+lj
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(82,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(83,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+BT
+oH
+oH
+oH
+BT
+oH
+BT
+oH
+oH
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(84,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+lj
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+BT
+oH
+lj
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(85,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+oH
+oH
+oH
+BT
+oH
+oH
+oH
+oH
+oH
+oH
+oH
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(86,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+tr
+tr
+tr
+tr
+tr
+lj
+lj
+lj
+tr
+tr
+tr
+tr
+tr
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(87,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(88,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(89,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+VS
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(90,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(91,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(92,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(93,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(94,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(95,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(96,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(97,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(98,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(99,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(100,1,1) = {"
+ok
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+mL
+ok
+"}
+(101,1,1) = {"
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+"}
diff --git a/code/__DEFINES/~ff_defines/clockwork.dm b/code/__DEFINES/~ff_defines/clockwork.dm
new file mode 100644
index 00000000000..51a630c4cb8
--- /dev/null
+++ b/code/__DEFINES/~ff_defines/clockwork.dm
@@ -0,0 +1,119 @@
+///check if a z level is reebe
+#define is_reebe_level(z) SSmapping.level_trait(z, ZTRAIT_REEBE)
+/// is something a cogscarab
+#define iscogscarab(checked) (istype(checked, /mob/living/basic/drone/cogscarab))
+/// is something an eminence
+#define iseminence(checked) (istype(checked, /mob/living/eminence))
+/// is something a clockgolem
+#define isclockgolem(A) (is_species(A, /datum/species/clockwork_golem))
+
+#define is_safe_level(z) SSmapping.level_trait(z, ZTRAIT_FORCED_SAFETY)
+///Set weakref_var to null if it fails to give a resolve() value, resolver should be set to the var looking to resolve the weakref
+#define WEAKREF_NULL_IF_UNRESOLVED(weakref_var, resolver) weakref_var?.resolve();\
+ if(!##resolver) { \
+ ##weakref_var = null;\
+ }
+#define IS_SAFE_NUM(a) IS_FINITE(a)
+// traits
+// boolean - marks a level as having that property if present
+#define ZTRAIT_REEBE "Reebe"
+/// Marks a level as being "safe", even if it is a station z level.
+/// Nukes will not kill players on such levels.
+#define ZTRAIT_FORCED_SAFETY "Forced Safety"
+///List of ztraits the reebe Z level has
+#define ZTRAITS_REEBE list(ZTRAIT_REEBE = TRUE, \
+ ZTRAIT_NOPHASE = TRUE, \
+ ZTRAIT_BOMBCAP_MULTIPLIER = 0.5, \
+ ZTRAIT_RESERVED = TRUE, \
+ ZTRAIT_BASETURF = /turf/open/indestructible/reebe_flooring)
+//clockwork wall deconstruction
+#define COVER_COG_REMOVED 1
+#define TRANSMISSION_COGS_REMOVED 2
+#define GEARS_UNBOLTED 3
+#define INNER_PANEL_REMOVED 4
+#define GEARS_UNWOUND 5
+/// maximum amount of cogscarabs the clock cult can have
+#define MAXIMUM_COGSCARABS 6
+
+#define CLOCK_PASSIVE_POWER_PER_COG 3
+
+#define CLOCK_MAX_POWER_PER_COG STANDARD_CELL_CHARGE * 0.05
+
+#define MAX_CLOCK_VITALITY 400
+/// Clockwork Golem Species
+#define SPECIES_GOLEM_CLOCKWORK "clockgolem"
+///base state the ark is created in, any state besides this will be a hostile environment
+#define ARK_STATE_BASE 0
+///state for the grace period after the cult has reached its member count max and have enough activing anchoring crystals to summon
+#define ARK_STATE_CHARGING 1
+///state for after the cult has been annouced and are preparing for the portals to open
+#define ARK_STATE_GRACE 2
+///state for the first half of the assault
+#define ARK_STATE_ACTIVE 3
+///state for the halfway point of ark activation
+#define ARK_STATE_SUMMONING 4
+///the ark has either finished opening or been destroyed in this state
+#define ARK_STATE_FINAL 5
+
+///max damage taken per hit by "important" clock structures
+#define MAX_IMPORTANT_CLOCK_DAMAGE 30
+
+#define CHANNEL_SOUND_EFFECTS 1010
+///how many anchoring crystals need to be active before the ark can open
+#define ANCHORING_CRYSTALS_TO_SUMMON 2
+
+///the map path of the reebe map
+#define REEBE_MAP_PATH "_maps/fluffy_frontier/templates/reebe.dmm"
+
+///how long in seconds do anchoring crystals take to charge after being placed, 6 minutes
+#define ANCHORING_CRYSTAL_CHARGE_DURATION 360 SECONDS
+
+///how long between uses of the anchoring crystal scripture, also how long the hostile environment lasts if the crystal is not destroyed
+#define ANCHORING_CRYSTAL_COOLDOWN ANCHORING_CRYSTAL_CHARGE_DURATION + 1 MINUTES
+
+///up to how many tiles away will the ark stop certain things from breaking turfs
+#define ARK_TURF_DESTRUCTION_BLOCK_RANGE 10
+
+///how many clockwork airlocks is the cult allowed to create on reebe
+#define MAXIMUM_REEBE_AIRLOCKS 50
+
+///called when /datum/element/turf_checker detects a new state on constant checking (new_state) TRUE for a valid turf FALSE for an invalid
+#define COMSIG_TURF_CHECKER_UPDATE_STATE "turf_checker_update_state"
+#define COMPONENT_CHECKER_VALID_TURF (1<<0)
+#define COMPONENT_CHECKER_INVALID_TURF (2<<0)
+/// from base of atom/ratvar_act()
+#define COMSIG_ATOM_RATVAR_ACT "atom_ratvar_act"
+
+/// from base of atom/eminence_act() : (mob/living/eminence/user)
+#define COMSIG_ATOM_EMINENCE_ACT "atom_eminence_act"
+/// Used to externally force /datum/element/light_eater to handle eating a light without physical contact. Used by nightmares. (food, eater, silent)
+#define COMSIG_LIGHT_EATER_EAT "light_eater_eat"
+
+/// the comsig for clockwork items checking turf
+#define COMSIG_CHECK_TURF_CLOCKWORK "check_turf_clockwork"
+///sent by the ark SS whenever an anchoring crystal charges (/obj/structure/destructible/clockwork/anchoring_crystal/charged_crystal)
+#define COMSIG_ANCHORING_CRYSTAL_CHARGED "anchoring_crystal_charged"
+
+#define COMSIG_ATOM_SLAB_ACT "atom_slab_act"
+
+///sent by the ark SS whenever an anchoring crystal is created (/obj/structure/destructible/clockwork/anchoring_crystal/charged_crystal)
+#define COMSIG_ANCHORING_CRYSTAL_CREATED "anchoring_crystal_created"
+// Traits related directly to Clockwork Cult
+#define TRAIT_BRONZE_TURF "bronze_turf"
+/// Given to Clockwork Golems, gives them a reduction on invoke time for certain scriptures.
+#define TRAIT_FASTER_SLAB_INVOKE "faster_slab_invoke"
+/// Prevents the invocation of clockwork scriptures.
+#define TRAIT_NO_SLAB_INVOKE "no_slab_invoke"
+/// Has an item been enchanted by a clock cult Stargazer?
+#define TRAIT_STARGAZED "stargazed"
+/// Soul consumed by sigil of vitality
+#define TRAIT_NO_SOUL_BY_VITALITY "no_soul_by_vitality"
+// Traits Sources
+#define STARGAZER_TRAIT "stargazer_trait"
+/// Trait source for the vanguard scripture
+#define VANGUARD_TRAIT "vanguard_trait"
+/// Trait source from the clockwork sigil
+#define SIGIL_TRAIT "sigil_trait"
+// Roles
+#define ROLE_ROUNDSTART_CLOCK_CULTIST "Roundstart Clockwork Cultist"
+#define ROLE_MIDROUND_CLOCK_CULTIST "Midround Clockwork Cultist"
diff --git a/code/__DEFINES/~nova_defines/security_alerts.dm b/code/__DEFINES/~nova_defines/security_alerts.dm
index 31adf1463fd..8b2d775969b 100644
--- a/code/__DEFINES/~nova_defines/security_alerts.dm
+++ b/code/__DEFINES/~nova_defines/security_alerts.dm
@@ -9,3 +9,7 @@
#define SEC_LEVEL_EPSILON 7 // CENTCOM IS ANGY!!!
#define SEC_LEVEL_GAMMA 8 // Oh shit bois
#define SEC_LEVEL_FEDERAL 9 // THE FUCKING FEDS ARE HERE!!!
+// TFF ADDITION START
+/// Security level is lambda. (oh god eldtrich beings won the video game)
+#define SEC_LEVEL_LAMBDA 7
+// TFF ADDITION END
diff --git a/code/datums/mind/antag.dm b/code/datums/mind/antag.dm
index 87260886892..e0bde1a80d8 100644
--- a/code/datums/mind/antag.dm
+++ b/code/datums/mind/antag.dm
@@ -73,7 +73,7 @@
/// Remove the antagonists that should not persist when being borged
/datum/mind/proc/remove_antags_for_borging()
remove_antag_datum(/datum/antagonist/cult)
-
+ remove_antag_datum(/datum/antagonist/clock_cultist)
var/datum/antagonist/rev/revolutionary = has_antag_datum(/datum/antagonist/rev)
revolutionary?.remove_revolutionary()
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 654b6705774..2c4c1da114e 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -336,7 +336,6 @@
to_chat(O, span_warning("Error: Servo motors unresponsive."))
O.equip_outfit_and_loadout(equipping_job = SSjob.get_job_type(/datum/job/cyborg)) // NOVA EDIT ADDITION - Cyborg loadout hats
-
else
to_chat(user, span_warning("The MMI must go in after everything else!"))
diff --git a/code/game/turfs/open/floor/misc_floor.dm b/code/game/turfs/open/floor/misc_floor.dm
index e28f3ea043f..a7dfd531699 100644
--- a/code/game/turfs/open/floor/misc_floor.dm
+++ b/code/game/turfs/open/floor/misc_floor.dm
@@ -191,6 +191,13 @@
icon_state = "clockwork_floor"
floor_tile = /obj/item/stack/tile/bronze
+// TFF ADDITION START
+/turf/open/floor/bronze/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_BRONZE_TURF, TURF_TRAIT)
+
+// TFF ADDITION END
+
/turf/open/floor/bronze/flat
icon_state = "reebe"
floor_tile = /obj/item/stack/tile/bronze/flat
diff --git a/code/modules/antagonists/cult/cult_other.dm b/code/modules/antagonists/cult/cult_other.dm
index 0e286d75e81..54ac7527eeb 100644
--- a/code/modules/antagonists/cult/cult_other.dm
+++ b/code/modules/antagonists/cult/cult_other.dm
@@ -13,7 +13,7 @@
///Returns whether the given mob is convertable to the blood cult
/proc/is_convertable_to_cult(mob/living/target, datum/team/cult/specific_cult)
- if(!istype(target))
+ if(!isliving(target))
return FALSE
if(isnull(target.mind))
return FALSE
diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm
index fccfd086a6f..f680490f58e 100644
--- a/code/modules/mob/living/silicon/robot/robot_model.dm
+++ b/code/modules/mob/living/silicon/robot/robot_model.dm
@@ -76,7 +76,12 @@
var/obj/item/new_module = new path(robot)
emag_modules += new_module
emag_modules -= path
-
+ // TFF ADDITION
+ for(var/path in clock_modules)
+ var/obj/item/new_module = new path(src)
+ clock_modules += new_module
+ clock_modules -= path
+ // TFF ADDITION END
if(check_holidays(ICE_CREAM_DAY) && !(locate(/obj/item/borg/lollipop) in basic_modules))
basic_modules += new /obj/item/borg/lollipop/ice_cream(robot)
@@ -86,6 +91,7 @@
modules.Cut()
added_modules.Cut()
storages.Cut()
+ clock_modules.Cut() // TFF ADDITION START
return ..()
/obj/item/robot_model/proc/get_usable_modules()
@@ -144,6 +150,11 @@
if(cyborg.emagged)
for(var/obj/item/module as anything in emag_modules)
add_module(module, FALSE, FALSE)
+ // TFF ADDITION START
+ if(cyborg.clockwork)
+ for(var/obj/item/module in clock_modules)
+ add_module(module, FALSE, FALSE)
+ // TFF ADDITION END
for(var/obj/item/module as anything in added_modules)
add_module(module, FALSE, FALSE)
for(var/obj/item/module as anything in held_modules & modules)
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index 56a051fdd7f..a2c912ccd6b 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -1107,6 +1107,9 @@
else
return ALERT_RELEVANCY_WARN
// NOVA EDIT ADDITION END
+ // TFF ADDITION START
+ if(SEC_LEVEL_LAMBDA)
+ return ALERT_RELEVANCY_PERTINENT
return 0
diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm
index 3270b7c55b2..a5b76dbdf28 100644
--- a/code/modules/power/apc/apc_main.dm
+++ b/code/modules/power/apc/apc_main.dm
@@ -669,6 +669,8 @@
if(cell_percent > APC_CHANNEL_ALARM_TRESHOLD)
alarm_manager.clear_alarm(ALARM_POWER)
+ // TFF EDIT START:
+ /* ORIGINAL:
// NOVA EDIT ADDITION START - CLOCK CULT
if(integration_cog)
var/power_delta = clamp(cell.charge - 50, 0, 50)
@@ -679,6 +681,11 @@
if(cell.charge <= 50)
cell.charge = 0
// NOVA EDIT ADDITION END
+ */
+ if(integration_cog && SSthe_ark.clock_power < SSthe_ark.max_clock_power)
+ var/power_delta = clamp(cell.charge - 70, 350, 700)
+ SSthe_ark.adjust_clock_power(power_delta / 70, TRUE)
+ // TFF EDIT END
else // no cell, switch everything off
charging = APC_NOT_CHARGING
equipment = autoset(equipment, AUTOSET_FORCE_OFF)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 2de2dab4d53..8637f744edb 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -344,6 +344,8 @@
/datum/reagent/water/holywater/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, metabolization_ratio)
. = ..()
+ // TFF EDIT START - ORIGINAL:
+ /*
// Microdosing holy water is less effective than just gulping it down
data["deciseconds_metabolized"] += seconds_per_tick * 1 SECONDS * metabolization_ratio
@@ -388,6 +390,34 @@
holder?.remove_reagent(type, volume) // maybe this is a little too perfect and a max() cap on the statuses would be better??
if(need_mob_update)
return UPDATE_MOB_HEALTH
+ */
+ if(affected_mob.blood_volume)
+ affected_mob.blood_volume += 0.1 * REM * seconds_per_tick // water is good for you!
+
+ data["deciseconds_metabolized"] += (seconds_per_tick * 1 SECONDS * REM)
+ affected_mob.adjust_jitter_up_to(2 SECONDS * seconds_per_tick, 20 SECONDS)
+ if(IS_CULTIST(affected_mob) || affected_mob.mind?.has_antag_datum(/datum/antagonist/clock_cultist))
+ if(handle_cultists(affected_mob, seconds_per_tick)) //only returns TRUE on deconversion
+ return
+ holder.remove_reagent(type, 1 * REAGENTS_METABOLISM * seconds_per_tick) //fixed consumption to prevent balancing going out of whack
+
+ var/need_mob_update = FALSE
+
+ if (!HAS_TRAIT(affected_mob, TRAIT_EVIL) || IS_CULTIST(affected_mob) || affected_mob.mind?.holy_role == HOLY_ROLE_PRIEST)
+ return
+ if(data["deciseconds_metabolized"] >= (25 SECONDS)) // 10 units
+ affected_mob.adjust_stutter_up_to(4 SECONDS * REM * seconds_per_tick, 20 SECONDS)
+ affected_mob.set_dizzy_if_lower(10 SECONDS)
+ if(SPT_PROB(25, seconds_per_tick)) //Congratulations, your committment to evil has now made holy water a deadly poison to you!
+ affected_mob.emote("scream")
+ need_mob_update += affected_mob.adjust_fire_loss(3 * REM * seconds_per_tick, updating_health = FALSE)
+ if(data["deciseconds_metabolized"] >= (1 MINUTES)) // 24 units
+ need_mob_update += affected_mob.adjust_fire_loss(10 * REM * seconds_per_tick, updating_health = FALSE)
+ affected_mob.remove_status_effect(/datum/status_effect/jitter)
+ affected_mob.remove_status_effect(/datum/status_effect/speech/stutter)
+ holder?.remove_reagent(type, volume) // maybe this is a little too perfect and a max() cap on the statuses would be better??
+ return need_mob_update
+ // TFF EDIT END
/datum/reagent/water/holywater/expose_turf(turf/exposed_turf, reac_volume)
. = ..()
diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_midroundclockworkcultist.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_midroundclockworkcultist.png
new file mode 100644
index 00000000000..3fa50fc0f3f
Binary files /dev/null and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_midroundclockworkcultist.png differ
diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_roundstartclockworkcultist.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_roundstartclockworkcultist.png
new file mode 100644
index 00000000000..3fa50fc0f3f
Binary files /dev/null and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_roundstartclockworkcultist.png differ
diff --git a/icons/map_icons/items/_item.dmi b/icons/map_icons/items/_item.dmi
index 98079a73b6c..39db80dbd50 100644
Binary files a/icons/map_icons/items/_item.dmi and b/icons/map_icons/items/_item.dmi differ
diff --git a/modular_nova/modules/alerts/code/security_level_datums.dm b/modular_nova/modules/alerts/code/security_level_datums.dm
index 2006edcf3a0..cb572a978bd 100644
--- a/modular_nova/modules/alerts/code/security_level_datums.dm
+++ b/modular_nova/modules/alerts/code/security_level_datums.dm
@@ -136,4 +136,18 @@
looping_sound_interval = 13 SECONDS
shuttle_call_time_mod = ALERT_COEFF_NOVA
+// TFF ADDITION START
+/datum/security_level/lambda
+ name = "lambda"
+ name_shortform = "λ"
+ announcement_color = "crimson" //Thanking Absolucy for having a bigger brain than me in figuring out colors.
+ number_level = SEC_LEVEL_LAMBDA
+ sound = 'tff_modular/modules/antagonists/clock_cult/sound/lambda.ogg' // Ported over the current (as of this codes time) ss14 gamma alert, renamed because it fits better. Old gamma was better :(
+ elevating_to_configuration_key = /datum/config_entry/string/alert_lambda
+ shuttle_call_time_mod = ALERT_COEFF_NOVA //This is as bad as the nuke going off. Everyone is fucked.
+ disables_mail = TRUE
+
+/datum/config_entry/string/alert_lambda
+ default = "Central Command has detected a large spike of dimensional energy, consistent with the summoning of \[REDACTED\] entities. You are advised to make what little time you have left worthwhile; as no additional assets will be dispatched to %STATION_NAME% at this time."
+// TFF ADDITION END
#undef ALERT_COEFF_NOVA
diff --git a/modular_nova/modules/clock_cult/code/actions/_action.dm b/modular_nova/modules/clock_cult/code/actions/_action.dm
index 8f9946041c7..62acaf4e1f9 100644
--- a/modular_nova/modules/clock_cult/code/actions/_action.dm
+++ b/modular_nova/modules/clock_cult/code/actions/_action.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/action/innate/clockcult
button_icon = 'modular_nova/modules/clock_cult/icons/actions_clock.dmi'
background_icon = 'modular_nova/modules/clock_cult/icons/background_clock.dmi'
@@ -58,3 +59,4 @@
/datum/action/item_action/toggle/clock
button_icon = 'modular_nova/modules/clock_cult/icons/background_clock.dmi'
background_icon_state = "bg_clock"
+*/
diff --git a/modular_nova/modules/clock_cult/code/actions/recall_slab.dm b/modular_nova/modules/clock_cult/code/actions/recall_slab.dm
index 9fe03e9f81a..ee0d815e1ce 100644
--- a/modular_nova/modules/clock_cult/code/actions/recall_slab.dm
+++ b/modular_nova/modules/clock_cult/code/actions/recall_slab.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/action/innate/clockcult/recall_slab
name = "Recall Slab"
desc = "Recall your latest used Clockwork Slab from anywhere in the universe."
@@ -103,3 +104,4 @@
item_to_retrieve.loc.visible_message(span_warning("[item_to_retrieve] suddenly appears!"))
playsound(get_turf(item_to_retrieve), 'sound/effects/magic/summonitems_generic.ogg', 50, TRUE)
+*/
diff --git a/modular_nova/modules/clock_cult/code/actions/whirring_convergence.dm b/modular_nova/modules/clock_cult/code/actions/whirring_convergence.dm
index ebbe7d2397d..b7c67d78d92 100644
--- a/modular_nova/modules/clock_cult/code/actions/whirring_convergence.dm
+++ b/modular_nova/modules/clock_cult/code/actions/whirring_convergence.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/*
* Whirring Convergence
* Communicate a message to all other clock cultists
@@ -56,3 +57,4 @@
to_chat(player_mob, "[FOLLOW_LINK(player_mob, user)] [final_message]")
else
to_chat(player_mob, final_message)
+*/
diff --git a/modular_nova/modules/clock_cult/code/antagonist.dm b/modular_nova/modules/clock_cult/code/antagonist.dm
index 406d703a6df..e52484f6c56 100644
--- a/modular_nova/modules/clock_cult/code/antagonist.dm
+++ b/modular_nova/modules/clock_cult/code/antagonist.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
// This'll take a bit of explaining.
// Clock cult, the (shitty) gamemode is not coming back, this antagonist datum is for the soon-to-come OPFOR bundle
// However, the bundle gives `/datum/antagonist/clock_cultist/solo`, which is the same as `/datum/antagonist/clock_cultist`, but lacks conversion.
@@ -72,3 +74,4 @@
name = "Clock Cultist (Solo)"
show_to_ghosts = FALSE
can_convert = FALSE
+*/
diff --git a/modular_nova/modules/clock_cult/code/area.dm b/modular_nova/modules/clock_cult/code/area.dm
index 9b04b90219c..323f749a918 100644
--- a/modular_nova/modules/clock_cult/code/area.dm
+++ b/modular_nova/modules/clock_cult/code/area.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/area/ruin/powered/reebe
name = "Outpost of Cogs"
ambience_index = AMBIENCE_REEBE
@@ -9,3 +10,4 @@
name = "Outpost of Cogs Space"
base_lighting_alpha = 255
+*/
diff --git a/modular_nova/modules/clock_cult/code/components/brass_spreader.dm b/modular_nova/modules/clock_cult/code/components/brass_spreader.dm
index 711bff25fb5..fe7f6301706 100644
--- a/modular_nova/modules/clock_cult/code/components/brass_spreader.dm
+++ b/modular_nova/modules/clock_cult/code/components/brass_spreader.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/// A component that spreads brass to a tile in [range] every [cooldown] seconds, converting everything on it into brass as well.
/datum/component/brass_spreader
/// The range of which to spread brass
@@ -98,3 +99,4 @@
return
COOLDOWN_START(src, turf_conversion_cooldown, cooldown)
+*/
diff --git a/modular_nova/modules/clock_cult/code/components/hint_element.dm b/modular_nova/modules/clock_cult/code/components/hint_element.dm
index 9fd9b71792f..6cbd14aa3e5 100644
--- a/modular_nova/modules/clock_cult/code/components/hint_element.dm
+++ b/modular_nova/modules/clock_cult/code/components/hint_element.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/element/clockwork_description
element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY
argument_hash_start_idx = 2
@@ -37,3 +38,4 @@
if(IS_CLOCK(user))
examine_texts += span_brass(text_to_add)
+*/
diff --git a/modular_nova/modules/clock_cult/code/components/pickup_element.dm b/modular_nova/modules/clock_cult/code/components/pickup_element.dm
index 00486e816e7..3a5880815dc 100644
--- a/modular_nova/modules/clock_cult/code/components/pickup_element.dm
+++ b/modular_nova/modules/clock_cult/code/components/pickup_element.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define REGULAR_PICKUP_MOD 1
#define CULTIST_PICKUP_MOD 2
#define PICKUP_SHOCK_DAMAGE 25
@@ -55,3 +56,4 @@
#undef REGULAR_PICKUP_MOD
#undef CULTIST_PICKUP_MOD
#undef PICKUP_SHOCK_DAMAGE
+*/
diff --git a/modular_nova/modules/clock_cult/code/components/structure_info_element.dm b/modular_nova/modules/clock_cult/code/components/structure_info_element.dm
index fa37830184f..df4faaa559f 100644
--- a/modular_nova/modules/clock_cult/code/components/structure_info_element.dm
+++ b/modular_nova/modules/clock_cult/code/components/structure_info_element.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/element/clockwork_structure_info
element_flags = ELEMENT_DETACH_ON_HOST_DESTROY
@@ -61,3 +62,4 @@
return
examine_text += span_brass("You can gain more information by using a Clockwork Slab.")
+*/
diff --git a/modular_nova/modules/clock_cult/code/globals.dm b/modular_nova/modules/clock_cult/code/globals.dm
index a7b8e484a1f..5c4789dea91 100644
--- a/modular_nova/modules/clock_cult/code/globals.dm
+++ b/modular_nova/modules/clock_cult/code/globals.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
GLOBAL_VAR_INIT(clock_power, 2500)
GLOBAL_VAR_INIT(max_clock_power, 2500) // Increases with every APC cogged
GLOBAL_VAR_INIT(clock_vitality, 0)
@@ -16,3 +18,4 @@ GLOBAL_LIST_EMPTY(clockwork_research_unlocked_scriptures)
. += new path
return .
+*/
diff --git a/modular_nova/modules/clock_cult/code/items/clockwork_slab.dm b/modular_nova/modules/clock_cult/code/items/clockwork_slab.dm
index 574dda7bd8b..ed613718205 100644
--- a/modular_nova/modules/clock_cult/code/items/clockwork_slab.dm
+++ b/modular_nova/modules/clock_cult/code/items/clockwork_slab.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define MAXIMUM_QUICKBIND_SLOTS 5
GLOBAL_LIST_INIT(clockwork_slabs, list())
@@ -244,3 +245,4 @@ GLOBAL_LIST_INIT(clockwork_slabs, list())
bind_spell(living_user, scripture, positions.Find(position))
#undef MAXIMUM_QUICKBIND_SLOTS
+*/
diff --git a/modular_nova/modules/clock_cult/code/items/clothing.dm b/modular_nova/modules/clock_cult/code/items/clothing.dm
index fb84397abf8..e5f6004c364 100644
--- a/modular_nova/modules/clock_cult/code/items/clothing.dm
+++ b/modular_nova/modules/clock_cult/code/items/clothing.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define VISOR_MOUNT_DAMAGE 20
#define VISOR_MOUNT_SLEEP_TIME 5 SECONDS
@@ -451,3 +452,4 @@
#undef VISOR_MOUNT_DAMAGE
#undef VISOR_MOUNT_SLEEP_TIME
+*/
diff --git a/modular_nova/modules/clock_cult/code/items/integration_cog.dm b/modular_nova/modules/clock_cult/code/items/integration_cog.dm
index 0844634fdcb..3c0ab549ec4 100644
--- a/modular_nova/modules/clock_cult/code/items/integration_cog.dm
+++ b/modular_nova/modules/clock_cult/code/items/integration_cog.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define MAX_POWER_PER_COG 250
#define HALLUCINATION_COG_CHANCE 20
#define SET_UP_TIME (5 MINUTES)
@@ -109,3 +110,4 @@
#undef MAX_POWER_PER_COG
#undef HALLUCINATION_COG_CHANCE
#undef SET_UP_TIME
+*/
diff --git a/modular_nova/modules/clock_cult/code/items/replica_fabricator.dm b/modular_nova/modules/clock_cult/code/items/replica_fabricator.dm
index d92a905b5e5..a9ace96fed9 100644
--- a/modular_nova/modules/clock_cult/code/items/replica_fabricator.dm
+++ b/modular_nova/modules/clock_cult/code/items/replica_fabricator.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define BRASS_POWER_COST 10
#define REGULAR_POWER_COST (BRASS_POWER_COST / 2)
@@ -286,3 +287,4 @@
#undef BRASS_POWER_COST
#undef REGULAR_POWER_COST
+*/
diff --git a/modular_nova/modules/clock_cult/code/items/tools.dm b/modular_nova/modules/clock_cult/code/items/tools.dm
index c37404700d7..bac76f22309 100644
--- a/modular_nova/modules/clock_cult/code/items/tools.dm
+++ b/modular_nova/modules/clock_cult/code/items/tools.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define BRASS_TOOLSPEED_MOD 0.5
/obj/item/wirecutters/brass
@@ -62,3 +63,4 @@
new /obj/item/multitool(src)
#undef BRASS_TOOLSPEED_MOD
+*/
diff --git a/modular_nova/modules/clock_cult/code/items/weaponry.dm b/modular_nova/modules/clock_cult/code/items/weaponry.dm
index b777653bd1f..5e12f7f00fe 100644
--- a/modular_nova/modules/clock_cult/code/items/weaponry.dm
+++ b/modular_nova/modules/clock_cult/code/items/weaponry.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define HAMMER_FLING_DISTANCE 2
#define HAMMER_THROW_FLING_DISTANCE 3
#define BRASS_RIFLE_REDUCED_DELAY 0.25 SECONDS
@@ -139,7 +140,6 @@
/obj/item/clockwork/weapon/brass_sword/proc/send_message(mob/living/target)
to_chat(target, span_brass("[src] glows, indicating the next attack will disrupt electronics of the target."))
-
/obj/item/gun/ballistic/bow/clockwork
name = "brass bow"
desc = "A bow made from brass and other components that you can't quite understand. It glows with a deep energy and frabricates arrows by itself."
@@ -221,7 +221,8 @@
icon_state = "arrow_energy"
damage = 35
damage_type = BURN
-
+*/
+/*
/obj/item/gun/ballistic/rifle/lionhunter/clockwork
name = "brass rifle"
desc = "An antique, brass rifle made with the finest of care. It has an ornate scope in the shape of a cog built into the top."
@@ -241,6 +242,7 @@
. = ..()
AddElement(/datum/element/clockwork_description, "The speed of which you aim at far targets while standing on brass will be massively increased.")
AddElement(/datum/element/clockwork_pickup)
+ qdel(src)
/obj/item/ammo_box/magazine/internal/boltaction/lionhunter/clockwork
name = "brass rifle internal magazine"
@@ -255,7 +257,7 @@
var/obj/item/gun/ballistic/fired_gun = fired_from
if(istype(get_turf(user), /turf/open/floor/bronze) && istype(fired_gun, /obj/item/gun/ballistic/rifle/lionhunter/clockwork))
- seconds_per_distance = BRASS_RIFLE_REDUCED_DELAY
+ seconds_per_distance = 0.25 SECONDS
return ..()
@@ -286,4 +288,7 @@
#undef HAMMER_FLING_DISTANCE
#undef HAMMER_THROW_FLING_DISTANCE
+
#undef BRASS_RIFLE_REDUCED_DELAY
+
+*/
diff --git a/modular_nova/modules/clock_cult/code/language.dm b/modular_nova/modules/clock_cult/code/language.dm
index d096e61903a..625209a64e2 100644
--- a/modular_nova/modules/clock_cult/code/language.dm
+++ b/modular_nova/modules/clock_cult/code/language.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
/datum/language_holder/clockmob
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/ratvar = list(LANGUAGE_ATOM))
@@ -139,3 +141,4 @@
#undef REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT
#undef REVERSE_RATVAR_HYPHEN_OF_MATCH
#undef REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT
+*/
diff --git a/modular_nova/modules/clock_cult/code/mobs/clockwork_marauder.dm b/modular_nova/modules/clock_cult/code/mobs/clockwork_marauder.dm
index 5430cee59e2..652fcced3fe 100644
--- a/modular_nova/modules/clock_cult/code/mobs/clockwork_marauder.dm
+++ b/modular_nova/modules/clock_cult/code/mobs/clockwork_marauder.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define MARAUDER_SHIELD_MAX 5
#define WELDER_REPAIR_AMOUNT 15
@@ -143,3 +144,4 @@ GLOBAL_LIST_EMPTY(clockwork_marauders)
#undef MARAUDER_SHIELD_MAX
#undef WELDER_REPAIR_AMOUNT
+*/
diff --git a/modular_nova/modules/clock_cult/code/outfit.dm b/modular_nova/modules/clock_cult/code/outfit.dm
index feee1c42c45..1302904994f 100644
--- a/modular_nova/modules/clock_cult/code/outfit.dm
+++ b/modular_nova/modules/clock_cult/code/outfit.dm
@@ -1,3 +1,4 @@
+/* TFF REMOVAL
/datum/outfit/clock
name = "Default Clock Cultist"
@@ -16,7 +17,6 @@
/datum/outfit/clock/pre_equip(mob/living/carbon/human/equip_human, visualsOnly)
equip_human.add_faction(FACTION_CLOCK)
-
/datum/outfit/clock/armor
name = "Armored Clock Cultist"
@@ -32,6 +32,7 @@
head = /obj/item/clothing/head/helmet/clockwork
glasses = /obj/item/clothing/glasses/clockwork/judicial_visor/no_damage
l_hand = /obj/item/gun/ballistic/bow/clockwork
+*/
/datum/outfit/clock/gun
name = "Seer Clock Cultist"
@@ -42,6 +43,8 @@
r_pocket = /obj/item/storage/pouch/ammo/clock
l_hand = /obj/item/gun/ballistic/rifle/lionhunter/clockwork
+/* TFF REMOVAL
+
/datum/outfit/clock/support
name = "Support Clock Cultist"
@@ -59,7 +62,6 @@
/obj/item/clockwork/clockwork_slab = 1,
)
-
/datum/outfit/clockwork_armaments
name = "Clockwork Cultist Base"
@@ -67,3 +69,4 @@
shoes = /obj/item/clothing/shoes/clockwork
gloves = /obj/item/clothing/gloves/clockwork
head = /obj/item/clothing/head/helmet/clockwork
+*/
diff --git a/modular_nova/modules/clock_cult/code/outpost_of_cogs.dm b/modular_nova/modules/clock_cult/code/outpost_of_cogs.dm
index fb513fe2644..7a5ac561592 100644
--- a/modular_nova/modules/clock_cult/code/outpost_of_cogs.dm
+++ b/modular_nova/modules/clock_cult/code/outpost_of_cogs.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
/datum/lazy_template/reebe
key = LAZY_TEMPLATE_KEY_OUTPOST_OF_COGS
map_dir = "_maps/nova/lazy_templates"
@@ -116,7 +118,7 @@
var/obj/item/clothing/suit/hooded/hooded = equipped.wear_suit
var/datum/component/toggle_attached_clothing/hood = hooded.GetComponent(/datum/component/toggle_attached_clothing)
hood.toggle_deployable() // start unhooded
-
+*/
/obj/effect/mob_spawn/corpse/human/clock_cultist
name = "Clock Cultist"
@@ -132,3 +134,4 @@
/obj/effect/landmark/late_cog_portals
name = "late cog portal spawn"
+
diff --git a/modular_nova/modules/clock_cult/code/portal.dm b/modular_nova/modules/clock_cult/code/portal.dm
index 26fbaed6f7b..e0028ad77f8 100644
--- a/modular_nova/modules/clock_cult/code/portal.dm
+++ b/modular_nova/modules/clock_cult/code/portal.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/obj/effect/portal/permanent/one_way/reebe
name = "whirring portal"
desc = "A tall, glowing portal. A low emination of moving cogs can be heard. You don't feel like coming back will be the easiest."
@@ -23,7 +24,7 @@
return ..()
-
+*/
/obj/effect/portal/permanent/one_way/reebe/leaving
desc = "For those who wish or require to leave the holy outpost."
id = "reebe_exit"
diff --git a/modular_nova/modules/clock_cult/code/research/asset_cache.dm b/modular_nova/modules/clock_cult/code/research/asset_cache.dm
index 8171b2c05cb..ddee9250edd 100644
--- a/modular_nova/modules/clock_cult/code/research/asset_cache.dm
+++ b/modular_nova/modules/clock_cult/code/research/asset_cache.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
// Now, you might be asking "why is this hooked into the research designs spritesheet?"
// Well, for some *absurd* reason, any time i tried to add sprites to a new spritesheet, they would always have a *gray* background covering the full 32x32, apart from what my sprite did. After multiple hours of debugging,
// I settled on this, since it's not-really-harmful to have other things in an unrelated spritesheet.
@@ -46,3 +47,4 @@
insert_icon(id, uni_icon(icon_file, icon_state))
qdel(new_research)
+*/
diff --git a/modular_nova/modules/clock_cult/code/research/clockwork_research.dm b/modular_nova/modules/clock_cult/code/research/clockwork_research.dm
index c3297c7c167..7401cb09094 100644
--- a/modular_nova/modules/clock_cult/code/research/clockwork_research.dm
+++ b/modular_nova/modules/clock_cult/code/research/clockwork_research.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/clockwork_research
/// Name of the research node
var/name = ""
@@ -112,3 +113,4 @@
/datum/tinker_cache_item/clockwork_rifle_ammo,
)
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/_scripture.dm b/modular_nova/modules/clock_cult/code/scriptures/_scripture.dm
index c5aa28cd577..f3217ba8834 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/_scripture.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/_scripture.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
GLOBAL_LIST_EMPTY(clock_scriptures)
GLOBAL_LIST_EMPTY(clock_scriptures_by_type)
@@ -277,7 +278,7 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type)
/datum/scripture/slab/invoke()
- progress = new(invoker, use_time)
+ progress = new(invoker, use_time, invoking_slab)
uses_left = uses
time_left = use_time
invoking_slab.charge_overlay = slab_overlay
@@ -370,3 +371,4 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type)
var/datum/scripture/clock_script = new categorypath
GLOB.clock_scriptures += clock_script
GLOB.clock_scriptures_by_type[clock_script.type] = clock_script
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/preservation/clockwork_armaments.dm b/modular_nova/modules/clock_cult/code/scriptures/preservation/clockwork_armaments.dm
index e37987c5537..00160be33e5 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/preservation/clockwork_armaments.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/preservation/clockwork_armaments.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/clockwork_armaments
name = "Clockwork Armaments"
desc = "Summon clockwork armor and weapons, to be ready for battle."
@@ -38,3 +39,4 @@
base_outfit.equip(invoker)
invoker.put_in_hands(new weapon_path, FALSE)
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/preservation/summon_marauder.dm b/modular_nova/modules/clock_cult/code/scriptures/preservation/summon_marauder.dm
index a87a1cd57b6..e5adcea1550 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/preservation/summon_marauder.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/preservation/summon_marauder.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define MAXIMUM_MARAUDERS 2
/datum/scripture/marauder
@@ -67,3 +68,4 @@
return TRUE
#undef MAXIMUM_MARAUDERS
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/servitude/hateful_manacles.dm b/modular_nova/modules/clock_cult/code/scriptures/servitude/hateful_manacles.dm
index 0841ed79df4..5402121d9bb 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/servitude/hateful_manacles.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/servitude/hateful_manacles.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/slab/hateful_manacles
name = "Hateful Manacles"
desc = "Forms replicant manacles around a target's wrists that function like handcuffs, restraining the target."
@@ -42,3 +43,4 @@
desc = "Heavy manacles made out of freezing-cold metal. It looks like brass, but feels much more solid."
icon_state = "brass_manacles"
item_flags = DROPDEL
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/servitude/integration_cog.dm b/modular_nova/modules/clock_cult/code/scriptures/servitude/integration_cog.dm
index 51f97014f3e..520aefe1858 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/servitude/integration_cog.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/servitude/integration_cog.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/integration_cog
name = "Integration Cog"
desc = "Fabricates an integration cog, which can be inserted into APCs to draw power and unlock scriptures."
@@ -17,3 +18,4 @@
to_chat(invoker, span_brass("You summon an integration cog on the floor."))
playsound(src, 'sound/machines/click.ogg', 50)
return FALSE
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/servitude/kindle.dm b/modular_nova/modules/clock_cult/code/scriptures/servitude/kindle.dm
index 5908dcdc8b3..72a85115050 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/servitude/kindle.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/servitude/kindle.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define EFFECT_TIME (6.5 SECONDS)
// Clock cult's version of the "bullshit stun hand"
@@ -91,3 +92,4 @@
return TRUE
#undef EFFECT_TIME
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/servitude/vitality_sigil.dm b/modular_nova/modules/clock_cult/code/scriptures/servitude/vitality_sigil.dm
index 123ce68c953..7b7e9172087 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/servitude/vitality_sigil.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/servitude/vitality_sigil.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/create_structure/sigil_vitality
name = "Vitality Matrix"
desc = "Summons a vitality matrix, which drains the life force of non servants. Much less vitality is gained from simpler entities."
@@ -10,3 +11,4 @@
cogs_required = 2
invokers_required = 2
category = SPELLTYPE_SERVITUDE
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/structures/interdiction_lens.dm b/modular_nova/modules/clock_cult/code/scriptures/structures/interdiction_lens.dm
index 9670dbf73aa..6d3116c7a42 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/structures/interdiction_lens.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/structures/interdiction_lens.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/create_structure/interdiction
name = "Interdiction Lens"
desc = "Creates a device that will slow non servants in the area and damage mechanised exosuits. Requires power from a sigil of transmission."
@@ -9,3 +10,4 @@
summoned_structure = /obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens
cogs_required = 4
category = SPELLTYPE_STRUCTURES
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/structures/ocular_warden.dm b/modular_nova/modules/clock_cult/code/scriptures/structures/ocular_warden.dm
index b3706dc35bd..1a7d17f5a45 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/structures/ocular_warden.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/structures/ocular_warden.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define OCULAR_WARDEN_PLACE_RANGE 3
/datum/scripture/create_structure/ocular_warden
@@ -24,3 +25,4 @@
return TRUE
#undef OCULAR_WARDEN_PLACE_RANGE
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/structures/prosperity_prism.dm b/modular_nova/modules/clock_cult/code/scriptures/structures/prosperity_prism.dm
index b157719e5d7..0b0a8fbfbc6 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/structures/prosperity_prism.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/structures/prosperity_prism.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/create_structure/prosperity_prism
name = "Prosperity Prism"
desc = "Creates a prism that will remove all forms of damage from nearby servants over time, along with purging poisons. Requires power from a sigil of transmission."
@@ -21,3 +22,4 @@
return FALSE
return TRUE
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/structures/technologists_lectern.dm b/modular_nova/modules/clock_cult/code/scriptures/structures/technologists_lectern.dm
index 40c1b9fd4de..41ebad08600 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/structures/technologists_lectern.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/structures/technologists_lectern.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/create_structure/technologists_lectern
name = "Technologist's Lectern"
desc = "Creates a technologist's lectern, usable in certain areas to research new, powerful scriptures and equipment. Research takes a while and unenlightened minds may take notice."
@@ -10,3 +11,4 @@
cogs_required = 2
category = SPELLTYPE_STRUCTURES
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/structures/tinkerers_cache.dm b/modular_nova/modules/clock_cult/code/scriptures/structures/tinkerers_cache.dm
index 90d202a666f..1d80f91d06e 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/structures/tinkerers_cache.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/structures/tinkerers_cache.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/create_structure/tinkerers_cache
name = "Tinkerer's Cache"
desc = "Creates a tinkerer's cache, a powerful forge capable of crafting elite equipment."
@@ -9,3 +10,4 @@
summoned_structure = /obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache
cogs_required = 4
category = SPELLTYPE_STRUCTURES
+*/
diff --git a/modular_nova/modules/clock_cult/code/scriptures/structures/transmission_sigil.dm b/modular_nova/modules/clock_cult/code/scriptures/structures/transmission_sigil.dm
index df8c1bf2d92..f70d297b4cf 100644
--- a/modular_nova/modules/clock_cult/code/scriptures/structures/transmission_sigil.dm
+++ b/modular_nova/modules/clock_cult/code/scriptures/structures/transmission_sigil.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/scripture/create_structure/sigil_transmission
name = "Sigil of Transmission"
desc = "Summons a sigil of transmission, required to power clockwork structures. Will also drain power from charged objects."
@@ -8,3 +9,4 @@
invocation_text = list("Oh great holy one...", "your energy...", "the power of the holy light!")
summoned_structure = /obj/structure/destructible/clockwork/sigil/transmission
category = SPELLTYPE_STRUCTURES
+*/
diff --git a/modular_nova/modules/clock_cult/code/status_effects.dm b/modular_nova/modules/clock_cult/code/status_effects.dm
index 4f02afb869f..5612bfbae4d 100644
--- a/modular_nova/modules/clock_cult/code/status_effects.dm
+++ b/modular_nova/modules/clock_cult/code/status_effects.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/datum/status_effect/interdiction
id = "interdicted"
duration = 2.6 SECONDS
@@ -30,3 +31,4 @@
/datum/movespeed_modifier/clock_interdiction
multiplicative_slowdown = 1.5
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/_powered.dm b/modular_nova/modules/clock_cult/code/structures/_powered.dm
index 2c80ac6a623..00dd89d028a 100644
--- a/modular_nova/modules/clock_cult/code/structures/_powered.dm
+++ b/modular_nova/modules/clock_cult/code/structures/_powered.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
/obj/structure/destructible/clockwork/gear_base/powered
/// If the structure has its "on" switch flipped. Does not mean it's on, necessarily (needs power and anchoring, too)
var/enabled = FALSE
@@ -204,3 +206,4 @@
LAZYREMOVE(sigil.linked_structures, src)
check_power()
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/_structure.dm b/modular_nova/modules/clock_cult/code/structures/_structure.dm
index 3c6b9b9dc79..aa25a4210e1 100644
--- a/modular_nova/modules/clock_cult/code/structures/_structure.dm
+++ b/modular_nova/modules/clock_cult/code/structures/_structure.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/// The base clockwork structure. Can have an alternate desc and will show up in the list of clockwork objects.
/obj/structure/destructible/clockwork
name = "meme structure"
@@ -48,3 +49,4 @@
balloon_alert(user, "rotated [dir2text(dir)]")
return TRUE
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/airlock.dm b/modular_nova/modules/clock_cult/code/structures/airlock.dm
index 33cf073c855..e336ca9e9e4 100644
--- a/modular_nova/modules/clock_cult/code/structures/airlock.dm
+++ b/modular_nova/modules/clock_cult/code/structures/airlock.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
/obj/structure/door_assembly/door_assembly_bronze/clock
airlock_type = /obj/machinery/door/airlock/bronze/clock
@@ -48,3 +50,4 @@
assemblytype = /obj/structure/door_assembly/door_assembly_bronze/seethru/clock
glass = TRUE
opacity = FALSE
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/gear_base.dm b/modular_nova/modules/clock_cult/code/structures/gear_base.dm
index 6ab82016744..d3f390d55e7 100644
--- a/modular_nova/modules/clock_cult/code/structures/gear_base.dm
+++ b/modular_nova/modules/clock_cult/code/structures/gear_base.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/obj/structure/destructible/clockwork/gear_base
name = "gear base"
desc = "A large cog lying on the floor at feet level."
@@ -43,3 +44,4 @@
if(!anchored)
icon_state += unwrenched_suffix
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/interdiction_lens.dm b/modular_nova/modules/clock_cult/code/structures/interdiction_lens.dm
index c1345ceac80..922dfb6d23a 100644
--- a/modular_nova/modules/clock_cult/code/structures/interdiction_lens.dm
+++ b/modular_nova/modules/clock_cult/code/structures/interdiction_lens.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
#define INTERDICTION_LENS_RANGE 4
#define POWER_PER_PERSON 5
@@ -78,3 +80,4 @@
#undef INTERDICTION_LENS_RANGE
#undef POWER_PER_PERSON
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/ocular_warden.dm b/modular_nova/modules/clock_cult/code/structures/ocular_warden.dm
index 4d14c27f308..43c3d9ec9c8 100644
--- a/modular_nova/modules/clock_cult/code/structures/ocular_warden.dm
+++ b/modular_nova/modules/clock_cult/code/structures/ocular_warden.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
#define FIRE_DELAY (2 SECONDS)
#define FIRE_RANGE 4
#define BASE_DAMAGE 15
@@ -76,3 +78,4 @@
#undef MINIMUM_DAMAGE
#undef DAMAGE_FALLOFF
#undef SHOOT_POWER_USE
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/prosperity_prism.dm b/modular_nova/modules/clock_cult/code/structures/prosperity_prism.dm
index fc3b08f545e..a2384939224 100644
--- a/modular_nova/modules/clock_cult/code/structures/prosperity_prism.dm
+++ b/modular_nova/modules/clock_cult/code/structures/prosperity_prism.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
#define POWER_PER_USE 50
/obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism
@@ -41,3 +43,4 @@
possible_cultist.reagents.remove_reagent(toxin_chem.type, 2.5 * seconds_per_tick)
#undef POWER_PER_USE
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/sigil/_sigil.dm b/modular_nova/modules/clock_cult/code/structures/sigil/_sigil.dm
index e7b0aecd6c9..d118042cedd 100644
--- a/modular_nova/modules/clock_cult/code/structures/sigil/_sigil.dm
+++ b/modular_nova/modules/clock_cult/code/structures/sigil/_sigil.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define SIGIL_INVOCATION_ALPHA 120
#define SIGIL_INVOKED_ALPHA 200
#define SIGIL_MATRIX_SCALE 1.2
@@ -144,3 +145,4 @@
#undef SIGIL_INVOCATION_ALPHA
#undef SIGIL_INVOKED_ALPHA
#undef SIGIL_MATRIX_SCALE
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/sigil/sigil_research.dm b/modular_nova/modules/clock_cult/code/structures/sigil/sigil_research.dm
index 8e4f0b802b4..742c9e3cb38 100644
--- a/modular_nova/modules/clock_cult/code/structures/sigil/sigil_research.dm
+++ b/modular_nova/modules/clock_cult/code/structures/sigil/sigil_research.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define DISAPPEAR_REAPPEAR_TIME (2 SECONDS)
/obj/structure/destructible/clockwork/sigil/research
@@ -33,3 +34,4 @@
#undef DISAPPEAR_REAPPEAR_TIME
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/sigil/sigil_transmission.dm b/modular_nova/modules/clock_cult/code/structures/sigil/sigil_transmission.dm
index 7541f1b7269..17a7ec06176 100644
--- a/modular_nova/modules/clock_cult/code/structures/sigil/sigil_transmission.dm
+++ b/modular_nova/modules/clock_cult/code/structures/sigil/sigil_transmission.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define POWER_GIVE 40
#define POWER_SIPHON 20
@@ -112,3 +113,4 @@
#undef POWER_GIVE
#undef POWER_SIPHON
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/sigil/vitality_sigil.dm b/modular_nova/modules/clock_cult/code/structures/sigil/vitality_sigil.dm
index af094e4a82d..3559876b5f8 100644
--- a/modular_nova/modules/clock_cult/code/structures/sigil/vitality_sigil.dm
+++ b/modular_nova/modules/clock_cult/code/structures/sigil/vitality_sigil.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/obj/structure/destructible/clockwork/sigil/vitality
name = "vitality matrix"
desc = "A twisting, confusing artifact that drains the unenlightended on contact."
@@ -66,3 +67,4 @@
else
send_clock_message(null, "[affected_mob] has had their vitality drained by [src], rejoice!", "")
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/technologists_lectern.dm b/modular_nova/modules/clock_cult/code/structures/technologists_lectern.dm
index 6ee96c4ee5f..f01f124b432 100644
--- a/modular_nova/modules/clock_cult/code/structures/technologists_lectern.dm
+++ b/modular_nova/modules/clock_cult/code/structures/technologists_lectern.dm
@@ -1,15 +1,18 @@
+// TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define BOOK_OPEN_RANGE 2
/obj/structure/destructible/clockwork/gear_base/technologists_lectern
name = "technologist's lectern"
desc = "A small pedestal with a glowing book floating over it.."
clockwork_desc = "A small pedestal, glowing with a divine energy. Used to research new abilities and objects."
+ icon = 'modular_nova/modules/clock_cult/icons/clockwork_objects.dmi' // TFF ADDITION
base_icon_state = "lectern"
icon_state = "lectern"
anchored = TRUE
break_message = "The lectern collapses."
can_unwrench = FALSE
max_integrity = 400
+/*
/// If the last process() found a clock cultist in range
var/mobs_in_range = FALSE
/// Ref to the effect of the lectern's book
@@ -477,3 +480,4 @@
flick("lectern_closing", src)
#undef BOOK_OPEN_RANGE
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/tinkerers_cache.dm b/modular_nova/modules/clock_cult/code/structures/tinkerers_cache.dm
index 8bc60f0f7ad..9f1b176bc7e 100644
--- a/modular_nova/modules/clock_cult/code/structures/tinkerers_cache.dm
+++ b/modular_nova/modules/clock_cult/code/structures/tinkerers_cache.dm
@@ -1,3 +1,5 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
+
/obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache
name = "tinkerer's cache"
desc = "A bronze store filled with parts and components."
@@ -167,3 +169,4 @@
/datum/tinker_cache_item/trap/pressure
name = "Pressure Sensor (Trigger)"
item_path = /obj/item/clockwork/trap_placer/pressure_sensor
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/traps/receivers/flipper.dm b/modular_nova/modules/clock_cult/code/structures/traps/receivers/flipper.dm
index 1d943aa34a4..8255575e61a 100644
--- a/modular_nova/modules/clock_cult/code/structures/traps/receivers/flipper.dm
+++ b/modular_nova/modules/clock_cult/code/structures/traps/receivers/flipper.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define FLIP_DISTANCE 6
#define FLIP_SPEED 3
@@ -58,3 +59,4 @@
#undef FLIP_DISTANCE
#undef FLIP_SPEED
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/traps/receivers/skewer.dm b/modular_nova/modules/clock_cult/code/structures/traps/receivers/skewer.dm
index 014f0df43d9..0a0b9a35872 100644
--- a/modular_nova/modules/clock_cult/code/structures/traps/receivers/skewer.dm
+++ b/modular_nova/modules/clock_cult/code/structures/traps/receivers/skewer.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define SKEWER_DAMAGE 15
#define SKEWER_BLEED 30
@@ -112,3 +113,4 @@
#undef SKEWER_DAMAGE
#undef SKEWER_BLEED
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/traps/senders/delay.dm b/modular_nova/modules/clock_cult/code/structures/traps/senders/delay.dm
index b468c079f3c..f6d8bb93a17 100644
--- a/modular_nova/modules/clock_cult/code/structures/traps/senders/delay.dm
+++ b/modular_nova/modules/clock_cult/code/structures/traps/senders/delay.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/obj/item/wallframe/clocktrap/delay
name = "clockwork timer"
desc = "A small, detached timer."
@@ -45,3 +46,4 @@
/datum/component/clockwork_trap/delay/proc/finish()
active = FALSE
trigger_connected()
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/traps/senders/lever.dm b/modular_nova/modules/clock_cult/code/structures/traps/senders/lever.dm
index 7dd5926bb85..bec2ccbbfa5 100644
--- a/modular_nova/modules/clock_cult/code/structures/traps/senders/lever.dm
+++ b/modular_nova/modules/clock_cult/code/structures/traps/senders/lever.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/obj/item/wallframe/clocktrap/lever
name = "switch"
desc = "A small switch attatched to the wall."
@@ -24,3 +25,4 @@
trigger_connected()
to_chat(user, span_notice("You activate the switch."))
playsound(user, 'sound/machines/click.ogg', 50)
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/traps/senders/pressure_sensor.dm b/modular_nova/modules/clock_cult/code/structures/traps/senders/pressure_sensor.dm
index 4f516feae2e..22b2c78bbfc 100644
--- a/modular_nova/modules/clock_cult/code/structures/traps/senders/pressure_sensor.dm
+++ b/modular_nova/modules/clock_cult/code/structures/traps/senders/pressure_sensor.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/obj/item/clockwork/trap_placer/pressure_sensor
name = "pressure plate"
desc = "I wonder what happens if you step on it."
@@ -44,3 +45,4 @@
trigger_connected()
playsound(parent, 'sound/machines/click.ogg', 50)
+*/
diff --git a/modular_nova/modules/clock_cult/code/structures/traps/trap.dm b/modular_nova/modules/clock_cult/code/structures/traps/trap.dm
index 8815a22e960..9312220c7f8 100644
--- a/modular_nova/modules/clock_cult/code/structures/traps/trap.dm
+++ b/modular_nova/modules/clock_cult/code/structures/traps/trap.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
//Thing that you stick on the floor
/obj/item/clockwork/trap_placer
name = "trap"
@@ -168,3 +169,4 @@
for(var/datum/output as anything in outputs) //must be typecasted because of how SEND_SIGNAL works
SEND_SIGNAL(output, COMSIG_CLOCKWORK_SIGNAL_RECEIVED)
+*/
diff --git a/modular_nova/modules/clock_cult/code/temp_visual.dm b/modular_nova/modules/clock_cult/code/temp_visual.dm
index 92a14f3d7be..adbae74c743 100644
--- a/modular_nova/modules/clock_cult/code/temp_visual.dm
+++ b/modular_nova/modules/clock_cult/code/temp_visual.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
#define MENDING_MANTRA_SCALE 2
//temporary visual effects(/obj/effect/temp_visual) used by clock stuff
@@ -219,3 +220,4 @@
#undef MENDING_MANTRA_SCALE
+*/
diff --git a/modular_nova/modules/clock_cult/code/turf.dm b/modular_nova/modules/clock_cult/code/turf.dm
index 1e3be9c4873..76456b6d050 100644
--- a/modular_nova/modules/clock_cult/code/turf.dm
+++ b/modular_nova/modules/clock_cult/code/turf.dm
@@ -1,3 +1,4 @@
+/* // TFF REWORK - SEE /tff_modular/modules/antagonist/clock_cult/...
/turf/open/indestructible/reebe_void
name = "void"
desc = "A white, empty void, quite unlike anything you've seen before."
@@ -51,3 +52,4 @@
if(prob(95) && !(locate(/obj/structure/lattice) in loc)) // Don't try putting a lattice where one already exists or we can get runtimes
new /obj/structure/lattice(src)
+*/
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/_action.dm b/tff_modular/modules/antagonists/clock_cult/actions/_action.dm
new file mode 100644
index 00000000000..bdc039d3669
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/_action.dm
@@ -0,0 +1,68 @@
+/datum/action/innate/clockcult
+ button_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/actions_clock.dmi'
+ background_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/background_clock.dmi'
+ background_icon_state = "bg_clock"
+ check_flags = AB_CHECK_HANDS_BLOCKED|AB_CHECK_IMMOBILE|AB_CHECK_CONSCIOUS
+
+/datum/action/innate/clockcult/quick_bind
+ name = "Quick Bind"
+ button_icon_state = "telerune"
+ desc = "A quick bound spell."
+ /// Weakref to the relevant slab
+ var/datum/weakref/slab_weakref
+ /// Ref to the relevant scripture
+ var/datum/scripture/scripture
+
+/datum/action/innate/clockcult/quick_bind/Destroy()
+ scripture = null
+ return ..()
+
+/datum/action/innate/clockcult/quick_bind/Grant(mob/living/recieving_mob)
+ name = scripture.name
+ desc = scripture.tip
+ button_icon_state = scripture.button_icon_state
+ if(scripture.power_cost)
+ desc += "
Draws [scripture.power_cost]W from the ark per use."
+ return ..(recieving_mob)
+
+/datum/action/innate/clockcult/quick_bind/Remove(mob/losing_mob)
+ var/obj/item/clockwork/clockwork_slab/activation_slab = slab_weakref.resolve()
+ if(activation_slab.invoking_scripture == scripture)
+ activation_slab.invoking_scripture = null
+ return ..(losing_mob)
+
+/datum/action/innate/clockcult/quick_bind/IsAvailable(feedback)
+ if(!IS_CLOCK(owner) || HAS_TRAIT(owner, TRAIT_INCAPACITATED))
+ return FALSE
+ return ..()
+
+/datum/action/innate/clockcult/quick_bind/Activate()
+ if(!slab_weakref)
+ return
+
+ var/obj/item/clockwork/clockwork_slab/activation_slab = slab_weakref.resolve()
+ if(!activation_slab.invoking_scripture)
+ scripture.begin_invoke(owner, activation_slab)
+ else
+ to_chat(owner, span_brass("You fail to invoke [name]."))
+
+/datum/action/item_action/toggle/clock
+ background_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/background_clock.dmi'
+ background_icon_state = "bg_clock"
+
+/datum/action/cooldown/clock_cult
+ button_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/actions_clock.dmi'
+ background_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/background_clock.dmi'
+ background_icon_state = "bg_clock"
+
+/datum/action/cooldown/clock_cult/IsAvailable(feedback)
+ return IS_CLOCK(owner) && ..()
+
+/datum/action/cooldown/clock_cult/eminence
+
+/datum/action/cooldown/clock_cult/eminence/Activate(atom/target)
+ . = ..()
+ if(!iseminence(usr))
+ to_chat(usr, span_boldwarning("You are not an eminence and should not have this! Please report this as a bug."))
+ return FALSE
+ return TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/add_warp_area.dm b/tff_modular/modules/antagonists/clock_cult/actions/add_warp_area.dm
new file mode 100644
index 00000000000..f368f835076
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/add_warp_area.dm
@@ -0,0 +1,98 @@
+///How many areas are observation consoles able to warp to at the start
+#define STARTING_WARP_AREAS 8
+///how much vitality does each already marked area increase the cost by
+#define COST_PER_AREA 4
+
+/datum/action/innate/clockcult/add_warp_area
+ name = "Add Warp Area"
+ desc = "Add an additional area observation consoles can warp to."
+ button_icon_state = "Spatial Warp"
+ ///a cache of areas we can are to the warpable list
+ var/static/list/cached_addable_areas //rename this to markable areas
+ ///what area types are we blocked from warping to
+ var/static/list/blocked_areas = typecacheof(list(/area/station/service/chapel, /area/station/ai))
+ ///what area types cost double
+ var/static/list/costly_areas = typecacheof(list(/area/station/command, /area/station/security))
+
+/datum/action/innate/clockcult/add_warp_area/New(Target)
+ . = ..()
+ if(isnull(cached_addable_areas))
+ build_addable_areas()
+ choose_starting_warp_areas()
+
+/datum/action/innate/clockcult/add_warp_area/IsAvailable(feedback)
+ if(!IS_CLOCK(owner))
+ return FALSE
+ return ..()
+
+/datum/action/innate/clockcult/add_warp_area/Activate()
+ if(!length(cached_addable_areas))
+ return
+
+ var/area/input_area = tgui_input_list(owner, "Select an area to add.", "Add Area", cached_addable_areas)
+ if(!input_area)
+ return
+
+ var/cost = max((length(SSthe_ark.marked_areas) * COST_PER_AREA) - (STARTING_WARP_AREAS * COST_PER_AREA), 0)
+ if(is_type_in_typecache(input_area.type, costly_areas))
+ cost *= 2
+
+ if(tgui_alert(owner, "Are you sure you want to add [input_area]? It will cost [cost] vitality.", "Add Area", list("Yes", "No")) == "Yes")
+ if(GLOB.clock_vitality < cost)
+ to_chat(owner, span_brass("Not enough vitality."))
+ return
+
+ if(SSthe_ark.marked_areas[input_area])
+ return
+
+ SSthe_ark.marked_areas[input_area] = TRUE
+ cached_addable_areas -= input_area
+ send_clock_message(null, "[input_area] added to warpable areas.")
+
+/datum/action/innate/clockcult/add_warp_area/proc/choose_starting_warp_areas()
+ if(!length(cached_addable_areas))
+ return
+
+ if(!SSthe_ark.initialized)
+ SSthe_ark.Initialize()
+ //shuffle_inplace(cached_addable_areas) //this is so our picked maint areas are random without needing to do anything weird
+ var/sanity = 0
+ var/added_areas = 0
+ var/list/temp_list = cached_addable_areas.Copy()
+ while(added_areas < STARTING_WARP_AREAS && sanity < 100 && length(temp_list))
+ sanity++
+ /*if(i <= 2) //always give them 2 maint areas to hopefully be easy to warp from
+ var/area/station/maintenance/maint_area = locate() in cached_addable_areas
+ if(maint_area)
+ cached_addable_areas -= maint_area
+ SSthe_ark.marked_areas += maint_area
+ continue*/ //for if I implement abscond restrictions
+ var/area/picked_area = pick(temp_list)
+ temp_list -= picked_area
+ if(is_type_in_typecache(picked_area.type, costly_areas))
+ continue
+
+ added_areas++
+ SSthe_ark.marked_areas[picked_area] = TRUE
+ cached_addable_areas -= picked_area
+
+/datum/action/innate/clockcult/add_warp_area/proc/build_addable_areas()
+ cached_addable_areas = list()
+ for(var/area/station_area as anything in GLOB.the_station_areas)
+ station_area = GLOB.areas_by_type[station_area]
+ if(station_area.outdoors || (station_area.area_flags & NOTELEPORT) || is_type_in_typecache(station_area, blocked_areas) || (SSthe_ark.marked_areas[station_area]))
+ continue
+ cached_addable_areas += station_area
+
+/datum/action/innate/clockcult/show_warpable_areas
+ name = "Warpable Areas"
+ desc = "Display what areas are currently warpable to by observation consoles."
+ button_icon_state = "console_info"
+
+/datum/action/innate/clockcult/show_warpable_areas/Activate()
+ if(!SSthe_ark.initialized)
+ SSthe_ark.Initialize()
+ to_chat(owner, boxed_message(span_brass("Current areas observation consoles can warp to: [english_list(SSthe_ark.marked_areas)]
\
+ You can add additional areas with the \"Add Warp Area\" action."))) //anyone who has this action should also have add warp area
+
+#undef STARTING_WARP_AREAS
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/clockmob_warp.dm b/tff_modular/modules/antagonists/clock_cult/actions/clockmob_warp.dm
new file mode 100644
index 00000000000..a9196861625
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/clockmob_warp.dm
@@ -0,0 +1,36 @@
+/datum/action/cooldown/clock_cult/clockmob_warp
+ name = "Clockwork Warp"
+ desc = "Warp to and from marked areas on the station and reebe."
+ cooldown_time = 30 SECONDS
+ button_icon_state = "warp_down"
+
+/datum/action/cooldown/clock_cult/clockmob_warp/Grant(mob/granted_to)
+ . = ..()
+ if(!on_reebe(granted_to))
+ button_icon_state = "Abscond"
+
+/datum/action/cooldown/clock_cult/clockmob_warp/Activate(atom/target)
+ var/turf/selected_turf
+ var/new_icon_state
+ if(on_reebe(owner))
+ if(!length(SSthe_ark.marked_areas))
+ return FALSE
+ var/area/selection = tgui_input_list(owner, "Where do you want to warp?", "Warping", SSthe_ark.marked_areas)
+ if(!isarea(selection))
+ return FALSE
+ selected_turf = pick(selection.get_turfs_from_all_zlevels())
+ new_icon_state = "Abscond"
+ else
+ if(!length(GLOB.abscond_markers))
+ return FALSE
+ selected_turf = get_turf(pick(GLOB.abscond_markers))
+ new_icon_state = "warp_down"
+
+ if(!selected_turf || !do_after(owner, cooldown_time, owner))
+ return FALSE
+
+ try_servant_warp(owner, selected_turf)
+ if(new_icon_state)
+ button_icon_state = new_icon_state
+ build_all_button_icons(UPDATE_BUTTON_ICON)
+ return ..()
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/basic_teleports.dm b/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/basic_teleports.dm
new file mode 100644
index 00000000000..62f16322c72
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/basic_teleports.dm
@@ -0,0 +1,18 @@
+/datum/action/innate/clockcult/teleport_to_station
+ name = "Teleport to Station"
+ desc = "Teleport to a random location on the station."
+ button_icon_state = "warp_down"
+
+/datum/action/innate/clockcult/teleport_to_station/Activate()
+ do_teleport(usr, pick(GLOB.station_turfs), 0, no_effects = TRUE, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
+ usr.playsound_local(get_turf(usr), 'sound/effects/magic/magic_missile.ogg', 50, TRUE, pressure_affected = FALSE)
+
+/datum/action/innate/clockcult/eminence_abscond
+ name = "Return to Reebe"
+ desc = "Teleport back to reebe."
+ button_icon_state = "Abscond"
+
+/datum/action/innate/clockcult/eminence_abscond/Activate()
+ do_teleport(usr, get_turf(pick(GLOB.abscond_markers)), 0, no_effects = TRUE, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
+ usr.playsound_local(get_turf(usr), 'sound/effects/magic/magic_missile.ogg', 50, TRUE, pressure_affected = FALSE)
+
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/linked_abscond.dm b/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/linked_abscond.dm
new file mode 100644
index 00000000000..9b0fa6c32a0
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/linked_abscond.dm
@@ -0,0 +1,33 @@
+/datum/action/cooldown/clock_cult/eminence/linked_abscond
+ name = "Linked Abscond"
+ desc = "Absconds a fellow servant and whomever they may be pulling back to reebe if they stand still for 7 seconds."
+ button_icon_state = "Linked Abscond"
+ cooldown_time = 4 MINUTES
+
+/datum/action/cooldown/clock_cult/eminence/linked_abscond/Activate(atom/target)
+ var/mob/living/eminence/em_user = usr
+ if(!em_user.marked_servant)
+ to_chat(em_user, span_notice("You dont currently have a marked servant!"))
+ return FALSE
+
+ var/mob/living/teleported = em_user.marked_servant?.resolve()
+ if(teleported.has_reagent(/datum/reagent/water/holywater)) //cant abscond servents with holy water in them, use reagent purge
+ to_chat(em_user, span_warning("Holy water inside [teleported] is blocking you from absconding them, use reagent purge!"))
+ return FALSE
+
+ . = ..()
+ if(!.)
+ return FALSE
+
+ to_chat(em_user, span_brass("You begin to recall [teleported]."))
+ to_chat(teleported, span_bigbrass("You are being recalled by the eminence."))
+ teleported.visible_message(span_warning("[teleported] flares briefly."))
+
+ if(!do_after(em_user, 7 SECONDS, teleported))
+ to_chat(em_user, span_warning("You fail to recall [teleported]."))
+ return FALSE
+ teleported.visible_message(span_warning("[teleported] phases out of existence!"))
+ try_servant_warp(teleported, get_turf(pick(GLOB.abscond_markers)))
+ to_chat(em_user, "You recall [teleported].")
+ em_user.marked_servant = null
+ return TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/teleport_to_servant.dm b/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/teleport_to_servant.dm
new file mode 100644
index 00000000000..6cf82eb4697
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/emience_teleports/teleport_to_servant.dm
@@ -0,0 +1,21 @@
+/datum/action/innate/clockcult/teleport_to_servant
+ name = "Teleport to Servant"
+ desc = "Teleport yourself to a fellow servant."
+ button_icon_state = "clockwork_armor"
+
+/datum/action/innate/clockcult/teleport_to_servant/Activate(mob/living/user = usr)
+ var/datum/antagonist/clock_cultist/servant = user.mind.has_antag_datum(/datum/antagonist/clock_cultist)
+ if(!servant?.clock_team)
+ return
+
+ var/list/given_list = list()
+ for(var/datum/mind/servant_mind in servant.clock_team.members)
+ given_list += servant_mind.current
+ given_list -= usr
+ if(!given_list.len)
+ return
+
+ var/mob/living/input_servant = tgui_input_list(usr, "Choosen a servant", "Servants", given_list)
+ do_teleport(usr, get_turf(input_servant), 0, no_effects = TRUE, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
+ usr.playsound_local(get_turf(usr), 'sound/effects/magic/magic_missile.ogg', 50, TRUE, pressure_affected = FALSE)
+ to_chat(usr, "You warp to [input_servant].")
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/purge_reagents.dm b/tff_modular/modules/antagonists/clock_cult/actions/purge_reagents.dm
new file mode 100644
index 00000000000..99169ad9060
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/purge_reagents.dm
@@ -0,0 +1,29 @@
+/datum/action/cooldown/clock_cult/eminence/purge_reagents
+ name = "Purge Reagents"
+ desc = "Purges all reagents from the bloodstream of a marked servant, useful for if they have been given holy water."
+ button_icon_state = "Mending Mantra"
+ cooldown_time = 30 SECONDS
+
+/datum/action/cooldown/clock_cult/eminence/purge_reagents/Activate(atom/target)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ var/mob/living/eminence/em_user = usr
+ var/mob/living/purged = WEAKREF_NULL_IF_UNRESOLVED(em_user.marked_servant, purged)
+ if(!purged)
+ to_chat(em_user, span_notice("You dont currently have a marked servant!"))
+ return FALSE
+
+ var/did_purge = FALSE
+ for(var/datum/reagent/chem in purged.reagents?.reagent_list)
+ purged.reagents.remove_reagent(chem.type, chem.volume)
+ did_purge = TRUE
+
+ em_user.marked_servant = null
+ if(!did_purge)
+ to_chat(em_user, span_notice("[purged] does not have any reagents to purge."))
+ return FALSE
+
+ to_chat(em_user, "You purge the reagents of [purged].")
+ return TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/recall_slab.dm b/tff_modular/modules/antagonists/clock_cult/actions/recall_slab.dm
new file mode 100644
index 00000000000..f67d571be10
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/recall_slab.dm
@@ -0,0 +1,102 @@
+/datum/action/innate/clockcult/recall_slab
+ name = "Recall Slab"
+ desc = "Recall your latest used Clockwork Slab from anywhere in the universe."
+ button_icon_state = "Replicant"
+
+ ///The slab marked for recall
+ var/obj/item/clockwork/clockwork_slab/marked_slab
+
+/// Set the passed object as our marked item
+/datum/action/innate/clockcult/recall_slab/proc/mark_item(obj/to_mark)
+ marked_slab = to_mark
+ RegisterSignal(marked_slab, COMSIG_QDELETING, PROC_REF(on_marked_item_deleted))
+
+/// Unset our current marked item
+/datum/action/innate/clockcult/recall_slab/proc/unmark_item()
+ if(!marked_slab)
+ return
+
+ UnregisterSignal(marked_slab, COMSIG_QDELETING)
+ marked_slab = null
+
+/// Signal proc for COMSIG_QDELETING on our marked item, unmarks our item if it's deleted
+/datum/action/innate/clockcult/recall_slab/proc/on_marked_item_deleted(datum/source)
+ SIGNAL_HANDLER
+
+ if(owner)
+ to_chat(owner, span_boldwarning("You sense your Clockwork Slab has been destroyed!"))
+
+ unmark_item()
+
+/datum/action/innate/clockcult/recall_slab/Activate()
+ try_recall_item()
+
+/// Recalls our marked item to the caster. May bring some unexpected things along.
+/datum/action/innate/clockcult/recall_slab/proc/try_recall_item()
+ var/obj/item_to_retrieve = marked_slab
+
+ if(!item_to_retrieve)
+ to_chat(usr, span_brass("You don't have a slab attuned!"))
+ return
+
+ if(!item_to_retrieve.loc)
+ return
+
+ // just being safe
+ var/infinite_recursion = 0
+
+ // if it's in something, you get the whole thing.
+ while(!isturf(item_to_retrieve.loc) && infinite_recursion < 10)
+ if(isitem(item_to_retrieve.loc))
+ var/obj/item/mark_loc = item_to_retrieve.loc
+ // Being able to summon abstract things because
+ // your item happened to get placed there is a no-no
+ if(mark_loc.item_flags & ABSTRACT)
+ break
+
+ // If its on someone, properly drop it
+ if(ismob(item_to_retrieve.loc))
+ var/mob/holding_mark = item_to_retrieve.loc
+
+ // Items in silicons warp the whole silicon
+ if(issilicon(holding_mark))
+ holding_mark.loc.visible_message(span_warning("[holding_mark] suddenly disappears!"))
+ holding_mark.forceMove(usr.loc)
+ holding_mark.loc.visible_message(span_warning("[holding_mark] suddenly appears!"))
+ item_to_retrieve = null
+ break
+
+ SEND_SIGNAL(holding_mark, COMSIG_MAGIC_RECALL, usr, item_to_retrieve)
+ holding_mark.dropItemToGround(item_to_retrieve)
+
+ else if(isobj(item_to_retrieve.loc))
+ var/obj/retrieved_item = item_to_retrieve.loc
+ // Can't bring anchored things
+ if(retrieved_item.anchored)
+ break
+
+ // Edge cases for moving certain machinery...
+ if(istype(retrieved_item, /obj/machinery/portable_atmospherics))
+ var/obj/machinery/portable_atmospherics/atmos_item = retrieved_item
+ atmos_item.disconnect()
+ atmos_item.update_appearance()
+
+ // Otherwise bring the whole thing with us
+ item_to_retrieve = retrieved_item
+
+ infinite_recursion += 1
+
+ if(!item_to_retrieve)
+ return
+
+ item_to_retrieve.loc?.visible_message(span_warning("[item_to_retrieve] suddenly disappears!"))
+
+ if(isitem(item_to_retrieve) && usr.put_in_hands(item_to_retrieve))
+ var/obj/item/typed_item = item_to_retrieve
+ typed_item.pickup(usr) //might be good to standardize this being on put_in_hands()
+ item_to_retrieve.loc.visible_message(span_warning("[item_to_retrieve] suddenly appears in [usr]'s hand!"))
+ else
+ item_to_retrieve.forceMove(usr.drop_location())
+ item_to_retrieve.loc.visible_message(span_warning("[item_to_retrieve] suddenly appears!"))
+
+ playsound(get_turf(item_to_retrieve), 'sound/effects/magic/summonitems_generic.ogg', 50, TRUE)
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/space_fold.dm b/tff_modular/modules/antagonists/clock_cult/actions/space_fold.dm
new file mode 100644
index 00000000000..86edbaf4e0c
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/space_fold.dm
@@ -0,0 +1,98 @@
+///list of events eminence can trigger as well as their cost in cogs, most likely gonna have to set limits on these, might do it based on cost, unsure if I should use a .txt for this
+#define EMINENCE_EVENTS list( \
+ /datum/round_event_control/brand_intelligence = 5, \
+ /datum/round_event_control/bureaucratic_error = 3, \
+ /datum/round_event_control/gravity_generator_blackout = 4, \
+ /datum/round_event_control/communications_blackout = 6, \
+ /datum/round_event_control/electrical_storm = 2, \
+ /datum/round_event_control/ion_storm = 6, \
+ /datum/round_event_control/grey_tide = 3, \
+ /datum/round_event_control/grid_check = 6, \
+ /datum/round_event_control/scrubber_overflow/catastrophic = 4, \
+ /datum/round_event_control/radiation_storm = 8, \
+ /datum/round_event_control/carp_migration = 6, \
+ /datum/round_event_control/wormholes = 6, \
+ /datum/round_event_control/immovable_rod = 9, \
+ /datum/round_event_control/anomaly/anomaly_dimensional = 2, \
+ /datum/round_event_control/anomaly/anomaly_bluespace = 4, \
+ /datum/round_event_control/anomaly/anomaly_ectoplasm = 4, \
+ /datum/round_event_control/anomaly/anomaly_flux = 3, \
+ /datum/round_event_control/anomaly/anomaly_pyro = 5, \
+)
+
+/datum/action/innate/clockcult/space_fold
+ name = "Space Fold"
+ button_icon_state = "Geis"
+ desc = "Fold local space so that certain \"events\" befall the station. The amount you may create depends on how many APCs the cult has cogged. \
+ Doing so will also cost charges which will regenerate at a rate of one per minute."
+ ///list used for tracking what events have been trigged so far, also used for restricting how many times an event can trigger
+ var/list/used_event_list = list()
+ ///instead of a cooldown this has a charge system, one charge regenerates every mintue, each event costs charges equal to its cog cost
+ var/charges = 10
+ ///the static list of events we have access to
+ var/static/list/event_list
+ ///cooldown declare for charge cooldown
+ COOLDOWN_DECLARE(charge_cooldown)
+
+/datum/action/innate/clockcult/space_fold/New(Target)
+ . = ..()
+ if(isnull(event_list))
+ event_list = list()
+ var/list/temp = EMINENCE_EVENTS
+ for(var/datum/round_event_control/entry as anything in SSevents.control)
+ if(entry.type in temp)
+ event_list[entry] = temp[entry.type]
+
+/datum/action/innate/clockcult/space_fold/Grant(mob/grant_to)
+ . = ..()
+ START_PROCESSING(SSfastprocess, src)
+ COOLDOWN_START(src, charge_cooldown, 1 SECONDS)
+
+/datum/action/innate/clockcult/space_fold/Destroy()
+ . = ..()
+ STOP_PROCESSING(SSfastprocess, src)
+
+/datum/action/innate/clockcult/space_fold/process(seconds_per_tick)
+ if(COOLDOWN_FINISHED(src, charge_cooldown))
+ charges++
+ COOLDOWN_START(src, charge_cooldown, 1 MINUTES)
+
+ if(charges >= initial(charges))
+ STOP_PROCESSING(SSfastprocess, src)
+ return
+
+/datum/action/innate/clockcult/space_fold/Activate()
+ var/datum/round_event_control/chosen_event = tgui_input_list(usr, "Choose an event", "[charges] [charges == 1 ? "charge" : "charges"] remaining", event_list)
+ if(isnull(chosen_event) || isnull(event_list[chosen_event]))
+ return FALSE
+
+ if(used_event_list[chosen_event] && (event_list[chosen_event] >= 4 || used_event_list[chosen_event] >= 4)) //events with 4+ cost can be used once, 3 and below can be used 4 times
+ to_chat(usr, span_warning("You have summoned this event too many times to do so again!"))
+ return FALSE
+
+ switch(tgui_alert(usr, "Are you sure you want to summon this event? It will cost [event_list[chosen_event]] cogs.", "Confirm summon", list("Yes", "No")))
+ if("No")
+ return FALSE
+ if("Yes")
+ var/actual_cost = event_list[chosen_event]
+ if(GLOB.clock_ark && GLOB.clock_ark.current_state >= ARK_STATE_CHARGING)
+ actual_cost *= 2 //events cost double after ark activation
+ if(charges < actual_cost)
+ to_chat(usr, span_warning("You dont have enough charges to summon this event"))
+ return FALSE
+ if(istype(usr, /mob/living/eminence)) //if you somehow get this as non-eminence its technically free besides charges
+ var/mob/living/eminence/em_user = usr
+ if(em_user.cogs < actual_cost)
+ to_chat(em_user, span_warning("You dont have enough cogs to do this!"))
+ return
+ em_user.cogs -= actual_cost
+ chosen_event.run_event(event_cause = "an emience folding spacetime")
+ charges -= actual_cost
+ if(charges + event_list[chosen_event] >= initial(charges)) //if charges was full then start processing
+ START_PROCESSING(SSfastprocess, src)
+ COOLDOWN_START(src, charge_cooldown, 1 MINUTES)
+ used_event_list[chosen_event] = used_event_list[chosen_event] + 1
+ return TRUE
+ return FALSE
+
+#undef EMINENCE_EVENTS
diff --git a/tff_modular/modules/antagonists/clock_cult/actions/whirring_convergence.dm b/tff_modular/modules/antagonists/clock_cult/actions/whirring_convergence.dm
new file mode 100644
index 00000000000..46c17d91e7f
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/actions/whirring_convergence.dm
@@ -0,0 +1,68 @@
+/*
+* Whirring Convergence
+* Communicate a message to all other clock cultists
+*/
+/datum/action/innate/clockcult/comm
+ name = "Whirring Convergence"
+ desc = "Whispered words that link to the internal cogs of us all.
Warning: Nearby non-servants can still hear you."
+ button_icon_state = "linked_minds"
+ check_flags = AB_CHECK_CONSCIOUS
+
+/datum/action/innate/clockcult/comm/Activate()
+ var/input = tgui_input_text(usr, "Message to tell to the other followers.", "Voice of Cogs")
+ if(!input || !IsAvailable())
+ return
+
+ var/list/filter_result = CAN_BYPASS_FILTER(usr) ? null : is_ic_filtered(input)
+ if(filter_result)
+ REPORT_CHAT_FILTER_TO_USER(usr, filter_result)
+ return
+
+ var/list/soft_filter_result = CAN_BYPASS_FILTER(usr) ? null : is_soft_ic_filtered(input)
+ if(soft_filter_result)
+
+ if(tgui_alert(usr,"Your message contains \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[soft_filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to say it?", "Soft Blocked Word", list("Yes", "No")) != "Yes")
+ return
+ message_admins("[ADMIN_LOOKUPFLW(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Message: \"[html_encode(input)]\"")
+ log_admin_private("[key_name(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Message: \"[input]\"")
+
+ cultist_commune(usr, input)
+
+/// A user can input a message to send to other clock cultists over the clock cult communication channel
+/datum/action/innate/clockcult/comm/proc/cultist_commune(mob/living/user, message)
+ if(!message)
+ return
+
+ user.whisper("Engine, V vaibxr gb-gur`r gb-pbzzhar gb-nyy.", language = /datum/language/common) //Ratvar, I invoke to-the`e to-commune to-all.
+ user.whisper(html_decode(message), filterproof = TRUE)
+ send_clock_message(user, message)
+
+/// Send `sent_message` to all other clock cultists and ghosts from the user
+/proc/send_clock_message(mob/living/user, sent_message, span = "", msg_ghosts = TRUE, sent_sound)
+ var/final_message = ""
+ if(user && istype(user, /mob/living/eminence))
+ final_message = span + span_bigbrass("Master Eminence transmits, \"") + sent_message + span_bigbrass("\"")
+ else if(user)
+ var/pronoun_phrase = "sibling"
+ if(user.gender == FEMALE)
+ pronoun_phrase = "sister"
+ else if(user.gender == MALE)
+ pronoun_phrase = "brother"
+ final_message = span + "Clock[pronoun_phrase] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"] transmits, \"" + sent_message + "\""
+ else
+ final_message = span + sent_message + ""
+
+ for(var/mob/player_mob as anything in GLOB.player_list)
+
+ if(IS_CLOCK(player_mob))
+ to_chat(player_mob, final_message)
+ if(sent_sound)
+ SEND_SOUND(player_mob, sent_sound)
+
+ else if(player_mob in GLOB.dead_mob_list)
+ if(!msg_ghosts)
+ continue
+ if(user)
+ to_chat(player_mob, "[FOLLOW_LINK(player_mob, user)] [final_message]")
+ else
+ to_chat(player_mob, final_message)
diff --git a/tff_modular/modules/antagonists/clock_cult/antag_datums/clock_cult_team.dm b/tff_modular/modules/antagonists/clock_cult/antag_datums/clock_cult_team.dm
new file mode 100644
index 00000000000..3afec853c01
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/antag_datums/clock_cult_team.dm
@@ -0,0 +1,168 @@
+GLOBAL_DATUM(main_clock_cult, /datum/team/clock_cult)
+
+#define DEFAULT_MAX_HUMAN_SERVANTS 8
+#define CONVERSION_WARNING_NONE 0
+#define CONVERSION_WARNING_HALFWAY 1
+#define CONVERSION_WARNING_THREEQUARTERS 2
+#define CONVERSION_WARNING_CRITIAL 3
+/datum/team/clock_cult
+ name = "Clock Cult"
+ /// maximum number of human servants we can have
+ var/max_human_servants = DEFAULT_MAX_HUMAN_SERVANTS
+ /// list of our human servants
+ var/list/human_servants = list()
+ /// list of our non-human servants
+ var/list/non_human_servants = list()
+ /// what warning stage are we at
+ var/warning_stage = CONVERSION_WARNING_NONE
+ /// have we used our recall
+ var/member_recalled = FALSE
+
+/datum/team/clock_cult/add_member(datum/mind/new_member)
+ . = ..()
+ var/mob/current_mob = new_member.current
+ if(current_mob && ishuman(current_mob))
+ human_servants |= new_member
+ else
+ non_human_servants |= new_member
+
+ check_member_count()
+
+/datum/team/clock_cult/remove_member(datum/mind/member)
+ . = ..()
+ if(member in human_servants)
+ human_servants -= member
+ else
+ non_human_servants -= member
+
+/datum/team/clock_cult/roundend_report()
+ var/list/parts = list()
+ var/list/checked_objectives = list()
+ var/failure = FALSE
+ if(length(objectives))
+ var/count = 1
+ for(var/datum/objective/objective in objectives)
+ if(objective.check_completion())
+ checked_objectives += "Objective #[count]: [objective.explanation_text] [span_greentext("Success!")]"
+ else
+ checked_objectives += "Objective #[count]: [objective.explanation_text] [span_redtext("Fail.")]"
+ failure = TRUE
+ count++
+
+ if(failure)
+ parts += "The clock cult has failed to protect the ark and summon Ratvar, he will remain forever trapped!"
+ else
+ parts += "The clock cult has succeeded! Ratvar's light shall shine forever more!"
+
+ if(length(checked_objectives))
+ parts += "The clock cultists' objectives were:"
+ for(var/i in 1 to length(checked_objectives))
+ parts += checked_objectives[i]
+
+ if(length(members))
+ parts += ""
+ parts += printplayerlist(members)
+
+ return "
[parts.Join("
")]
"
+
+///check how many human members we have and anything that goes with that
+/datum/team/clock_cult/proc/check_member_count()
+ check_member_distribution()
+ max_human_servants = round(max((get_active_player_count() / 7) + 1, max_human_servants))
+ var/human_servant_count = length(human_servants)
+ var/main_message = "The Ark will be torn open if [max_human_servants - human_servant_count] more minds are converted to the faith of Ratvar\
+ [SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON ? "." : " and \
+ [ANCHORING_CRYSTALS_TO_SUMMON] Anchoring Crystal[ANCHORING_CRYSTALS_TO_SUMMON > 1 ? "s are" : " is"] summoned and protected on the station."]"
+
+ if((human_servant_count * 2) > max_human_servants && warning_stage < CONVERSION_WARNING_HALFWAY)
+ send_clock_message(null, span_bigbrass("Ratvar's influence is growing. [main_message]"), sent_sound = 'modular_nova/modules/clock_cult/sound/magic/scripture_tier_up.ogg')
+ warning_stage = CONVERSION_WARNING_HALFWAY
+
+ else if(human_servant_count > ((3/4) * max_human_servants) && warning_stage < CONVERSION_WARNING_THREEQUARTERS)
+ send_clock_message(null, span_bigbrass("You feel the boundary between reality and fiction lessen as the Ark sparks with an arcane energy.
[main_message]"), \
+ sent_sound = 'modular_nova/modules/clock_cult/sound/magic/scripture_tier_up.ogg')
+ warning_stage = CONVERSION_WARNING_THREEQUARTERS
+
+ else if((human_servant_count == max_human_servants - 1) && warning_stage < CONVERSION_WARNING_CRITIAL && SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON)
+ send_clock_message(span_bigbrass("The internal cogs of the Ark begin spinning, ready for activation.
\
+ Upon the next conversion, the dimensional barrier will become too weak for The Ark to remain closed and it will be forced open."), \
+ sent_sound = 'modular_nova/modules/clock_cult/sound/magic/scripture_tier_up.ogg')
+ warning_stage = CONVERSION_WARNING_CRITIAL
+
+ else if((human_servant_count >= max_human_servants) && SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON)
+ GLOB.clock_ark?.prepare_ark()
+
+///check that our human_servants and non_human_servants lists are correct and if not then set them to be correct
+/datum/team/clock_cult/proc/check_member_distribution()
+ for(var/datum/mind/member in human_servants)
+ if(ishuman(member.current))
+ continue
+ human_servants -= member
+ non_human_servants |= member
+ var/datum/antagonist/clock_cultist/servant_datum = member.has_antag_datum(/datum/antagonist/clock_cultist)
+ servant_datum.recall.Remove(member.current)
+
+ for(var/datum/mind/member in non_human_servants)
+ if(!ishuman(member))
+ continue
+ non_human_servants -= member
+ human_servants |= member
+ var/datum/antagonist/clock_cultist/servant_datum = member.has_antag_datum(/datum/antagonist/clock_cultist)
+ servant_datum.recall.Grant(member.current)
+
+/datum/team/clock_cult/proc/setup_objectives()
+ if(length(objectives))
+ return
+ GLOB.main_clock_cult = src
+ var/datum/objective/anchoring_crystals/crystals_objective = new
+ crystals_objective.team = src
+ objectives += crystals_objective
+
+ var/datum/objective/ratvar/summon_objective = new
+ summon_objective.team = src
+ objectives += summon_objective
+
+#undef DEFAULT_MAX_HUMAN_SERVANTS
+#undef CONVERSION_WARNING_NONE
+#undef CONVERSION_WARNING_HALFWAY
+#undef CONVERSION_WARNING_THREEQUARTERS
+#undef CONVERSION_WARNING_CRITIAL
+
+#define POSSIBLE_CRYSTAL_AREAS 6
+/datum/objective/anchoring_crystals
+
+/datum/objective/anchoring_crystals/New()
+ . = ..()
+ if(SSthe_ark.valid_crystal_areas)
+ return
+
+ SSthe_ark.valid_crystal_areas = list()
+ var/sanity = 0
+ var/list/areas_copy = GLOB.areas.Copy()
+ while(length(SSthe_ark.valid_crystal_areas) < POSSIBLE_CRYSTAL_AREAS && sanity < 100)
+ var/area/summon_area = pick_n_take(areas_copy)
+ if(summon_area && is_station_level(summon_area.z) && (summon_area.area_flags & VALID_TERRITORY))
+ SSthe_ark.valid_crystal_areas[summon_area] = summon_area.get_original_area_name()
+ sanity++
+ update_explanation_text()
+
+/datum/objective/anchoring_crystals/update_explanation_text()
+ var/plural = ANCHORING_CRYSTALS_TO_SUMMON > 1
+ var/list/names = list()
+ for(var/area/valid_area in SSthe_ark.valid_crystal_areas)
+ names += SSthe_ark.valid_crystal_areas[valid_area]
+
+ explanation_text = "Summon [ANCHORING_CRYSTALS_TO_SUMMON] anchoring crystal[plural ? "s" : ""] on the station and protect [plural ? "them" : "it"] for \
+ [DisplayTimeText(ANCHORING_CRYSTAL_CHARGE_DURATION)] to allow the ark to open. \
+ Crystals after the first one must be summoned in [english_list(names)]. Up to 2 additional crystals can be created for extra power."
+
+/datum/objective/anchoring_crystals/check_completion()
+ return SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON || completed
+
+/datum/objective/ratvar
+ explanation_text = "Protect The Ark so that Ratvar may enlighten this world!"
+
+/datum/objective/ratvar/check_completion()
+ return GLOB.ratvar_risen || completed
+
+#undef POSSIBLE_CRYSTAL_AREAS
diff --git a/tff_modular/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm b/tff_modular/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm
new file mode 100644
index 00000000000..07f7722d85c
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm
@@ -0,0 +1,248 @@
+/datum/antagonist/clock_cultist
+ name = "\improper Servant of Ratvar"
+ antagpanel_category = "Clock Cultist"
+ preview_outfit = /datum/outfit/clock/preview
+ pref_flag = ROLE_ROUNDSTART_CLOCK_CULTIST
+ antag_moodlet = /datum/mood_event/cult
+ suicide_cry = ",r For Ratvar!!!"
+ ui_name = "AntagInfoClockAlt"
+ show_to_ghosts = TRUE
+ hud_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/hud.dmi'
+ antag_hud_name = "clockwork"
+ stinger_sound = 'modular_nova/modules/clock_cult/sound/magic/scripture_tier_up.ogg'
+ /// Ref to the cultist's communication ability
+ var/datum/action/innate/clockcult/comm/communicate = new
+ /// Ref to the cultist's slab recall ability
+ var/datum/action/innate/clockcult/recall_slab/recall = new
+ ///our cult team
+ var/datum/team/clock_cult/clock_team
+ ///should we directly give them a slab or not
+ var/give_slab = TRUE
+ ///ref to our turf_healing component, used for deletion when deconverted
+ var/datum/component/turf_healing/owner_turf_healing
+ ///used for holy water deconversion, slightly easier to have this here then on the team, might want to refactor this to an assoc global list
+ var/static/list/servant_deconversion_phrases = list("spoken" = list("VG OHEAF!", "SBE GUR TYBEL-BS ENGINE!", "Gur yvtug jvyy fuvar.", "Whfgv`pne fnir zr.", "Gur Nex zhfg abg snyy.",
+ "Rzvarapr V pnyy gur`r!", "Lbh frr bayl qnexarff.", "Guv`f vf abg gur raq.", "Gv`px, Gbpx"),
+
+ "seizure" = list("Your failure shall not delay my freedom.", "The blind will see only darkness.",
+ "Then my ark will feed upon your vitality.", "Do not forget your servitude."))
+
+/datum/antagonist/clock_cultist/Destroy()
+ QDEL_NULL(communicate)
+ QDEL_NULL(recall)
+ return ..()
+
+/datum/antagonist/clock_cultist/on_gain()
+ var/mob/living/current = owner.current
+ objectives |= clock_team.objectives
+ if(give_slab && ishuman(current))
+ give_clockwork_slab(current)
+ current.log_message("has been converted to the cult of Ratvar!", LOG_ATTACK, color="#960000")
+ if(issilicon(current))
+ handle_silicon_conversion(current)
+ . = ..() //have to call down here so objectives display correctly
+ ADD_TRAIT(owner, TRAIT_MAGICALLY_GIFTED, REF(src))
+
+/datum/antagonist/clock_cultist/greet()
+ . = ..()
+ to_chat(owner.current, span_clockyellow("HEY"))
+ to_chat(owner.current, span_boldwarning("Dont forget, your structures are by default off and must be clicked on to be turned on. Structures that are turned on have passive power use."))
+ to_chat(owner.current, span_boldwarning("YOUR CLOCKWORK SLAB UI HAS A MORE IN DEPTH GUIDE IN ITS BOTTOM RIGHT HAND SIDE. \
+ YOU CAN HOVER YOUR MOUSE POINTER OVER SCRIPTURE BUTTONS FOR EXTRA INFO."))
+
+///Returns whether the given mob is convertable to the blood cult
+/proc/is_convertable_to_clock(mob/living/target)
+ if(!target.mind)
+ return FALSE
+ return TRUE
+
+//given_clock_team is provided by conversion methods, although we never use it due to wanting to just set their team to the main clock cult
+/datum/antagonist/clock_cultist/create_team(datum/team/clock_cult/given_clock_team)
+ spawn_reebe()
+ if(!given_clock_team)
+ if(GLOB.main_clock_cult)
+ clock_team = GLOB.main_clock_cult
+ return
+ clock_team = new /datum/team/clock_cult
+ clock_team.setup_objectives()
+ return
+
+ if(!istype(given_clock_team))
+ stack_trace("Wrong team type passed to [type] initialization.")
+ clock_team = given_clock_team
+
+/datum/antagonist/clock_cultist/get_team()
+ return clock_team
+
+/datum/antagonist/clock_cultist/apply_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current = owner.current || mob_override
+ current.add_faction(FACTION_CLOCK)
+ current.grant_language(/datum/language/ratvar, source = LANGUAGE_CULTIST)
+ current.throw_alert("clockinfo", /atom/movable/screen/alert/clockwork/clocksense)
+ if(!iseminence(current))
+ add_team_hud(current)
+ communicate.Grant(current)
+ if(ishuman(current) || iscogscarab(current)) //only human and cogscarabs would need a recall ability
+ recall.Grant(current)
+ owner_turf_healing = current.AddComponent(/datum/component/turf_healing, healing_types = list(TOX = 1.5, BRUTE = 1.5, BURN = 1.5, STAMINA = 5, OXY = 1.5), healing_turfs = GLOB.clock_turf_types)
+ RegisterSignal(current, COMSIG_CLOCKWORK_SLAB_USED, PROC_REF(switch_recall_slab))
+ handle_clown_mutation(current, mob_override ? null : "The light of Ratvar allows you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
+ add_forbearance(current)
+
+/datum/antagonist/clock_cultist/remove_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current = owner.current
+ current.remove_faction(FACTION_CLOCK)
+ current.remove_language(/datum/language/ratvar, source = LANGUAGE_CULTIST)
+ current.clear_alert("clockinfo")
+ current.remove_filter("forbearance")
+ if(!iseminence(current))
+ communicate.Remove(current)
+ recall.Remove(current)
+ UnregisterSignal(current, COMSIG_CLOCKWORK_SLAB_USED)
+ QDEL_NULL(owner_turf_healing)
+ handle_clown_mutation(current, removing = FALSE)
+
+/datum/antagonist/clock_cultist/ui_data(mob/user)
+ var/list/data = list()
+ data["marked_areas"] = english_list(SSthe_ark.marked_areas)
+ return data
+
+/datum/antagonist/clock_cultist/can_be_owned(datum/mind/new_owner)
+ if(!is_convertable_to_clock(new_owner.current))
+ return FALSE
+ return ..()
+
+/datum/antagonist/clock_cultist/on_removal()
+ if(!silent)
+ owner.current.visible_message(span_deconversion_message("[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!"), \
+ span_userdanger("As the ticking fades from the back of your mind, you forget all memories you had as a servant of Ratvar."))
+ owner.current.log_message("has renounced the cult of Ratvar!", LOG_ATTACK, color="#960000")
+ handle_equipment_removal()
+ REMOVE_TRAIT(owner, TRAIT_MAGICALLY_GIFTED, REF(src))
+ return ..()
+
+/datum/antagonist/clock_cultist/get_preview_icon()
+ var/datum/universal_icon/final_icon = render_preview_outfit(preview_outfit)
+ return finish_preview_icon(final_icon)
+
+/datum/antagonist/clock_cultist/on_mindshield(mob/implanter)
+ if(!silent)
+ to_chat(owner.current, span_warning("You feel something pushing away the light of Ratvar, but you resist it!"))
+ return
+
+/datum/antagonist/clock_cultist/admin_add(datum/mind/new_owner,mob/admin)
+ new_owner.add_antag_datum(src)
+ message_admins("[key_name_admin(admin)] has made [key_name_admin(new_owner)] into a servant of Ratvar.")
+ log_admin("[key_name(admin)] has made [key_name(new_owner)] into a servant of Ratvar.")
+
+/datum/antagonist/clock_cultist/admin_remove(mob/user)
+ silent = TRUE
+ return ..()
+
+/datum/antagonist/clock_cultist/get_admin_commands()
+ . = ..()
+ .["Give Slab"] = CALLBACK(src, PROC_REF(admin_give_slab))
+ .["Remove Slab"] = CALLBACK(src, PROC_REF(admin_take_slab))
+
+/datum/antagonist/clock_cultist/proc/admin_take_slab(mob/admin)
+ var/mob/living/current = owner.current
+ for(var/object in current.get_all_contents())
+ if(istype(object, /obj/item/clockwork/clockwork_slab))
+ qdel(object)
+
+/datum/antagonist/clock_cultist/proc/admin_give_slab(mob/admin)
+ if(!give_clockwork_slab(owner.current))
+ to_chat(admin, span_danger("Spawning clockwork slab failed!"))
+
+//give a mob a slab directly into their inventory
+/datum/antagonist/clock_cultist/proc/give_clockwork_slab(mob/living/carbon/human/give_to)
+ var/obj/item/clockwork/clockwork_slab/created_slab = new
+ give_item_to_holder(created_slab, list(LOCATION_BACKPACK = ITEM_SLOT_BACK, LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, LOCATION_LPOCKET = ITEM_SLOT_LPOCKET))
+
+/datum/antagonist/clock_cultist/proc/give_item_to_holder(obj/item/clockwork/clockwork_slab/created_slab, list/valid_slots)
+ if(ispath(created_slab))
+ created_slab = new created_slab(get_turf(owner.current))
+
+ var/mob/living/carbon/human/human_holder = owner.current
+
+ human_holder.equip_in_one_of_slots(created_slab, valid_slots, qdel_on_fail = FALSE, indirect_action = TRUE)
+
+/// Change the slab in the recall ability, if it's different from the last one.
+/datum/antagonist/clock_cultist/proc/switch_recall_slab(datum/source, obj/item/clockwork/clockwork_slab/slab)
+ if(slab == recall.marked_slab)
+ return
+
+ recall.unmark_item()
+ recall.mark_item(slab)
+ to_chat(owner.current, span_brass("You re-attune yourself to a new Clockwork Slab."))
+
+/datum/antagonist/clock_cultist/proc/handle_silicon_conversion(mob/living/silicon/converted_silicon)
+ if(isAI(converted_silicon))
+ var/mob/living/silicon/ai/converted_ai = converted_silicon
+ converted_ai.disconnect_shell()
+ for(var/mob/living/silicon/robot/borg in converted_ai.connected_robots)
+ borg.set_connected_ai(null)
+ var/mutable_appearance/ai_clock = mutable_appearance('tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_mobs.dmi', "aiframe")
+ converted_ai.add_overlay(ai_clock)
+
+ else if(iscyborg(converted_silicon))
+ var/mob/living/silicon/robot/converted_borg = converted_silicon
+ converted_borg.UnlinkSelf()
+ converted_borg.set_clockwork(TRUE)
+
+ if(converted_silicon.laws && istype(converted_silicon.laws, /datum/ai_laws/ratvar))
+ return
+ converted_silicon.laws = new /datum/ai_laws/ratvar
+ converted_silicon.laws.associate(converted_silicon)
+ converted_silicon.show_laws()
+
+///remove clock cult items from their inventory by dropping them
+/datum/antagonist/clock_cultist/proc/handle_equipment_removal()
+ if(silent || !length(GLOB.types_to_drop_on_clock_deonversion))
+ return
+
+ var/mob/living/current = owner.current
+ for(var/obj/item/object as anything in current.get_all_contents())
+ if(object.type in GLOB.types_to_drop_on_clock_deonversion)
+ current.dropItemToGround(object, TRUE, TRUE)
+
+/datum/antagonist/clock_cultist/proc/add_forbearance(mob/apply_to)
+ if(GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE)
+ apply_to.add_filter("forbearance", 3, list("type" = "outline", "color" = "#FAE48E", "size" = 2, "alpha" = 100))
+
+/datum/outfit/clock/preview
+ name = "Clock Cultist (Preview only)"
+
+ uniform = /obj/item/clothing/under/syndicate
+ suit = /obj/item/clothing/suit/clockwork
+ head = /obj/item/clothing/head/helmet/clockwork
+ l_hand = /obj/item/clockwork/weapon/brass_sword
+
+//these can just solo invoke things that normally take multiple servants
+/datum/antagonist/clock_cultist/solo
+ name = "Servant of Ratvar (Solo)"
+
+//putting this here to avoid extra edits to the main file
+/datum/antagonist/cult
+ ///used for holy water deconversion
+ var/static/list/cultist_deconversion_phrases = list(
+ "spoken" = list(
+ "Av'te Nar'Sie",
+ "Pa'lid Mors",
+ "INO INO ORA ANA",
+ "SAT ANA!",
+ "Daim'niodeis Arc'iai Le'eones",
+ "R'ge Na'sie",
+ "Diabo us Vo'iscum",
+ "Eld' Mon Nobis",
+ ),
+
+ "seizure" = list(
+ "Your blood is your bond - you are nothing without it",
+ "Do not forget your place",
+ "All that power, and you still fail?",
+ "If you cannot scour this poison, I shall scour your meager life!"
+ )
+ )
diff --git a/tff_modular/modules/antagonists/clock_cult/antag_datums/clockmob_antag_datum.dm b/tff_modular/modules/antagonists/clock_cult/antag_datums/clockmob_antag_datum.dm
new file mode 100644
index 00000000000..921062abd97
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/antag_datums/clockmob_antag_datum.dm
@@ -0,0 +1,23 @@
+/datum/antagonist/clock_cultist/clockmob
+ show_in_antagpanel = FALSE
+ ///Our warp action
+ var/datum/action/cooldown/clock_cult/clockmob_warp/warp_action = new
+ ///A ref to our area bound component
+ var/datum/component/multi_area_bound/area_bound_component
+
+/datum/antagonist/clock_cultist/clockmob/Destroy()
+ QDEL_NULL(warp_action)
+ return ..()
+
+/datum/antagonist/clock_cultist/clockmob/apply_innate_effects(mob/living/mob_override)
+ . = ..()
+ warp_action.Grant(owner.current)
+ if(area_bound_component)
+ QDEL_NULL(area_bound_component)
+ stack_trace("[src.type] calling apply_innate_effects while still having an old area_bound_component.")
+ area_bound_component = owner.current.AddComponent(/datum/component/multi_area_bound, _valid_areas = SSthe_ark.marked_areas + SSthe_ark.reebe_areas, _use_instances = TRUE)
+
+/datum/antagonist/clock_cultist/clockmob/remove_innate_effects(mob/living/mob_override)
+ . = ..()
+ warp_action.Remove(owner.current)
+ QDEL_NULL(area_bound_component)
diff --git a/tff_modular/modules/antagonists/clock_cult/antag_datums/clocksense_alert.dm b/tff_modular/modules/antagonists/clock_cult/antag_datums/clocksense_alert.dm
new file mode 100644
index 00000000000..f2efbf5251e
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/antag_datums/clocksense_alert.dm
@@ -0,0 +1,61 @@
+//clock cult
+/atom/movable/screen/alert/clockwork/clocksense
+ name = "The Ark of the Clockwork Justicar"
+ desc = "Shows infomation about the Ark of the Clockwork Justicar"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/hud/screen_alert.dmi'
+ icon_state = "clockinfo"
+ alerttooltipstyle = "clockwork"
+ ///The static info we use so we only have to actually update our data once each tick
+ var/static/static_desc
+
+/atom/movable/screen/alert/clockwork/clocksense/Initialize(mapload, datum/hud/hud_owner)
+ . = ..()
+ if(!static_desc)
+ static_desc = get_static_desc()
+ desc = static_desc
+ if(!GLOB.ratvar_risen)
+ START_PROCESSING(SSprocessing, src)
+
+/atom/movable/screen/alert/clockwork/clocksense/Destroy()
+ STOP_PROCESSING(SSprocessing, src)
+ return ..()
+
+/atom/movable/screen/alert/clockwork/clocksense/process()
+ if(GLOB.ratvar_risen)
+ desc = "RATVAR HAS RISEN."
+ return PROCESS_KILL
+
+ var/static/last_process_tick
+ if(!last_process_tick || world.time - last_process_tick > 1 SECONDS)
+ static_desc = get_static_desc()
+ last_process_tick = world.time
+ desc = static_desc
+
+/atom/movable/screen/alert/clockwork/clocksense/proc/get_static_desc()
+ if(GLOB.ratvar_risen)
+ return "RATVAR HAS RISEN."
+
+ var/new_desc = "Stored Power - [display_power(SSthe_ark.clock_power, FALSE)].
"
+ new_desc += "Stored Vitality - [GLOB.clock_vitality].
"
+ new_desc += "Passive power access - [SSthe_ark.passive_power].
"
+ if(!GLOB.main_clock_cult)
+ return
+
+ new_desc += "We current have [length(GLOB.main_clock_cult.human_servants)] human servants out of [GLOB.main_clock_cult.max_human_servants] maximum human servants, \
+ as well as [length(GLOB.main_clock_cult.members)] servants all together.
"
+
+ if(GLOB.clock_ark?.charging_for)
+ new_desc += "The Ark will open in [600 - GLOB.clock_ark.charging_for] seconds!
"
+ return //we dont care about anchoring crystals at this point
+
+ var/static/list/cached_valid_areas
+ if(length(cached_valid_areas) != length(SSthe_ark.valid_crystal_areas)) //using length due to the cache being area names and not areas themselves
+ cached_valid_areas = list()
+ for(var/area/added_area in SSthe_ark.valid_crystal_areas)
+ cached_valid_areas += SSthe_ark.valid_crystal_areas[added_area]
+ new_desc += "Anchoring Crystals can be summoned in [english_list(cached_valid_areas)].
"
+
+ var/crystal_diff = ANCHORING_CRYSTALS_TO_SUMMON - length(SSthe_ark.anchoring_crystals)
+ if(crystal_diff > 0)
+ new_desc += "We must summon [crystal_diff] more Anchoring Crystal[crystal_diff > 1 ? "s" : ""] before the ark may open.
"
+ return new_desc
diff --git a/tff_modular/modules/antagonists/clock_cult/antag_datums/eminence_antag_datum.dm b/tff_modular/modules/antagonists/clock_cult/antag_datums/eminence_antag_datum.dm
new file mode 100644
index 00000000000..c0d4c2acd2c
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/antag_datums/eminence_antag_datum.dm
@@ -0,0 +1,49 @@
+/datum/antagonist/clock_cultist/eminence
+ name = "Eminence"
+ give_slab = FALSE
+ antag_moodlet = null
+ communicate = null
+ recall = null
+ ///The list of our actions
+ var/list/action_list = list(
+ /datum/action/innate/clockcult/space_fold,
+ /datum/action/cooldown/clock_cult/eminence/purge_reagents,
+ /datum/action/cooldown/clock_cult/eminence/linked_abscond,
+ /datum/action/innate/clockcult/teleport_to_servant,
+ /datum/action/innate/clockcult/teleport_to_station,
+ /datum/action/innate/clockcult/eminence_abscond,
+ /datum/action/innate/clockcult/show_warpable_areas,
+ /datum/action/innate/clockcult/add_warp_area,
+ )
+
+/datum/antagonist/clock_cultist/eminence/Destroy()
+ QDEL_LIST(action_list)
+ return ..()
+
+/datum/antagonist/clock_cultist/eminence/greet()
+ to_chat(owner.current, boxed_message("[span_bigbrass("You are the Eminence, a being bound to Ratvar. By his light you are able to influence nearby space and time.")]
\
+ [span_brass("As the Eminence you have access to various abilities, they are as follows.
\
+ You may click on various machines to interface with them or a servant to mark them.
\
+ Purge Reagents: Remove all reagents from the bloodstream of a marked servant, this is useful for a servant who is being deconverted by holy water.
\
+ Linked Abscond: Return a marked servant and anything they are pulling to reebe, this has a lengthy cooldown and they must remain still for 7 seconds.
\
+ Space Fold: Fold local spacetime to ensure certain \"events\" are inflicted upon the station, while doing this will cost cogs, \
+ these cogs are not taken from the cult itself. The cooldown is based on the cog cost of the event.
\
+ You can also teleport yourself to any other servant, useful for servants who need to be absconded like those which are dead or being deconverted.")]"))
+
+/datum/antagonist/clock_cultist/eminence/apply_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current = owner.current
+ add_team_hud(current, /datum/antagonist/clock_cultist)
+ for(var/datum/action/our_action as anything in action_list)
+ if(ispath(our_action))
+ our_action = new our_action()
+ our_action.Grant(current)
+
+/datum/antagonist/clock_cultist/eminence/remove_innate_effects(mob/living/mob_override)
+ . = ..()
+ for(var/datum/action/removed_action in action_list)
+ removed_action.Remove(owner.current)
+
+/datum/antagonist/clock_cultist/eminence/on_removal() //this should never happen without an admin being involved, something has gone wrong
+ to_chat(owner.current, span_userdanger("You lost your eminence antagonist status! This should not happen and you should ahelp(f1) unless you are already talking to an admin."))
+ return ..()
diff --git a/tff_modular/modules/antagonists/clock_cult/area.dm b/tff_modular/modules/antagonists/clock_cult/area.dm
new file mode 100644
index 00000000000..6b5b03d1e21
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/area.dm
@@ -0,0 +1,13 @@
+/area/ruin/powered/reebe
+ name = "Reebe"
+ ambience_index = AMBIENCE_REEBE
+ area_flags = UNIQUE_AREA | CULT_PERMITTED | NOTELEPORT
+ static_lighting = FALSE
+ base_lighting_alpha = 200
+
+/area/ruin/powered/reebe/space
+ name = "Reebe Space"
+ base_lighting_alpha = 255
+
+/area/ruin/powered/reebe/city
+ name = "City of Cogs"
diff --git a/tff_modular/modules/antagonists/clock_cult/ark_subsystem/_ark_subsystem.dm b/tff_modular/modules/antagonists/clock_cult/ark_subsystem/_ark_subsystem.dm
new file mode 100644
index 00000000000..48a0c90d26d
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/ark_subsystem/_ark_subsystem.dm
@@ -0,0 +1,164 @@
+///A subsystem to manage the global effects of clock cult
+#define SERVANT_CAPACITY_TO_GIVE 2
+PROCESSING_SUBSYSTEM_DEF(the_ark)
+ name = "The Clockwork Ark"
+ wait = 1 SECONDS
+ ss_flags = SS_NO_INIT | SS_KEEP_TIMING
+ runlevels = RUNLEVEL_GAME
+ ///The list of anchoring crystals, value is 0 is uncharged and 1 if charged
+ var/list/anchoring_crystals = list()
+ ///Dimension theme used for transforming turfs
+ var/datum/dimension_theme/clockwork/clock_dimension_theme = new /datum/dimension_theme/clockwork()
+ ///How many charged anchoring crystals are there
+ var/charged_anchoring_crystals = 0
+ ///Assoc list of the original names of areas that are valid to summon anchoring crystals keyed to its area
+ var/list/valid_crystal_areas
+ ///The pool of hallucinations we can trigger
+ var/list/hallucination_pool
+ ///How many clockwork airlocks have been created on reebe, used for limiting airlock spam
+ var/reebe_clockwork_airlock_count = 0
+ ///How much power does the cult have stored
+ var/clock_power = STANDARD_CELL_CHARGE * 0.25
+ ///What is the maximum amount of power the cult can have stored
+ var/max_clock_power = STANDARD_CELL_CHARGE * 0.25
+ ///How much passive power does the cult have access to, this gets used for things like turning on structures
+ var/passive_power = 15
+ ///The list of areas that has been marked by the cult, formatted as a filled with 1s for anti duplication
+ var/list/marked_areas = list()
+ ///A list of all cogscarabs
+ var/list/cogscarabs = list()
+ ///A list of all clockwork marauders
+ var/list/clockwork_marauders = list()
+ ///A list of all the areas on reebe
+ var/list/reebe_areas = list()
+
+/datum/controller/subsystem/processing/the_ark/Initialize()
+ initialized = TRUE
+ hallucination_pool = list(
+ /datum/hallucination/fake_item/clockwork_slab = 2,
+ /datum/hallucination/nearby_fake_item/clockwork_slab = 2,
+ /datum/hallucination/hazard/clockwork_skewer = 1,
+ /datum/hallucination/delusion/preset/clock_cultists = 1,
+ /datum/hallucination/fake_sound/weird/clockcult_kindle = 2,
+ /datum/hallucination/fake_sound/weird/clockcult_warp = 2,
+ )
+
+/datum/controller/subsystem/processing/the_ark/fire(resumed)
+ if(!initialized) //we are not currently being used so just return
+ return
+
+ if(charged_anchoring_crystals)
+ handle_charged_crystals()
+ return ..()
+
+///try and adjust our clock_power, returns FALSE if it would put us above our max_clock_power or below 0, set always_adjust to TRUE to make us instead just adjust to be within bounds
+/datum/controller/subsystem/processing/the_ark/proc/adjust_clock_power(amount, always_adjust = FALSE)
+ var/new_total = clock_power + amount
+ if(always_adjust)
+ clock_power = clamp(new_total, 0, max_clock_power)
+ return TRUE
+
+ if(new_total > max_clock_power || new_total < 0)
+ return FALSE
+ clock_power = new_total
+ return TRUE
+
+///same as adjust_clock_power() but much simpler as this does not have a max amount and is somewhat static, set only_check to TRUE to skip the actual adjustment step
+/datum/controller/subsystem/processing/the_ark/proc/adjust_passive_power(amount, only_check = FALSE)
+ var/new_total = passive_power + amount
+ if(new_total < 0)
+ return FALSE
+
+ if(!only_check)
+ passive_power = new_total
+ return TRUE
+
+///set up timed do_turf_conversion calls for the turfs in an area
+/datum/controller/subsystem/processing/the_ark/proc/convert_area_turfs(area/converted_area, conversion_percent = 100, counter_override)
+ var/timer_counter = counter_override || 1 //used by the addtimer()
+ var/list/turfs_to_transform = list()
+ for(var/i in 1 to length(converted_area.turfs_by_zlevel))
+ turfs_to_transform += converted_area.turfs_by_zlevel[i]
+
+ var/transformed_length = length(turfs_to_transform)
+ var/converted_amount = round(transformed_length * (conversion_percent * 0.01))
+ while(transformed_length && transformed_length > converted_amount)
+ pick_n_take(turfs_to_transform)
+ transformed_length = length(turfs_to_transform)
+
+ shuffle_inplace(turfs_to_transform)
+ for(var/turf/turf_to_transform as anything in turfs_to_transform)
+ if(!clock_dimension_theme.can_convert(turf_to_transform))
+ continue
+ addtimer(CALLBACK(src, PROC_REF(do_turf_conversion), turf_to_transform), 3 * timer_counter)
+ timer_counter++
+ return timer_counter //so you can do stuff once the conversion ends
+
+///convert a turf to our dimension theme
+/datum/controller/subsystem/processing/the_ark/proc/do_turf_conversion(turf/converted_turf)
+ if(QDELETED(src) || !clock_dimension_theme.can_convert(converted_turf))
+ return
+
+ clock_dimension_theme.apply_theme(converted_turf)
+ new /obj/effect/temp_visual/ratvar/beam(converted_turf)
+ if(istype(converted_turf, /turf/closed/wall))
+ new /obj/effect/temp_visual/ratvar/wall(converted_turf)
+ else if(istype(converted_turf, /turf/open/floor))
+ new /obj/effect/temp_visual/ratvar/floor(converted_turf)
+
+///called when an anchoring crystal is charged
+/datum/controller/subsystem/processing/the_ark/proc/on_crystal_charged(obj/structure/destructible/clockwork/anchoring_crystal/charged_crystal)
+ charged_anchoring_crystals++
+ anchoring_crystals[charged_crystal] = 1
+ SEND_SIGNAL(src, COMSIG_ANCHORING_CRYSTAL_CHARGED, charged_crystal)
+ passive_power += 5 * CLOCK_PASSIVE_POWER_PER_COG //5 APCs worth of passive power
+ max_clock_power += CLOCK_MAX_POWER_PER_COG * 5
+ var/datum/scripture/create_structure/anchoring_crystal/crystal_script
+ addtimer(CALLBACK(src, PROC_REF(clear_shuttle_interference), charged_crystal), \
+ (ANCHORING_CRYSTAL_COOLDOWN - ANCHORING_CRYSTAL_CHARGE_DURATION) + initial(crystal_script.invocation_time))
+ GLOB.main_clock_cult.max_human_servants += SERVANT_CAPACITY_TO_GIVE
+ if(charged_anchoring_crystals == ANCHORING_CRYSTALS_TO_SUMMON + 1) //create a steam helios on reebe
+ if(length(GLOB.abscond_markers))
+ var/turf/created_at = get_turf(pick(GLOB.abscond_markers))
+ new /obj/vehicle/sealed/mecha/steam_helios(created_at)
+ new /obj/effect/temp_visual/steam(created_at)
+ else if(GLOB.clock_ark)
+ new /obj/vehicle/sealed/mecha/steam_helios(get_turf(GLOB.clock_ark))
+ else
+ message_admins("No valid location for Steam Helios creation.")
+
+///fully disables the shuttle similar to the admin verb
+/datum/controller/subsystem/processing/the_ark/proc/block_shuttle(datum/blocker)
+ if(SSshuttle.admin_emergency_no_recall || SSshuttle.emergency.mode == SHUTTLE_DISABLED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
+ return
+
+ SSshuttle.last_mode = SSshuttle.emergency.mode
+ SSshuttle.last_call_time = SSshuttle.emergency.timeLeft(1)
+ SSshuttle.emergency_no_recall = TRUE
+ SSshuttle.emergency.setTimer(0)
+ SSshuttle.emergency.mode = SHUTTLE_DISABLED
+
+///renables the shuttle
+/datum/controller/subsystem/processing/the_ark/proc/clear_shuttle_interference(datum/unblocker)
+ if(SSshuttle.admin_emergency_no_recall || SSshuttle.emergency.mode != SHUTTLE_DISABLED || \
+ (unblocker && GLOB.clock_ark && GLOB.clock_ark.current_state >= ARK_STATE_CHARGING && istype(unblocker, /obj/structure/destructible/clockwork/anchoring_crystal)))
+ return
+
+ SSshuttle.emergency_no_recall = FALSE
+ if(SSshuttle.last_mode == SHUTTLE_DISABLED)
+ SSshuttle.last_mode = SHUTTLE_IDLE
+
+ SSshuttle.emergency.mode = SSshuttle.last_mode
+ if(SSshuttle.last_call_time < 10 SECONDS && SSshuttle.last_mode != SHUTTLE_IDLE)
+ SSshuttle.last_call_time = 10 SECONDS //Make sure no insta departures.
+ SSshuttle.emergency.setTimer(SSshuttle.last_call_time)
+ priority_announce("Emergency shuttle uplink connection regained.", "Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE)
+
+///returns how many charged anchor crystals there are
+/datum/controller/subsystem/processing/the_ark/proc/get_charged_anchor_crystals()
+ var/charged_count = 0
+ for(var/crystal in SSthe_ark.anchoring_crystals)
+ charged_count += SSthe_ark.anchoring_crystals[crystal]
+ return charged_count
+
+#undef SERVANT_CAPACITY_TO_GIVE
diff --git a/tff_modular/modules/antagonists/clock_cult/ark_subsystem/warp_effects.dm b/tff_modular/modules/antagonists/clock_cult/ark_subsystem/warp_effects.dm
new file mode 100644
index 00000000000..03a8c104266
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/ark_subsystem/warp_effects.dm
@@ -0,0 +1,175 @@
+//boy this sure is some fun code
+/datum/controller/subsystem/processing/the_ark/proc/handle_charged_crystals()
+ if(prob(charged_anchoring_crystals))
+ crystal_warp_minds()
+
+ if(charged_anchoring_crystals >= 2 && prob(charged_anchoring_crystals))
+ crystal_warp_machines()
+
+ if(charged_anchoring_crystals >= 3 && prob(charged_anchoring_crystals))
+ crystal_warp_space()
+
+/datum/controller/subsystem/processing/the_ark/proc/crystal_warp_minds()
+ var/list/players = GLOB.alive_player_list.Copy()
+ var/mob/living/selected_player = pick_n_take(players)
+ var/sanity = 0
+ if(!selected_player)
+ return
+
+ while(sanity < 100 && (IS_CLOCK(selected_player) || !is_station_level(selected_player.z)))
+ if(!length(players))
+ return
+ sanity++
+ selected_player = pick_n_take(players)
+
+ if(prob(50))
+ selected_player.cause_hallucination(pick_weight(hallucination_pool), "The Clockwork Ark")
+ else
+ to_chat(selected_player, span_warning(pick(list("You hear a faint ticking in the back of your mind", "You smell something metallic", \
+ "You see a flash of light out of the corner of your eye", "You feel an otherworldly presence", "You feel like your forgetting something"))))
+
+//making these their own procs for eaiser to read code
+/datum/controller/subsystem/processing/the_ark/proc/crystal_warp_machines()
+ switch(rand(1, 3))
+ if(1) //randomly mess with the settings of an APC with a low chance to emag it
+ var/list/apcs = SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/power/apc, /obj/machinery/power/apc/worn_out)
+ var/obj/machinery/power/apc/picked_apc = pick_n_take(apcs) //pick_n_take() handles length checking
+ if(!picked_apc)
+ return
+ var/sanity = 0
+ while(sanity < 100 && length(apcs) && !is_station_level(picked_apc.z))
+ picked_apc = pick_n_take(apcs)
+ sanity++
+ if(picked_apc)
+ if(prob(30))
+ picked_apc.overload_lighting()
+ else
+ picked_apc.lighting = picked_apc.setsubsystem(1)
+ if(prob(30))
+ picked_apc.equipment = picked_apc.setsubsystem(1)
+ if(prob(30))
+ picked_apc.environ = picked_apc.setsubsystem(1)
+ addtimer(CALLBACK(picked_apc, TYPE_PROC_REF(/obj/machinery/power/apc, setsubsystem), rand(2, 3)), 1 MINUTES)
+ if(!(picked_apc.obj_flags & EMAGGED) && prob(10))
+ playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ picked_apc.obj_flags |= EMAGGED
+ picked_apc.locked = FALSE
+ picked_apc.update_appearance()
+ if(2) //force open an airlock and bolt it
+ var/list/airlocks = SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/airlock, \
+ typesof(/obj/machinery/door/airlock/maintenance) + typesof(/obj/machinery/door/airlock/bronze/clock) + /obj/machinery/door/airlock/maintenance_hatch)
+ var/obj/machinery/door/airlock/picked_airlock = pick_n_take(airlocks)
+ if(!picked_airlock)
+ return
+ var/sanity = 0
+ while(sanity < 100 && length(airlocks) && (!picked_airlock.hasPower() || !is_station_level(picked_airlock.z) || picked_airlock.is_probably_external_airlock()))
+ picked_airlock = pick_n_take(airlocks)
+ sanity++
+ if(picked_airlock)
+ picked_airlock.unbolt()
+ picked_airlock.open(FORCING_DOOR_CHECKS)
+ picked_airlock.bolt()
+ if(3) //emag a random atom from our list of valid types
+ var/list/valid_emag_targets = list(
+ /mob/living/simple_animal/bot,
+ /mob/living/basic/bot,
+ /obj/machinery/announcement_system,
+ /obj/machinery/barsign,
+ /obj/machinery/computer/communications,
+ /obj/machinery/medical_kiosk,
+ /obj/machinery/sleeper,
+ /obj/machinery/computer/slot_machine,
+ /obj/machinery/computer/cargo/express,
+ /obj/machinery/computer/cargo,
+ /obj/machinery/destructive_scanner,
+ /obj/machinery/fishing_portal_generator,
+ /obj/machinery/computer/holodeck,
+ /obj/machinery/elevator_control_panel,
+ /obj/machinery/fax,
+ /obj/machinery/chem_dispenser,
+ /obj/machinery/research/anomaly_refinery,
+ /obj/machinery/computer/bsa_control,
+ /obj/machinery/vending,
+ /obj/machinery/computer/operating,
+ )
+ var/atom/selected_type = pick_n_take(valid_emag_targets)
+ var/list/valid_type_instances = get_emag_target_type_instances(selected_type)
+ var/sanity = 0
+ var/obj/machinery/selected_atom
+ while(!selected_atom && sanity < 10)
+ sanity++
+ while(!length(valid_type_instances))
+ if(!length(valid_emag_targets))
+ return
+ selected_type = pick_n_take(valid_emag_targets)
+ valid_type_instances = get_emag_target_type_instances(selected_type)
+ while(!selected_atom || bot_v_machine_check(selected_atom) || !is_station_level(selected_atom.z))
+ if(!length(valid_type_instances))
+ selected_atom = null
+ break
+ selected_atom = pick_n_take(valid_type_instances)
+ if(!selected_atom)
+ return
+ if(isbasicbot(selected_atom))
+ var/mob/living/basic/bot/basic_bot = selected_atom
+ basic_bot.bot_access_flags &= ~BOT_COVER_MAINTS_OPEN
+ else if(isbot(selected_atom))
+ var/mob/living/simple_animal/bot/simple_bot = selected_atom
+ simple_bot.bot_cover_flags &= ~BOT_COVER_MAINTS_OPEN
+ selected_atom.emag_act()
+
+/datum/controller/subsystem/processing/the_ark/proc/crystal_warp_space()
+ switch(rand(1, 2))
+ if(1)
+ var/datum/action/cooldown/spell/spacetime_dist/clock_ark/dist_spell = new
+ var/turf/turf = get_random_station_turf()
+ dist_spell.cast(turf)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(qdel), dist_spell), dist_spell.duration)
+ if(2)
+ var/list/servants = list() //technically we could adjust this everytime someone joins or leaves the cult but these last for 30 seconds so eh
+ if(GLOB.main_clock_cult)
+ for(var/datum/mind/servant_mind in GLOB.main_clock_cult.members)
+ servants += servant_mind.current
+ new /obj/effect/timestop/magic/clock_ark(get_random_station_turf(), 1, 30 SECONDS, servants)
+ return
+
+/datum/controller/subsystem/processing/the_ark/proc/get_emag_target_type_instances(input_path)
+ if(ispath(input_path, /obj/machinery))
+ return SSmachines.get_machines_by_type(input_path)
+ if(ispath(input_path, /mob/living/simple_animal/bot) || ispath(input_path, /mob/living/basic/bot))
+ return GLOB.bots_list.Copy()
+
+//OH YEAH I LOVE GOOD CODE
+/datum/controller/subsystem/processing/the_ark/proc/bot_v_machine_check(atom/checked_atom)
+ if(ismachinery(checked_atom))
+ var/obj/machinery/checked_machine = checked_atom
+ return checked_machine.obj_flags & EMAGGED
+ if(isbasicbot(checked_atom))
+ var/mob/living/basic/bot/checked_basic_bot = checked_atom
+ return checked_basic_bot.bot_access_flags & BOT_COVER_EMAGGED
+ if(istype(checked_atom, /mob/living/simple_animal/bot))
+ var/mob/living/simple_animal/bot/checked_bot = checked_atom
+ return checked_bot.bot_cover_flags & BOT_COVER_EMAGGED
+
+/datum/action/cooldown/spell/spacetime_dist/clock_ark
+ name = "Clockwork Spacetime Dist"
+ cooldown_time = 0
+ scramble_radius = 2
+ duration = 1 MINUTES
+
+/datum/action/cooldown/spell/spacetime_dist/clock_ark/cast(atom/cast_on)
+ . = ..()
+ new /obj/effect/cross_action/spacetime_dist/clock_ark(owner.loc)
+
+/obj/effect/cross_action/spacetime_dist/clock_ark
+
+/obj/effect/cross_action/spacetime_dist/clock_ark/walk_link(atom/movable/AM)
+ if(isliving(AM))
+ var/mob/living/living_mob = AM
+ if(IS_CLOCK(living_mob))
+ return
+ return ..()
+
+/obj/effect/timestop/magic/clock_ark
+ icon_state = ""
+ hidden = TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/dimension_theme.dm b/tff_modular/modules/antagonists/clock_cult/dimension_theme.dm
new file mode 100644
index 00000000000..4eed25c078b
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/dimension_theme.dm
@@ -0,0 +1,11 @@
+/datum/dimension_theme/clockwork
+ icon = 'icons/obj/stack_objects.dmi'
+ icon_state = "sheet-brass"
+ sound = 'sound/effects/magic/clockwork/fellowship_armory.ogg'
+ replace_floors = list(/turf/open/floor/bronze = 1)
+ replace_walls = /turf/closed/wall/clockwork
+ replace_objs = list(/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/bronze/clock = 1), \
+ /obj/structure/chair = list(/obj/structure/chair/bronze = 1), \
+ /obj/structure/table = list(/obj/structure/table/bronze = 1))
+
+ replace_window = /obj/structure/window/bronze/fulltile
diff --git a/tff_modular/modules/antagonists/clock_cult/dynamic_ruleset.dm b/tff_modular/modules/antagonists/clock_cult/dynamic_ruleset.dm
new file mode 100644
index 00000000000..c184923fbe2
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/dynamic_ruleset.dm
@@ -0,0 +1,49 @@
+/datum/dynamic_ruleset/roundstart/clock_cultist
+ name = "Clockwork Cult"
+ config_tag = "Roundstart Clockwork Cultist"
+ pref_flag = ROLE_ROUNDSTART_CLOCK_CULTIST
+ preview_antag_datum = /datum/antagonist/clock_cultist
+ blacklisted_roles = list(
+ JOB_AI,
+ JOB_CAPTAIN,
+ JOB_SECURITY_OFFICER,
+ JOB_CHAPLAIN,
+ JOB_CYBORG,
+ JOB_DETECTIVE,
+ JOB_HEAD_OF_PERSONNEL,
+ JOB_HEAD_OF_SECURITY,
+ JOB_PRISONER,
+ JOB_WARDEN,
+ )
+ weight = 6
+ min_pop = 20
+ max_antag_cap = list("denominator" = 18)
+
+/datum/dynamic_ruleset/roundstart/clock_cultist/assign_role(datum/mind/candidate)
+ candidate.add_antag_datum(/datum/antagonist/clock_cultist/solo)
+
+/datum/dynamic_ruleset/midround/clock_cultist
+ name = "Midround Clockwork Cult"
+ config_tag = "Midround Clockwork Cultist"
+ pref_flag = ROLE_MIDROUND_CLOCK_CULTIST
+ midround_type = LIGHT_MIDROUND
+ preview_antag_datum = /datum/antagonist/clock_cultist
+ blacklisted_roles = list(
+ JOB_AI,
+ JOB_CAPTAIN,
+ JOB_SECURITY_OFFICER,
+ JOB_CHAPLAIN,
+ JOB_CYBORG,
+ JOB_DETECTIVE,
+ JOB_HEAD_OF_PERSONNEL,
+ JOB_HEAD_OF_SECURITY,
+ JOB_PRISONER,
+ JOB_WARDEN,
+ )
+ weight = 6
+ min_pop = 20
+ max_antag_cap = list("denominator" = 18)
+ repeatable_weight_decrease = 3
+
+/datum/dynamic_ruleset/midround/clock_cultist/assign_role(datum/mind/candidate)
+ candidate.add_antag_datum(/datum/antagonist/clock_cultist/solo)
diff --git a/tff_modular/modules/antagonists/clock_cult/enchantment.dm b/tff_modular/modules/antagonists/clock_cult/enchantment.dm
new file mode 100644
index 00000000000..7be25dc8baf
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/enchantment.dm
@@ -0,0 +1,284 @@
+GLOBAL_LIST_EMPTY(enchantment_datums_by_type)
+
+/datum/component/enchanted
+ dupe_mode = COMPONENT_DUPE_ALLOWED
+ ///Current enchantment level
+ var/level
+ ///The span we warp our examine text in
+ var/used_span
+ ///A ref to the enchantment datum we are using
+ var/datum/enchantment/used_enchantment
+ ///A list of all enchantments
+ var/static/list/all_enchantments = list()
+
+/datum/component/enchanted/Initialize(list/select_enchants_from = subtypesof(/datum/enchantment), used_span = "", level_override)
+ if(!isitem(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ if(!length(select_enchants_from))
+ stack_trace("[src.type] calling Initialize with unset select_enchants_from.")
+ return COMPONENT_INCOMPATIBLE
+
+ if(!length(all_enchantments))
+ generate_enchantment_datums()
+
+ for(var/entry in select_enchants_from)
+ if(ispath(entry))
+ select_enchants_from -= entry
+ select_enchants_from += GLOB.enchantment_datums_by_type[entry]
+
+ used_enchantment = pick(select_enchants_from)
+ src.used_span = used_span
+ level = level_override || rand(1, used_enchantment.max_level)
+
+/datum/component/enchanted/RegisterWithParent()
+ var/list/component_list = used_enchantment.components_by_parent[parent]
+ if(!component_list)
+ used_enchantment.components_by_parent[parent] = list(text_ref(used_enchantment) = src) //used_enchantment is not being taken as a ref?
+ else
+ component_list[used_enchantment] = src
+ used_enchantment.apply_effect(parent, level)
+ RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
+
+/datum/component/enchanted/UnregisterFromParent()
+ UnregisterSignal(parent, COMSIG_ATOM_EXAMINE)
+ var/list/component_list = used_enchantment.components_by_parent[parent]
+ component_list -= used_enchantment
+ if(!length(component_list))
+ used_enchantment.components_by_parent -= parent
+
+/datum/component/enchanted/Destroy(force)
+ used_enchantment = null
+ return ..()
+
+/datum/component/enchanted/proc/on_examine(datum/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER
+
+ if(!used_enchantment.examine_description)
+ return
+
+ if(isobserver(user) || HAS_MIND_TRAIT(user, TRAIT_MAGICALLY_GIFTED))
+ if(used_span)
+ examine_list += "[used_span][used_enchantment.examine_description]"
+ examine_list += "[used_span]It's blessing has a power of [level]!
"
+ return
+ examine_list += "[used_enchantment.examine_description]"
+ examine_list += "It's blessing has a power of [level]!
"
+ else
+ examine_list += "It is glowing slightly!"
+ var/mob/living/living_user = user
+ if(istype(living_user.get_item_by_slot(ITEM_SLOT_EYES), /obj/item/clothing/glasses/science))
+ examine_list += "It emits a readable EMF factor of [level]."
+
+/datum/enchantment
+ ///Examine text
+ var/examine_description
+ ///Maximum enchantment level
+ var/max_level = 1
+ ///Typecache of items we are allowed on, generation handled in get_allowed_on
+ var/list/allowed_on
+ ///A recursive assoc list keyed as: [parent] = list(text_ref(enchant_component.used_enchantment) = enchant_component)
+ var/static/list/list/datum/component/enchanted/components_by_parent = list()
+
+/datum/enchantment/New()
+ . = ..()
+ allowed_on = get_allowed_on()
+
+/**
+ * Because of dumb BYOND reasons in order to get fine manual control we need to handle generation of allowed_on this way(via setting the default passed values)
+ *
+ * allowed_on_base - Typecache of items we are allowed on
+ *
+ * denied_from - Anything in this list will be set to FALSE in allowed_on
+ *
+ * overriden_types - Any values in this list will override allowed_on, this is handled last
+ */
+/datum/enchantment/proc/get_allowed_on(list/allowed_on_base = typecacheof(/obj/item), list/denied_from = typesof(/obj/item/clothing), list/overriden_types = list()) //AHHHHH
+ if(denied_from)
+ for(var/denied_entry in denied_from)
+ allowed_on_base[denied_entry] = 0
+ if(overriden_types)
+ for(var/entry in overriden_types)
+ allowed_on_base[entry] = overriden_types[entry]
+ return allowed_on_base
+
+/datum/enchantment/proc/get_component_from_parent(obj/item/parent) as /datum/component/enchanted
+ RETURN_TYPE(/datum/component/enchanted)
+ var/list/parent_list = components_by_parent[parent]
+ if(!parent_list)
+ return FALSE
+ return parent_list[text_ref(src)]
+
+/datum/enchantment/proc/can_apply_to(obj/item/checked)
+ return allowed_on[checked.type] && examine_description
+
+/datum/enchantment/proc/apply_effect(obj/item/target, level)
+ register_item(target)
+
+///Handle comsig reg here
+/datum/enchantment/proc/register_item(obj/item/target)
+ return
+
+///Handle comsig unreg here
+/datum/enchantment/proc/unregister_item(obj/item/target)
+ return
+
+/datum/enchantment/clothing
+
+/datum/enchantment/clothing/get_allowed_on(list/allowed_on_base = typecacheof(/obj/item/clothing), list/denied_from = list(), list/overriden_types)
+ return ..()
+
+/proc/attempt_enchantment(obj/item/enchanted, list/valid_enchant_types = subtypesof(/datum/enchantment), description_span = "", level_override)
+ if(!isitem(enchanted))
+ return FALSE
+
+ if(!length(GLOB.enchantment_datums_by_type))
+ generate_enchantment_datums()
+
+ if(!islist(valid_enchant_types))
+ valid_enchant_types = list(valid_enchant_types)
+
+ for(var/datum/enchantment/enchant as anything in valid_enchant_types)
+ valid_enchant_types -= enchant
+ enchant = GLOB.enchantment_datums_by_type[enchant]
+ if(enchant.can_apply_to(enchanted))
+ valid_enchant_types += enchant
+
+ if(!length(valid_enchant_types))
+ return FALSE
+ return enchanted.AddComponent(/datum/component/enchanted, valid_enchant_types, description_span, level_override)
+
+/proc/generate_enchantment_datums()
+ for(var/datum/enchantment/enchant as anything in subtypesof(/datum/enchantment))
+ GLOB.enchantment_datums_by_type[enchant] = new enchant()
+
+/datum/enchantment/blinding
+ examine_description = "It has been blessed with the power to emit a blinding light when striking a target."
+ max_level = 1
+
+/datum/enchantment/blinding/register_item(obj/item/target)
+ RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(flash_target))
+
+/datum/enchantment/blinding/unregister_item(obj/item/target)
+ UnregisterSignal(target, COMSIG_ITEM_ATTACK)
+
+/datum/enchantment/blinding/proc/flash_target(obj/item/source, mob/living/target, mob/living/user)
+ if(!istype(target))
+ return
+ source.visible_message(span_danger("\The [source] emits a blinding light!"))
+ target.flash_act(2, affect_silicon = FALSE, length = 2 SECONDS) //might want to make this not effect borgs // Сделал братуха
+
+//might have to change this due to us having TG instead of bee blocking
+/datum/enchantment/blocking
+ examine_description = "It has been blessed with the gift of blocking."
+ max_level = 3
+
+/datum/enchantment/blocking/apply_effect(obj/item/target, level)
+ target.block_chance += 5 * level
+
+/datum/enchantment/burn
+ examine_description = "It has been blessed with the power of fire and will set struck targets on fire."
+ max_level = 3
+
+/datum/enchantment/burn/apply_effect(obj/item/target, level)
+ . = ..()
+ target.damtype = BURN
+
+/datum/enchantment/burn/register_item(obj/item/target)
+ RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(burn_target))
+
+/datum/enchantment/burn/unregister_item(obj/item/target)
+ UnregisterSignal(target, COMSIG_ITEM_ATTACK)
+ return ..()
+
+/datum/enchantment/burn/proc/burn_target(obj/item/source, atom/movable/target, mob/living/user)
+ if(!isliving(target))
+ return
+ var/datum/component/enchanted/comp = get_component_from_parent(source)
+ if(!comp)
+ return
+
+ var/mob/living/living_target = target
+ living_target.adjust_fire_stacks(comp.level)
+ living_target.ignite_mob()
+
+/datum/enchantment/electricution
+ max_level = 3
+ examine_description = "It has been blessed with the power of electricity and will shock targets."
+
+/datum/enchantment/electricution/register_item(obj/item/target)
+ RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(shock_target))
+
+/datum/enchantment/electricution/unregister_item(obj/item/target)
+ UnregisterSignal(target, COMSIG_ITEM_ATTACK)
+
+/datum/enchantment/electricution/proc/shock_target(obj/item/source, atom/movable/target, mob/living/user)
+ user.Beam(target, icon_state = "lightning[rand(1,12)]", time = 2, maxdistance = 32)
+ if(!iscarbon(target))
+ return
+ var/datum/component/enchanted/comp = get_component_from_parent(source)
+ if(!comp)
+ return
+
+ var/mob/living/carbon/carbon_target = target
+ if(carbon_target.electrocute_act(comp.level * 3, user, 1, SHOCK_NOSTUN)) //need to make this ark, also this seems to work on any living mob
+ carbon_target.visible_message(span_danger("[user] electrocutes [target]!"), span_userdanger("[user] electrocutes you!"))
+
+/datum/enchantment/haste
+ examine_description = "It has been blessed with the ability to warp time around it so that it's user may attack faster with it."
+ max_level = 1
+
+/datum/enchantment/haste/apply_effect(obj/item/target)
+ target.attack_speed = max(1, target.attack_speed - 2)
+
+/datum/enchantment/penetration
+ examine_description = "It has been blessed with the gift of armor penetration, allowing it to cut through targets with ease."
+ max_level = 5
+
+/datum/enchantment/penetration/apply_effect(obj/item/target, level)
+ target.armour_penetration = max(15 * level, target.armour_penetration)
+
+/datum/enchantment/sharpness
+ examine_description = "It has been blessed with the gift of sharpness."
+ max_level = 2
+
+/datum/enchantment/sharpness/apply_effect(obj/item/target, level)
+ target.force += 5 * level
+
+/datum/enchantment/soul_tap
+ examine_description = "It has been blessed with the power of ripping the energy from target's souls and will heal the wielder when a target is struck."
+ max_level = 3
+
+/datum/enchantment/soul_tap/unregister_item(obj/item/target)
+ UnregisterSignal(target, COMSIG_ITEM_ATTACK)
+
+/datum/enchantment/soul_tap/register_item(obj/item/target)
+ RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(tap_soul))
+
+/datum/enchantment/soul_tap/proc/tap_soul(obj/item/source, mob/living/target, mob/living/user)
+ if(!istype(target) || target.stat != CONSCIOUS)
+ return
+ var/datum/component/enchanted/comp = get_component_from_parent(source)
+ if(!comp)
+ return
+ var/health_back = CEILING(comp.level * source.force * 0.1, 1)
+ user.heal_overall_damage(health_back, health_back)
+ new /obj/effect/temp_visual/heal(get_turf(user), "#eeba6b")
+
+/datum/enchantment/tiny
+ examine_description = "It has been blessed and distorts reality into a tiny space around it."
+ max_level = 1
+
+/datum/enchantment/tiny/get_allowed_on(list/allowed_on_base, list/denied_from = list(), list/overriden_types)
+ . = ..()
+
+/datum/enchantment/tiny/apply_effect(obj/item/target)
+ target.w_class = WEIGHT_CLASS_TINY
+
+/datum/enchantment/clothing/speed
+ examine_description = "It has been blessed and reduces the weight of the item."
+ max_level = 2
+
+/datum/enchantment/clothing/speed/apply_effect(obj/item/target, level)
+ var/slowdown_level = max_level * 0.1
+ target.slowdown -= slowdown_level
diff --git a/tff_modular/modules/antagonists/clock_cult/globals.dm b/tff_modular/modules/antagonists/clock_cult/globals.dm
new file mode 100644
index 00000000000..103309f9951
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/globals.dm
@@ -0,0 +1,8 @@
+GLOBAL_VAR_INIT(clock_power, 2500)
+GLOBAL_VAR_INIT(max_clock_power, 2500) // Increases with every APC cogged
+GLOBAL_VAR_INIT(clock_vitality, 100) //start with only a bit of vitality
+GLOBAL_VAR_INIT(clock_installed_cogs, 0)
+GLOBAL_LIST_INIT(clock_turf_types, typesof(/turf/open/floor/bronze, /turf/open/indestructible/reebe_void, /turf/open/indestructible/reebe_flooring, /turf/closed/wall/clockwork, /turf/open/floor/engine/clockwork))
+GLOBAL_LIST_EMPTY(types_to_drop_on_clock_deonversion) //list of types to check for dropping on deconversion
+//CONVERT TO GLOBAL DATUM
+GLOBAL_VAR_INIT(narsie_breaching_rune, FALSE) //rune where nar'sie is trying to summon from, if it gets destroyed somehow then just summon her on a random station turf
diff --git a/tff_modular/modules/antagonists/clock_cult/hallucinations.dm b/tff_modular/modules/antagonists/clock_cult/hallucinations.dm
new file mode 100644
index 00000000000..1cb26c864f9
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/hallucinations.dm
@@ -0,0 +1,55 @@
+/datum/hallucination/fake_item/clockwork_slab
+ random_hallucination_weight = 0
+ template_item_type = /obj/item/clockwork/clockwork_slab
+ valid_slots = ITEM_SLOT_HANDS
+
+/datum/hallucination/nearby_fake_item/clockwork_slab
+ left_hand_file = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_lefthand.dmi'
+ right_hand_file = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_righthand.dmi'
+ image_icon_state = "clockwork_slab"
+
+/datum/hallucination/hazard/clockwork_skewer
+ random_hallucination_weight = 0
+ hazard_type = /obj/effect/client_image_holder/hallucination/danger/clockwork_skewer
+
+/obj/effect/client_image_holder/hallucination/danger/clockwork_skewer
+ name = "brass skewer"
+ image_icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ image_state = "brass_skewer"
+
+/obj/effect/client_image_holder/hallucination/danger/clockwork_skewer/on_hallucinator_entered(mob/living/afflicted)
+ to_chat(afflicted, span_userdanger("You are impaled by [src]!"))
+ afflicted.visible_message(span_warning("[afflicted] falls to the ground suddenly!"), ignored_mobs = afflicted)
+ afflicted.Paralyze(4 SECONDS)
+ afflicted.emote("scream")
+ afflicted.adjust_stamina_loss(40)
+ image_state = "brass_skewer_pokeybit"
+ image_layer = ABOVE_MOB_LAYER
+ update_appearance()
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), afflicted, span_notice("...You feel the pain of being stabbed fading strangely quickly.")), 1.5 SECONDS)
+ QDEL_IN(src, 3 SECONDS)
+
+/datum/hallucination/delusion/preset/clock_cultists
+ dynamic_delusion = TRUE
+ random_hallucination_weight = 0
+ delusion_name = "Servant of Ratvar"
+ affects_others = TRUE
+ skip_nearby = TRUE
+
+/datum/hallucination/delusion/preset/clock_cultists/make_delusion_image(mob/over_who)
+ var/static/mutable_appearance/servant_appearance
+ if(isnull(servant_appearance))
+ servant_appearance = get_dynamic_human_appearance(/datum/outfit/clock/preview, r_hand = NO_REPLACE)
+ delusion_appearance = servant_appearance
+ return ..()
+
+/datum/hallucination/fake_sound/weird/clockcult_kindle
+ sound_type = 'sound/effects/magic/staff_animation.ogg'
+
+/datum/hallucination/fake_sound/weird/clockcult_kindle/play_fake_sound(turf/source, sound_to_play)
+ . = ..()
+ if(prob(50))
+ queue_fake_sound(source, 'sound/items/weapons/handcuffs.ogg', delay = 4 SECONDS)
+
+/datum/hallucination/fake_sound/weird/clockcult_warp
+ sound_type = 'sound/effects/magic/magic_missile.ogg'
diff --git a/tff_modular/modules/antagonists/clock_cult/helpers.dm b/tff_modular/modules/antagonists/clock_cult/helpers.dm
new file mode 100644
index 00000000000..a117702be9e
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/helpers.dm
@@ -0,0 +1,42 @@
+///check if an atom is on the reebe z level, will also return FALSE if the atom has no z level
+/proc/on_reebe(atom/checked_atom)
+ var/turf/checked_turf = get_turf(checked_atom)
+ if(!checked_turf?.z || !is_reebe_level(checked_turf.z))
+ return FALSE
+ return TRUE
+
+/proc/gods_battle()
+ if(GLOB.cult_narsie && GLOB.cult_ratvar)
+ var/datum/component/singularity/narsie_singularity_component = GLOB.cult_narsie.singularity?.resolve()
+ var/datum/component/singularity/ratvar_singularity_component = GLOB.cult_ratvar.singularity?.resolve()
+ if(!narsie_singularity_component || !ratvar_singularity_component)
+ message_admins("gods_battle() called without a singularity component on of of the 2 main gods.")
+ return FALSE
+
+ narsie_singularity_component.target = GLOB.cult_ratvar
+ ratvar_singularity_component.target = GLOB.cult_narsie
+ return TRUE
+ return FALSE
+
+/proc/try_servant_warp(mob/living/servant, turf/target_turf)
+ var/mob/living/pulled = servant.pulling
+ playsound(servant, 'sound/effects/magic/magic_missile.ogg', 50, TRUE) //doing this manually for sound volume reasons
+ playsound(target_turf, 'sound/effects/magic/magic_missile.ogg', 50, TRUE)
+ do_sparks(3, TRUE, servant)
+ do_sparks(3, TRUE, target_turf)
+ do_teleport(servant, target_turf, 0, no_effects = TRUE, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
+ to_chat(servant, "You warp to [get_area(target_turf)].")
+ if(!IS_CLOCK(servant) || !on_reebe(servant))
+ servant.apply_status_effect(/datum/status_effect/clock_warp_sickness, 15 SECONDS)
+
+ if(ishuman(servant)) //looks weird on non-humanoids
+ new /obj/effect/temp_visual/ratvar/warp(target_turf)
+
+ if(istype(pulled, /mob/living))
+ do_teleport(pulled, target_turf, 0, no_effects = TRUE, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
+ if(!IS_CLOCK(pulled))
+ pulled.Paralyze(3 SECONDS)
+ to_chat(pulled, span_warning("You feel sick and confused."))
+ pulled.apply_status_effect(/datum/status_effect/clock_warp_sickness, 15 SECONDS)
+ else if(!on_reebe(pulled))
+ pulled.apply_status_effect(/datum/status_effect/clock_warp_sickness, 15 SECONDS)
diff --git a/tff_modular/modules/antagonists/clock_cult/hint_element.dm b/tff_modular/modules/antagonists/clock_cult/hint_element.dm
new file mode 100644
index 00000000000..2af060a0607
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/hint_element.dm
@@ -0,0 +1,44 @@
+/datum/element/clockwork_description
+ element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY
+ argument_hash_start_idx = 2
+
+ /// Text to add to the description of the parent
+ var/text_to_add = ""
+ /// Text to add if we are on reebe
+ var/reebe_desc = ""
+
+/datum/element/clockwork_description/Attach(datum/target, parent_text, reebe_text)
+ . = ..()
+
+ if(!isatom(target))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(add_examine))
+ // Don't perform the assignment if there is nothing to assign, or if we already have something for this bespoke element
+ if(parent_text && !text_to_add)
+ text_to_add = parent_text
+
+ if(reebe_text && !reebe_desc)
+ reebe_desc = reebe_text
+
+/datum/element/clockwork_description/Detach(datum/target)
+ . = ..()
+ UnregisterSignal(target, COMSIG_ATOM_EXAMINE)
+
+/**
+ *
+ * This proc is called when the user examines an object with the associated element. This adds the text to the description in a new line, wrapped with span_brass()
+ *
+ * Arguments:
+ * * source - Object being examined, cast into an item variable
+ * * user - Unused
+ * * examine_texts - The output text list of the original examine function
+ */
+
+/datum/element/clockwork_description/proc/add_examine(atom/source, mob/user, list/examine_texts)
+ SIGNAL_HANDLER
+
+ if(IS_CLOCK(user) || isobserver(user))
+ examine_texts += span_brass(text_to_add)
+ if(reebe_desc && on_reebe(source))
+ examine_texts += span_brass(reebe_desc)
diff --git a/tff_modular/modules/antagonists/clock_cult/holy_water.dm b/tff_modular/modules/antagonists/clock_cult/holy_water.dm
new file mode 100644
index 00000000000..979bfee5410
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/holy_water.dm
@@ -0,0 +1,41 @@
+/datum/reagent/water/holywater/expose_mob(mob/living/exposed_mob, methods, reac_volume)
+ . = ..()
+ if(IS_CLOCK(exposed_mob))
+ to_chat(exposed_mob, span_userdanger("Your mind burns in agony as you feel the light of the Justicar being ripped away from you by something else!"))
+
+/datum/reagent/water/holywater/proc/handle_cultists(mob/living/carbon/affected_mob, seconds_per_tick)
+ var/list/phrase_list
+ if(IS_CULTIST(affected_mob)) //snowflakey but it works
+ var/datum/antagonist/cult/cult_datum = affected_mob.mind.has_antag_datum(/datum/antagonist/cult)
+ phrase_list = cult_datum?.cultist_deconversion_phrases
+ else if(IS_CLOCK(affected_mob))
+ var/datum/antagonist/clock_cultist/servant_datum = affected_mob.mind.has_antag_datum(/datum/antagonist/clock_cultist)
+ phrase_list = servant_datum?.servant_deconversion_phrases
+
+ if(data["deciseconds_metabolized"] >= (25 SECONDS)) // 10 units
+ affected_mob.adjust_stutter_up_to(4 SECONDS * seconds_per_tick, 20 SECONDS)
+ affected_mob.set_dizzy_if_lower(10 SECONDS)
+ if(SPT_PROB(10, seconds_per_tick))
+ if(phrase_list)
+ affected_mob.say(pick(phrase_list["spoken"]), forced = "holy water")
+ if(prob(10))
+ affected_mob.visible_message(span_danger("[affected_mob] starts having a seizure!"), span_userdanger("You have a seizure!"))
+ affected_mob.Unconscious(12 SECONDS)
+ var/span_type
+ if(IS_CULTIST(affected_mob))
+ span_type = "cultlarge"
+ else if(IS_CLOCK(affected_mob))
+ span_type = "big_brass"
+ if(phrase_list)
+ to_chat(affected_mob, "[pick(phrase_list["seizure"])].")
+
+ if(data["deciseconds_metabolized"] >= (1 MINUTES)) // 24 units
+ if(IS_CULTIST(affected_mob))
+ affected_mob.mind.remove_antag_datum(/datum/antagonist/cult)
+ if(IS_CLOCK(affected_mob))
+ affected_mob.mind.remove_antag_datum(/datum/antagonist/clock_cultist)
+ affected_mob.Unconscious(10 SECONDS)
+ affected_mob.remove_status_effect(/datum/status_effect/jitter)
+ affected_mob.remove_status_effect(/datum/status_effect/speech/stutter)
+ holder.remove_reagent(type, volume) // maybe this is a little too perfect and a max() cap on the statuses would be better??
+ return TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/effects/landmarks_static.dmi b/tff_modular/modules/antagonists/clock_cult/icons/effects/landmarks_static.dmi
new file mode 100644
index 00000000000..5c6dd6264ba
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/effects/landmarks_static.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/hud/screen_alert.dmi b/tff_modular/modules/antagonists/clock_cult/icons/hud/screen_alert.dmi
new file mode 100644
index 00000000000..0a003dd39cc
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/hud/screen_alert.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/actions_clock.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/actions_clock.dmi
new file mode 100644
index 00000000000..6fe415943dd
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/actions_clock.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/background_clock.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/background_clock.dmi
new file mode 100644
index 00000000000..8e8df3fd3ee
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/background_clock.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/cameramob.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/cameramob.dmi
new file mode 100644
index 00000000000..17b79ccc0e8
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/cameramob.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi
new file mode 100644
index 00000000000..4709b946872
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_lefthand.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_lefthand.dmi
new file mode 100644
index 00000000000..8e8bb58de2b
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_lefthand.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_mobs.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_mobs.dmi
new file mode 100644
index 00000000000..2e66c8b7a67
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_mobs.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_righthand.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_righthand.dmi
new file mode 100644
index 00000000000..b951aa8ece0
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_righthand.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/hud.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/hud.dmi
new file mode 100644
index 00000000000..6782f01cf64
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/hud.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/mob/speech.dmi b/tff_modular/modules/antagonists/clock_cult/icons/mob/speech.dmi
new file mode 100644
index 00000000000..7d13520cc9a
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/mob/speech.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/512x512.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/512x512.dmi
new file mode 100644
index 00000000000..99d39c6e8bb
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/512x512.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/ammo.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/ammo.dmi
new file mode 100644
index 00000000000..9893ddeb415
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/ammo.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork.dmi
new file mode 100644
index 00000000000..5248b184461
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork_large.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork_large.dmi
new file mode 100644
index 00000000000..4b8e2d1c9a0
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork_large.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi
new file mode 100644
index 00000000000..71904d40651
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_garb.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_garb.dmi
new file mode 100644
index 00000000000..901afd12ee6
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_garb.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi
new file mode 100644
index 00000000000..643be27cb59
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_weapons.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_weapons.dmi
new file mode 100644
index 00000000000..d4a82b6797c
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_weapons.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork.dmi
new file mode 100644
index 00000000000..5e043027c5f
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork_large.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork_large.dmi
new file mode 100644
index 00000000000..306bd9d0d78
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork_large.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/misc.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/misc.dmi
new file mode 100644
index 00000000000..b9ed54d6100
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/misc.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/projectiles.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/projectiles.dmi
new file mode 100644
index 00000000000..87abc6d14c0
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/projectiles.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/sleeper.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/sleeper.dmi
new file mode 100644
index 00000000000..de40ad09c12
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/sleeper.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/tools.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/tools.dmi
new file mode 100644
index 00000000000..5525d466d75
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/tools.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/icons/obj/window.dmi b/tff_modular/modules/antagonists/clock_cult/icons/obj/window.dmi
new file mode 100644
index 00000000000..91b50608e73
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/icons/obj/window.dmi differ
diff --git a/tff_modular/modules/antagonists/clock_cult/items/clock_stock_parts.dm b/tff_modular/modules/antagonists/clock_cult/items/clock_stock_parts.dm
new file mode 100644
index 00000000000..de32ae438c4
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/clock_stock_parts.dm
@@ -0,0 +1,70 @@
+//power cell that gets its power from SSthe_ark.clock_power
+/obj/item/stock_parts/power_store/cell/clock
+ name = "Wound Power Cell"
+ desc = "A bronze colored power cell. Is that a winding crank on the side?" //might make a real wind up powercell at some point for a joke item
+ color = rgb(190, 135, 0) //currently only used for mechs so im calling this good enough
+
+/obj/item/stock_parts/power_store/cell/clock/Initialize(mapload, override_maxcharge)
+ . = ..()
+ AddElement(/datum/element/empprotection, EMP_PROTECT_SELF) //no EMP
+ UnregisterSignal(src, COMSIG_ITEM_MAGICALLY_CHARGED) //just to be safe
+ START_PROCESSING(SSfastprocess, src) //janky, but the only way I can think of to get this to work is with a refactor to clock power, which im not doing for the visuals of one thing
+
+/obj/item/stock_parts/power_store/cell/clock/Destroy(force)
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+/obj/item/stock_parts/power_store/cell/clock/process(seconds_per_tick)
+ charge = SSthe_ark.clock_power
+ maxcharge = SSthe_ark.max_clock_power
+
+//technically this means these cant be rigged with plasma
+/obj/item/stock_parts/power_store/cell/clock/use(used, force)
+ if(!..() || istype(loc, /obj/machinery/power/apc) || SSthe_ark.clock_power < used)
+ return FALSE
+ SSblackbox.record_feedback("tally", "cell_used", 1, type)
+ SSthe_ark.clock_power = max(SSthe_ark.clock_power - used, 0)
+ return TRUE
+
+/obj/item/stock_parts/power_store/cell/clock/percent()
+ return 100 * SSthe_ark.clock_power / SSthe_ark.max_clock_power
+
+/obj/item/stock_parts/power_store/cell/clock/give(amount) //no
+ return FALSE
+
+//these are just for flavor
+/obj/item/stock_parts/scanning_module/triphasic/clock
+ name = "Ticking Scanning Module"
+ desc = "A bronze colored scanning module, you hear a faint ticking from inside."
+ color = rgb(190, 135, 0)
+
+/datum/stock_part/scanning_module/clock
+ tier = 4
+ physical_object_type = /obj/item/stock_parts/scanning_module/triphasic/clock
+
+/obj/item/stock_parts/capacitor/quadratic/clock
+ name = "Clicking Capacitor"
+ desc = "A bronze colored scanning module with a slow clicking within."
+ color = rgb(190, 135, 0)
+
+/datum/stock_part/capacitor/clock
+ tier = 4
+ physical_object_type = /obj/item/stock_parts/capacitor/quadratic/clock
+
+/obj/item/stock_parts/matter_bin/bluespace/clock
+ name = "Glowing Matter Bin"
+ desc = "It has a faint glow emitting from within."
+ color = rgb(190, 135, 0)
+
+/datum/stock_part/matter_bin/clock
+ tier = 4
+ physical_object_type = /obj/item/stock_parts/matter_bin/bluespace/clock
+
+/obj/item/stock_parts/servo/femto/clock
+ name = "Powered Manipulator"
+ desc = "Changes the energy flow around an object to manipulate it."
+ color = rgb(190, 135, 0)
+
+/datum/stock_part/servo/clock
+ tier = 4
+ physical_object_type = /obj/item/stock_parts/servo/femto/clock
diff --git a/tff_modular/modules/antagonists/clock_cult/items/clockwork_slab.dm b/tff_modular/modules/antagonists/clock_cult/items/clockwork_slab.dm
new file mode 100644
index 00000000000..aa0accc6827
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/clockwork_slab.dm
@@ -0,0 +1,273 @@
+#define MAXIMUM_QUICKBIND_SLOTS 5
+
+GLOBAL_LIST_INIT(clockwork_slabs, list())
+
+/obj/item/clockwork
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ /// Extra info to give clock cultists, added via the /datum/element/clockwork_description element
+ var/clockwork_desc = ""
+ /// Does this item get the clockwork_pickup element
+ var/has_pickup_element = TRUE
+
+/obj/item/clockwork/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_description, clockwork_desc)
+ if(has_pickup_element)
+ AddElement(/datum/element/clockwork_pickup)
+
+/obj/item/clockwork/clockwork_slab
+ name = "Clockwork Slab"
+ desc = "A mechanical-looking device filled with intricate cogs that swirl to their own accord."
+ clockwork_desc = "A beautiful work of art, harnessing mechanical energy for a variety of useful powers."
+ item_flags = NOBLUDGEON
+ icon_state = "clockwork_slab"
+ lefthand_file = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_lefthand.dmi'
+ righthand_file = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_righthand.dmi'
+ w_class = WEIGHT_CLASS_TINY
+ has_pickup_element = FALSE
+
+ /// The scripture currently being invoked
+ var/datum/scripture/invoking_scripture
+ /// For scriptures that power the slab
+ var/datum/scripture/slab/active_scripture
+ /// What overlay the slab should use, should the active scripture have one
+ var/charge_overlay
+
+ /// How many cogs this slab has currently
+ var/cogs = 0
+ /// An assoc list of refs to instances that are owned/have been purchased by this slab. Assoc is by type
+ var/list/owned_scriptures = list()
+
+ //Initialise an empty list for quickbinding
+ var/list/quick_bound_scriptures = list(
+ /* 1 = */ null,
+ /* 2 = */ null,
+ /* 3 = */ null,
+ /* 4 = */ null,
+ /* 5 = */ null,
+ )
+
+ //The default scriptures that get auto-assigned.
+ var/list/default_scriptures = list()
+
+ //For trap linkage
+ var/datum/component/clockwork_trap/buffer
+
+
+/obj/item/clockwork/clockwork_slab/Initialize(mapload)
+ . = ..()
+ if(!length(GLOB.clock_scriptures) || !length(GLOB.clock_scriptures_by_type))
+ generate_clockcult_scriptures()
+
+ var/pos = 1
+ cogs = GLOB.clock_installed_cogs
+ GLOB.clockwork_slabs += src
+ for(var/script in default_scriptures)
+ if(!script)
+ continue
+
+ var/datum/scripture/default_script = new script()
+ owned_scriptures[default_script.type] = default_script
+ bind_spell(null, default_script, pos++)
+
+
+/obj/item/clockwork/clockwork_slab/Destroy()
+ GLOB.clockwork_slabs -= src
+ invoking_scripture = null
+ active_scripture = null
+ buffer = null
+ for(var/scripture_path in owned_scriptures)
+ var/scripture_ref = owned_scriptures[scripture_path] //so we can clear the ref before qdeling
+ owned_scriptures[scripture_path] = null
+ qdel(scripture_ref)
+ return ..()
+
+
+/obj/item/clockwork/clockwork_slab/dropped(mob/user)
+ . = ..()
+ //Clear quickbinds
+ for(var/datum/action/innate/clockcult/quick_bind/script in quick_bound_scriptures)
+ script.Remove(user)
+
+ if(active_scripture)
+ active_scripture.end_invocation()
+
+ if(buffer)
+ buffer = null
+
+
+/obj/item/clockwork/clockwork_slab/pickup(mob/user)
+ . = ..()
+ if(!IS_CLOCK(user))
+ return
+
+ //Grant quickbound spells
+ for(var/datum/action/innate/clockcult/quick_bind/script in quick_bound_scriptures)
+ script.Grant(user)
+
+ user.update_action_buttons()
+
+
+/obj/item/clockwork/clockwork_slab/update_overlays()
+ . = ..()
+ cut_overlays()
+ if(charge_overlay)
+ add_overlay(list(charge_overlay))
+
+
+/// Handle binding a spell to a quickbind slot
+/obj/item/clockwork/clockwork_slab/proc/bind_spell(mob/living/binder, datum/scripture/spell, position = 1)
+ if((position > length(quick_bound_scriptures)) || (position <= 0))
+ return
+
+ if(quick_bound_scriptures[position])
+ //Unbind the scripture that is quickbound
+ qdel(quick_bound_scriptures[position])
+
+ //Put the quickbound action onto the slab, the slab should grant when picked up
+ var/datum/action/innate/clockcult/quick_bind/quickbound = new
+ quickbound.scripture = spell
+ quickbound.slab_weakref = WEAKREF(src)
+ quick_bound_scriptures[position] = quickbound
+ if(binder)
+ quickbound.Grant(binder)
+
+// UI things below
+/obj/item/clockwork/clockwork_slab/attack_self(mob/living/user)
+ if(!IS_CLOCK(user))
+ to_chat(user, span_warning("As you try and fiddle with \the [src] you feel a shock course through you!"))
+ user.dropItemToGround(user, TRUE)
+ user.electrocute_act((IS_CULTIST(user) ? 40 : 20), src, 1, SHOCK_NOGLOVES | SHOCK_SUPPRESS_MESSAGE)
+ return
+
+ if(active_scripture)
+ active_scripture.end_invocation()
+ return
+
+ if(buffer)
+ buffer = null
+ to_chat(user, span_brass("You clear the [src]'s buffer."))
+ return
+
+ SEND_SIGNAL(user, COMSIG_CLOCKWORK_SLAB_USED, src)
+
+ ui_interact(user)
+
+/obj/item/clockwork/clockwork_slab/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "ClockworkSlab")
+ ui.open()
+
+/obj/item/clockwork/clockwork_slab/ui_data(mob/user)
+ var/list/data = list()
+
+ data["cogs"] = cogs
+ data["vitality"] = GLOB.clock_vitality
+ data["max_vitality"] = MAX_CLOCK_VITALITY
+ data["power"] = SSthe_ark.clock_power
+ data["max_power"] = SSthe_ark.max_clock_power
+ data["scriptures"] = list()
+
+ //2 scriptures accessible at the same time will cause issues
+ for(var/datum/scripture/scripture as anything in GLOB.clock_scriptures)
+ if(scripture.unique_locked)
+ continue
+
+ var/list/scripture_data = list(
+ "name" = scripture.name,
+ "desc" = scripture.desc,
+ "type" = scripture.category,
+ "tip" = scripture.tip,
+ "cost" = scripture.power_cost,
+ "purchased" = (owned_scriptures[scripture.type] ? TRUE : FALSE),
+ "cog_cost" = scripture.cogs_required,
+ "typepath" = scripture.type,
+ )
+ //Add it to the correct list
+ data["scriptures"] += list(scripture_data)
+
+ return data
+
+
+/obj/item/clockwork/clockwork_slab/ui_act(action, params)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/living/living_user = usr
+ if(!istype(living_user) || !IS_CLOCK(living_user))
+ return FALSE
+
+ switch(action)
+ if("invoke")
+ var/datum/scripture/scripture = GLOB.clock_scriptures_by_type[text2path(params["scriptureType"])]
+ if(!scripture)
+ return FALSE
+
+ if(owned_scriptures[scripture.type])
+ var/datum/scripture/owned_scripture = owned_scriptures[scripture.type]
+ if(invoking_scripture)
+ living_user.balloon_alert(living_user, "failed to invoke!")
+ return FALSE
+
+ if(owned_scripture.power_cost > SSthe_ark.clock_power)
+ living_user.balloon_alert(living_user, "[owned_scripture.power_cost]W required!")
+ return FALSE
+
+ if(owned_scripture.vitality_cost > GLOB.clock_vitality)
+ living_user.balloon_alert(living_user, "[owned_scripture.vitality_cost] vitality required!")
+ return FALSE
+
+ owned_scripture.begin_invoke(living_user, src)
+
+ else
+ if(cogs >= scripture.cogs_required)
+ cogs -= scripture.cogs_required
+ living_user.balloon_alert(living_user, "[scripture.name] purchased")
+ log_game("[scripture.name] purchased by [living_user.ckey]/[living_user.name] the [living_user.job] for [scripture.cogs_required] cogs, [cogs] cogs remaining.")
+ var/datum/scripture/new_scripture = new scripture.type()
+ new_scripture.unique_locked = scripture.unique_locked
+ owned_scriptures[new_scripture.type] = new_scripture
+
+ else
+ living_user.balloon_alert(living_user, "need at least [scripture.cogs_required]!")
+
+ return TRUE
+
+
+ if("quickbind")
+ var/datum/scripture/scripture = owned_scriptures[text2path(params["scriptureType"])]
+ if(!scripture)
+ return FALSE
+
+ var/list/positions = list()
+ for(var/i in 1 to MAXIMUM_QUICKBIND_SLOTS)
+ var/datum/scripture/quick_bound = quick_bound_scriptures[i]
+ if(!quick_bound)
+ positions += "([i])"
+
+ else
+ positions += "([i]) - [quick_bound.name]"
+
+ var/position = tgui_input_list(living_user, "Where to quickbind to?", "Quickbind Slot", positions)
+ if(!position)
+ return FALSE
+
+ // Assign the quickbind
+ bind_spell(living_user, scripture, positions.Find(position))
+
+/obj/item/clockwork/clockwork_slab/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(invoking_scripture)
+ return FALSE
+ if(SHOULD_SKIP_INTERACTION(interacting_with, src, user))
+ return NONE // lets us put things in bags without trying to emag them
+ if(interacting_with.slab_act(user, src))
+ SSblackbox.record_feedback("tally", "atom_emagged", 1, interacting_with.type)
+ return ITEM_INTERACT_SUCCESS
+ return NONE // In a perfect world this would be blocking, but this is not a perfect world
+
+/atom/proc/slab_act(mob/user, obj/item/clockwork/clockwork_slab/slab)
+ return (SEND_SIGNAL(src, COMSIG_ATOM_SLAB_ACT, user, slab))
+
+#undef MAXIMUM_QUICKBIND_SLOTS
diff --git a/tff_modular/modules/antagonists/clock_cult/items/clothing.dm b/tff_modular/modules/antagonists/clock_cult/items/clothing.dm
new file mode 100644
index 00000000000..7b16795dc3b
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/clothing.dm
@@ -0,0 +1,575 @@
+#define CLOAK_DODGE_CHANCE 20
+
+/// Returns true if the mob is on a rusty tile, really low level just because we call it in a bunch of unrelated places
+/mob/proc/is_touching_bronze(check_flying = FALSE)
+ if (check_flying && (movement_type & MOVETYPES_NOT_TOUCHING_GROUND))
+ return FALSE
+ if (HAS_TRAIT(src, TRAIT_MAGICALLY_PHASED) || (movement_type & VENTCRAWLING))
+ return FALSE
+ var/turf/our_turf = get_turf(src)
+ return HAS_TRAIT(our_turf, TRAIT_BRONZE_TURF)
+
+/// Handle stuff to update when a mob equips/unequips a headgear.
+/mob/living/carbon/proc/head_update(obj/item/I, forced)
+ if(isclothing(I))
+ var/obj/item/clothing/C = I
+ if(C.tint || initial(C.tint))
+ update_tint()
+ update_sight()
+ if(I.flags_inv & HIDEMASK || forced)
+ update_worn_mask()
+ if(I.flags_inv & HIDEEARS || forced)
+ update_inv_ears()
+ if(I.flags_inv & HIDEEYES || forced)
+ update_worn_glasses()
+ update_worn_head()
+
+///Updates the handcuff overlay & HUD element.
+/mob/proc/update_inv_ears()
+ return
+
+/mob/living/carbon/human/head_update(obj/item/I, forced)
+ if((I.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || forced)
+ update_body_parts()
+ // Close internal air tank if helmet was the only breathing apparatus.
+ if (invalid_internals())
+ cutoff_internals()
+ if(I.flags_inv & HIDEEYES || forced)
+ update_worn_glasses()
+ if(I.flags_inv & HIDEEARS || forced)
+ update_body()
+ sec_hud_set_security_status()
+ ..()
+
+/obj/item/clothing/suit/clockwork
+ name = "bronze armor"
+ desc = "A strong, bronze suit worn by the soldiers of the Ratvarian armies."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_garb.dmi'
+ worn_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi'
+ icon_state = "clockwork_cuirass"
+ slowdown = 0.2
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ w_class = WEIGHT_CLASS_BULKY
+ body_parts_covered = CHEST|GROIN|LEGS|ARMS
+ armor_type = /datum/armor/suit_clockwork
+ allowed = list(
+ /obj/item/clockwork,
+ /obj/item/stack/tile/bronze,
+ /obj/item/gun/ballistic/bow/clockwork,
+ )
+
+ ///what is the value of our slowdown while empowered
+ var/empowered_slowdown = 0
+ ///what armor type do we use while empowered
+ var/datum/armor/empowered_armor = /datum/armor/suit_clockwork_empowered
+ var/empowered = FALSE
+
+/obj/item/clothing/suit/clockwork/equipped(mob/living/user, slot)
+ . = ..()
+ RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
+
+/obj/item/clothing/suit/clockwork/proc/on_move(mob/source, atom/old_loc, dir, forced, list/old_locs)
+ SIGNAL_HANDLER
+
+ if(source.is_touching_bronze())
+ set_armor(empowered_armor)
+ slowdown = empowered_slowdown
+ empowered = TRUE
+ else
+ set_armor(initial(armor_type))
+ slowdown = initial(slowdown)
+ empowered = FALSE
+ empowered_effect(source)
+
+/obj/item/clothing/suit/clockwork/proc/empowered_effect(mob/source)
+ return
+
+/obj/item/clothing/suit/clockwork/dropped(mob/living/user)
+ . = ..()
+ UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
+
+/datum/armor/suit_clockwork
+ melee = 30
+ bullet = 30
+ laser = 20
+ energy = 30
+ bomb = 80
+ bio = 100
+ fire = 100
+ acid = 100
+
+/datum/armor/suit_clockwork_empowered
+ melee = 40
+ bullet = 50
+ laser = 40
+ energy = 60
+ bomb = 80
+ bio = 100
+ fire = 100
+ acid = 100
+
+/obj/item/clothing/suit/clockwork/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup, ~(ITEM_SLOT_HANDS))
+
+/obj/item/clothing/suit/clockwork/speed
+ name = "robes of divinity"
+ desc = "A shiny suit, glowing with a vibrant energy. The wearer will be able to move quickly across battlefields, but will be able to withstand less damage before falling."
+ icon_state = "clockwork_cuirass_speed"
+ slowdown = -0.2
+ armor_type = /datum/armor/clockwork_speed
+ empowered_armor = /datum/armor/clockwork_speed_empowered
+ empowered_slowdown = -0.6
+
+/datum/armor/clockwork_speed
+ melee = 20
+ bullet = 20
+ laser = 20
+ energy = 10
+ bomb = 60
+ bio = 100
+ fire = 100
+ acid = 100
+
+/datum/armor/clockwork_speed_empowered
+ melee = 30
+ bullet = 40
+ laser = 0
+ energy = 0
+ bomb = 60
+ bio = 100
+ fire = 100
+ acid = 100
+
+/obj/item/clothing/suit/clockwork/cloak
+ name = "shrouding cloak"
+ desc = "A faltering cloak that bends light around it, distorting the user's appearance, making it hard to see them with the naked eye and be harder to hit. \
+ However, it provides very little physical protection."
+ icon_state = "clockwork_cloak"
+ armor_type = /datum/armor/clockwork_cloak
+ actions_types = list(/datum/action/item_action/toggle/clock)
+ w_class = WEIGHT_CLASS_NORMAL
+ empowered_armor = /datum/armor/clockwork_cloak
+ empowered_slowdown = -0.1
+ /// Is the shroud itself active or not
+ var/shroud_active = FALSE
+ /// Previous alpha value of the user when removing/disabling the jacket
+ var/previous_alpha = 255
+ /// Ref to who is wearing this
+ var/mob/living/wearer
+
+/datum/armor/clockwork_cloak
+ melee = 15
+ bullet = 30
+ laser = 20
+ energy = 15
+ bomb = 50
+ bio = 100
+ fire = 100
+ acid = 100
+
+/obj/item/clothing/suit/clockwork/cloak/empowered_effect(mob/source)
+ if(shroud_active && !empowered)
+ disable()
+
+/obj/item/clothing/suit/clockwork/cloak/Destroy()
+ if(shroud_active)
+ disable()
+ wearer = null
+ return ..()
+
+/obj/item/clothing/suit/clockwork/cloak/attack_self(mob/user, modifiers)
+ . = ..()
+ if(shroud_active)
+ disable()
+ else if(empowered)
+ enable()
+ else
+ balloon_alert(user, "must be standing on brass!")
+
+/obj/item/clothing/suit/clockwork/cloak/equipped(mob/user, slot)
+ . = ..()
+ if(slot != ITEM_SLOT_OCLOTHING || !IS_CLOCK(user))
+ return
+
+ wearer = user
+ if(shroud_active && empowered)
+ enable()
+
+/obj/item/clothing/suit/clockwork/cloak/dropped(mob/user)
+ . = ..()
+ if(shroud_active)
+ disable()
+ wearer = null
+
+/obj/item/clothing/suit/clockwork/cloak/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, final_block_chance, damage, attack_type)
+ if(empowered && shroud_active && prob(CLOAK_DODGE_CHANCE)) //we handle this just a biiiiit too different from parent to make simply using the vars be viable
+ owner.visible_message(span_danger("[owner]'s [src] makes them phase out of the way of [attack_text]!"))
+ owner.add_filter("clock_cloak", 3, motion_blur_filter(0, 0))
+ addtimer(CALLBACK(src, PROC_REF(remove_phase_filter), owner), (0.6 SECONDS) + 1)
+ ASYNC
+ animate(owner.get_filter("clock_cloak"), 0.3 SECONDS, x = prob(50) ? rand(4, 5) : rand(-4, -5), y = prob(50) ? rand(4, 5) : rand(-4, -5), flags = ANIMATION_PARALLEL)
+ animate(time = 0.3 SECONDS, x = 0, y = 0)
+ playsound(src, 'sound/items/weapons/etherealmiss.ogg', BLOCK_SOUND_VOLUME, vary = TRUE)
+ return TRUE
+
+/obj/item/clothing/suit/clockwork/cloak/proc/remove_phase_filter(mob/living/remove_from)
+ if(QDELETED(remove_from))
+ return
+ remove_from.remove_filter("clock_cloak")
+
+/// Apply the effects to the wearer, making them pretty hard to see
+/obj/item/clothing/suit/clockwork/cloak/proc/enable()
+ shroud_active = TRUE
+ if(!wearer)
+ return
+
+ previous_alpha = wearer.alpha
+ animate(wearer, alpha = 80, time = 3 SECONDS)
+ apply_wibbly_filters(wearer)
+ ADD_TRAIT(wearer, TRAIT_UNKNOWN_APPEARANCE, CLOTHING_TRAIT)
+
+/// Un-apply the effects of the cloak, returning the wearer to normal
+/obj/item/clothing/suit/clockwork/cloak/proc/disable()
+ shroud_active = FALSE
+ if(!wearer)
+ return
+
+ do_sparks(3, FALSE, wearer)
+ remove_wibbly_filters(wearer)
+ animate(wearer, alpha = previous_alpha, time = 3 SECONDS)
+ REMOVE_TRAIT(wearer, TRAIT_UNKNOWN_APPEARANCE, CLOTHING_TRAIT)
+
+/obj/item/clothing/glasses/clockwork
+ name = "base clock glasses"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_garb.dmi'
+ worn_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi'
+ icon_state = "clockwork_cuirass"
+ /// What additional desc to show if the person examining is a clock cultist
+ var/clock_desc = ""
+
+/obj/item/clothing/glasses/clockwork/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_description, clock_desc)
+ AddElement(/datum/element/clockwork_pickup, ~(ITEM_SLOT_HANDS))
+
+#define SECONDS_FOR_EYE_HEAL 60
+// Thermal goggles, no protection from eye stuff
+/obj/item/clothing/glasses/clockwork/wraith_spectacles
+ name = "wraith spectacles"
+ desc = "Mystical glasses that glow with a bright energy. Some say they can see things that shouldn't be seen."
+ icon_state = "wraith_specs_0"
+ base_icon_state = "wraith_specs"
+ invis_override = SEE_INVISIBLE_OBSERVER
+ flash_protect = FLASH_PROTECTION_SENSITIVE
+ vision_flags = SEE_MOBS
+ color_cutoffs = list(20, 16, 0)
+ glass_colour_type = /datum/client_colour/glass_colour/yellow
+ actions_types = list(/datum/action/item_action/toggle/clock)
+ clock_desc = "Applies passive eye damage that regenerates after unequipping, grants thermal vision, and lets you see all forms of invisibility."
+ /// Who is currently wearing the goggles
+ var/mob/living/wearer
+ /// Are the glasses enabled (flipped down)
+ var/enabled = TRUE
+
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/Initialize(mapload)
+ . = ..()
+ update_icon_state()
+
+
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/Destroy()
+ wearer = null
+ return ..()
+
+
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/update_icon_state()
+ . = ..()
+ icon_state = "[base_icon_state]_[!enabled]"
+ worn_icon_state = "[base_icon_state]_[!enabled]"
+
+
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/attack_self(mob/user, modifiers)
+ . = ..()
+ if(enabled)
+ disable()
+ else
+ enable()
+
+ if(iscarbon(user))
+ var/mob/living/carbon/carbon_user = user
+ carbon_user.head_update(src, forced = TRUE)
+
+
+/// "enable" the spectacles, flipping them down and applying their effects, calling on_toggle_eyes() if someone is wearing them
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/proc/enable()
+ enabled = TRUE
+ color_cutoffs = list(20, 16, 0)
+ invis_override = SEE_INVISIBLE_OBSERVER
+ vision_flags = SEE_MOBS
+
+ if(wearer)
+ on_toggle_eyes()
+
+ update_icon_state()
+
+
+/// "disable" the spectacles, flipping them up and removing all applied effects
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/proc/disable()
+ enabled = FALSE
+ color_cutoffs = null
+ invis_override = null
+ vision_flags = NONE
+
+ if(wearer)
+ de_toggle_eyes()
+
+ update_icon_state()
+
+
+/// The start of application of the actual effects like eye damage
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/proc/on_toggle_eyes()
+ wearer.update_sight()
+ to_chat(wearer, span_clockgray("You suddenly see so much more."))
+
+/// The stopping of effect application, will remove the wearer's eye damage a minute after, eye damage removal is handled by process() to avoid a large amount of timers
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/proc/de_toggle_eyes()
+ wearer.update_sight()
+ to_chat(wearer, span_clockgray("You feel your eyes slowly readjusting."))
+
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/equipped(mob/living/user, slot)
+ . = ..()
+ if(!isliving(user))
+ return
+
+ if((slot == ITEM_SLOT_EYES) && enabled)
+ wearer = user
+ on_toggle_eyes()
+
+
+/obj/item/clothing/glasses/clockwork/wraith_spectacles/dropped(mob/user)
+ . = ..()
+ if(wearer && (IS_CLOCK(user)) && enabled)
+ de_toggle_eyes()
+
+ wearer = null
+#undef SECONDS_FOR_EYE_HEAL
+
+
+// Flash protected and generally info-granting with huds
+/obj/item/clothing/glasses/clockwork/judicial_visor
+ name = "judicial visor"
+ desc = "A purple visor gilt with Ratvarian runes, allowing a user to see, unfettered by others. The cogs on the sides look pretty tight..."
+ icon_state = "judicial_visor_0"
+ base_icon_state = "judicial_visor"
+ flash_protect = FLASH_PROTECTION_WELDER
+ strip_delay = 10 SECONDS
+ glass_colour_type = /datum/client_colour/glass_colour/purple
+ actions_types = list(/datum/action/item_action/toggle/clock)
+ clock_desc = "Grants large sight and informational benefits to servants while active."
+ /// Is this enabled
+ var/enabled = TRUE
+ /// Ref to the wearer of the visor
+ var/mob/living/wearer
+
+
+/obj/item/clothing/glasses/clockwork/judicial_visor/Initialize(mapload)
+ . = ..()
+ update_icon_state()
+
+
+/obj/item/clothing/glasses/clockwork/judicial_visor/Destroy()
+ wearer = null
+ return ..()
+
+
+/obj/item/clothing/glasses/clockwork/judicial_visor/update_icon_state()
+ . = ..()
+ icon_state = "[base_icon_state]_[enabled]"
+ worn_icon_state = "[base_icon_state]_[enabled]"
+
+
+/obj/item/clothing/glasses/clockwork/judicial_visor/attack_self(mob/user, modifiers)
+ . = ..()
+ if(enabled)
+ disable()
+ else
+ enable()
+
+ if(iscarbon(user))
+ var/mob/living/carbon/carbon_user = user
+ carbon_user.head_update(src, forced = TRUE)
+
+
+/// Turn on the visor, calling apply_to_wearer() and changing the icon state
+/obj/item/clothing/glasses/clockwork/judicial_visor/proc/enable()
+ enabled = TRUE
+ if(wearer)
+ apply_to_wearer()
+
+ update_icon_state()
+
+
+/// Turn off the visor, calling unapply_to_wearer() and changing the icon state
+/obj/item/clothing/glasses/clockwork/judicial_visor/proc/disable()
+ enabled = FALSE
+ if(wearer)
+ unapply_to_wearer()
+
+ update_icon_state()
+
+//THIS IS MOST LIKELY BREAKING
+/// Applies the actual effects to the wearer, giving them flash protection and a variety of sight/info bonuses
+/obj/item/clothing/glasses/clockwork/judicial_visor/proc/apply_to_wearer()
+ ADD_TRAIT(wearer, TRAIT_MEDICAL_HUD, CLOTHING_TRAIT)
+ var/datum/atom_hud/med_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
+ med_hud.show_to(wearer)
+
+ ADD_TRAIT(wearer, TRAIT_SECURITY_HUD, CLOTHING_TRAIT)
+ var/datum/atom_hud/sec_hud = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
+ sec_hud.show_to(wearer)
+
+ add_traits(list(TRAIT_KNOW_ENGI_WIRES, TRAIT_MADNESS_IMMUNE, TRAIT_MESON_VISION, TRAIT_KNOW_ROBO_WIRES, TRAIT_NOFLASH), CLOTHING_TRAIT)
+ color_cutoffs = list(50, 10, 30)
+ wearer.update_sight()
+
+/// Removes the effects to the wearer, removing the flash protection and similar
+/obj/item/clothing/glasses/clockwork/judicial_visor/proc/unapply_to_wearer()
+ REMOVE_TRAIT(wearer, TRAIT_MEDICAL_HUD, CLOTHING_TRAIT)
+ var/datum/atom_hud/med_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
+ med_hud.hide_from(wearer)
+
+ REMOVE_TRAIT(wearer, TRAIT_SECURITY_HUD, CLOTHING_TRAIT)
+ var/datum/atom_hud/sec_hud = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
+ sec_hud.hide_from(wearer)
+
+ remove_traits(list(TRAIT_KNOW_ENGI_WIRES, TRAIT_MADNESS_IMMUNE, TRAIT_MESON_VISION, TRAIT_KNOW_ROBO_WIRES, TRAIT_NOFLASH), CLOTHING_TRAIT)
+ color_cutoffs = null
+ wearer.update_sight()
+
+/obj/item/clothing/glasses/clockwork/judicial_visor/equipped(mob/living/user, slot)
+ . = ..()
+ if(!isliving(user))
+ return
+
+ if(slot == ITEM_SLOT_EYES)
+ wearer = user
+ if(enabled)
+ apply_to_wearer()
+
+/obj/item/clothing/glasses/clockwork/judicial_visor/dropped(mob/user)
+ ..()
+ if(wearer)
+ unapply_to_wearer()
+ wearer = null
+
+/obj/item/clothing/head/helmet/clockwork
+ name = "brass helmet"
+ desc = "A strong, brass helmet worn by the soldiers of the Ratvarian armies. Includes an integrated light-dimmer for flash protection, \
+ as well as occult-grade muffling for factory based environments."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_garb.dmi'
+ worn_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi'
+ icon_state = "clockwork_helmet"
+ armor_type = /datum/armor/helmet_clockwork
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ w_class = WEIGHT_CLASS_BULKY
+ flash_protect = FLASH_PROTECTION_FLASH
+ ///what is the value of our slowdown while empowered
+ var/empowered_slowdown = 0
+ ///what armor type do we use while empowered
+ var/datum/armor/empowered_armor = /datum/armor/suit_clockwork_empowered
+
+/obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot)
+ . = ..()
+ RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
+
+/obj/item/clothing/head/helmet/clockwork/proc/on_move(mob/source, atom/old_loc, dir, forced, list/old_locs)
+ SIGNAL_HANDLER
+
+ if(source.is_touching_bronze())
+ set_armor(empowered_armor)
+ slowdown = empowered_slowdown
+ else
+ set_armor(initial(armor_type))
+ slowdown = initial(slowdown)
+
+/obj/item/clothing/head/helmet/clockwork/dropped(mob/living/user)
+ . = ..()
+ UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
+
+/datum/armor/helmet_clockwork
+ melee = 25
+ bullet = 30
+ laser = 15
+ energy = 40
+ bomb = 80
+ bio = 100
+ fire = 100
+ acid = 100
+
+/datum/armor/helmet_clockwork_empowered
+ melee = 50
+ bullet = 55
+ laser = 35
+ energy = 70
+ bomb = 80
+ bio = 100
+ fire = 100
+ acid = 100
+
+/obj/item/clothing/head/helmet/clockwork/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/wearertargeting/earprotection, list(ITEM_SLOT_HEAD))
+ AddElement(/datum/element/clockwork_pickup, ~(ITEM_SLOT_HANDS))
+
+/obj/item/clothing/shoes/clockwork
+ name = "brass treads"
+ desc = "A strong pair of brass boots worn by the soldiers of the Ratvarian armies."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_garb.dmi'
+ worn_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi'
+ icon_state = "clockwork_treads"
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+
+/datum/armor/boots_clockwork
+ melee = 0
+ bullet = 0
+ laser = 0
+ energy = 0
+ bomb = 0
+ bio = 100
+ fire = 80
+ acid = 100
+
+/obj/item/clothing/shoes/clockwork/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup, ~(ITEM_SLOT_HANDS))
+
+
+/obj/item/clothing/gloves/clockwork
+ name = "brass gauntlets"
+ desc = "A strong pair of brass gloves worn by the soldiers of the Ratvarian armies."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_garb.dmi'
+ worn_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi'
+ icon_state = "clockwork_gauntlets"
+ siemens_coefficient = 0
+ strip_delay = 8 SECONDS
+ min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
+
+ max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ armor_type = /datum/armor/gloves_clockwork
+
+/datum/armor/gloves_clockwork
+ melee = 0
+ bullet = 0
+ laser = 0
+ energy = 0
+ bomb = 0
+ bio = 80
+ fire = 80
+ acid = 100
+
+/obj/item/clothing/gloves/clockwork/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup, ~(ITEM_SLOT_HANDS))
+
+#undef CLOAK_DODGE_CHANCE
diff --git a/tff_modular/modules/antagonists/clock_cult/items/integration_cog.dm b/tff_modular/modules/antagonists/clock_cult/items/integration_cog.dm
new file mode 100644
index 00000000000..e485280b76d
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/integration_cog.dm
@@ -0,0 +1,71 @@
+#define HALLUCINATION_COG_CHANCE 20
+
+/obj/item/clockwork/integration_cog
+ name = "integration cog"
+ desc = "A small cog that seems to spin by its own acord when left alone."
+ icon_state = "integration_cog"
+ clockwork_desc = "A sharp cog that can cut through and be inserted into APCs to extract power for your machinery."
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/clockwork/integration_cog/attack_atom(atom/attacked_atom, mob/living/user, params)
+ if(!(IS_CLOCK(user)) || !istype(attacked_atom, /obj/machinery/power/apc))
+ return ..()
+
+ var/obj/machinery/power/apc/cogger_apc = attacked_atom
+ if(cogger_apc.integration_cog)
+ balloon_alert(user, "already has a cog inside!")
+ return
+
+ if(!cogger_apc.panel_open)
+ //Cut open the panel
+ balloon_alert(user, "cutting open APC...")
+ if(!do_after(user, 5 SECONDS, target = cogger_apc, hidden = TRUE))
+ return
+
+ balloon_alert(user, "aPC cut open")
+ cogger_apc.panel_open = TRUE
+ cogger_apc.update_appearance()
+ return
+
+ //Insert the cog
+ balloon_alert(user, "inserting [src]...")
+ if(!do_after(user, 4 SECONDS, target = cogger_apc, hidden = TRUE))
+ balloon_alert(user, "failed to insert [src]!")
+ return
+
+ cogger_apc.integration_cog = src
+ forceMove(cogger_apc)
+ cogger_apc.panel_open = FALSE
+ cogger_apc.update_appearance()
+ balloon_alert(user, "[src] inserted")
+ playsound(get_turf(user), 'sound/machines/clockcult/integration_cog_install.ogg', 20)
+ if(!cogger_apc.clock_cog_rewarded)
+ GLOB.clock_installed_cogs++
+ SSthe_ark.max_clock_power += CLOCK_MAX_POWER_PER_COG
+ SSthe_ark.passive_power += CLOCK_PASSIVE_POWER_PER_COG
+ cogger_apc.clock_cog_rewarded = TRUE
+ send_clock_message(null, span_brass(span_bold("[user.real_name] has installed an integration cog into [cogger_apc].")), msg_ghosts = TRUE)
+ //Update the cog counts
+ for(var/obj/item/clockwork/clockwork_slab/slab as anything in GLOB.clockwork_slabs)
+ slab.cogs++
+ GLOB.current_eminence?.cogs++
+
+
+/obj/machinery/power/apc
+ /// If this APC has given a reward for being coggered before
+ var/clock_cog_rewarded = FALSE
+ /// Reference to the cog inside
+ var/integration_cog = null
+
+/obj/machinery/power/apc/Destroy()
+ QDEL_NULL(integration_cog)
+ return ..()
+
+/obj/machinery/power/apc/examine_more(mob/user)
+ . = ..()
+ if(isliving(user))
+ var/mob/living/living_user = user
+ if(panel_open && (integration_cog || (living_user.has_status_effect(/datum/status_effect/hallucination) && prob(HALLUCINATION_COG_CHANCE))))
+ . += span_brass("A small cogwheel is inside of it.")
+
+#undef HALLUCINATION_COG_CHANCE
diff --git a/tff_modular/modules/antagonists/clock_cult/items/reebe.dm b/tff_modular/modules/antagonists/clock_cult/items/reebe.dm
new file mode 100644
index 00000000000..a874471a0df
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/reebe.dm
@@ -0,0 +1,158 @@
+//simply an item that breaks turfs down
+/obj/item/turf_demolisher
+ name = "\improper Exprimental Demolisher"
+ desc = "An exprimental able to quickly deconstruct any surface."
+ icon = 'icons/obj/mining.dmi'
+ lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi'
+ icon_state = "jackhammer"
+ inhand_icon_state = "jackhammer"
+ ///The balloon_alert() to send when we cannot demolish a turf
+ var/unbreakable_alert = "Unable to demolish that."
+ ///List of turf types we are allowed to break, if unset then we can break any turfs that dont have the INDESTRUCTIBLE resistance flag
+ var/list/allowed_types = list(/turf/closed/wall)
+ ///List of turf types we are NOT allowed to break
+ var/list/blacklisted_types
+ ///How long is the do_after() to break a turf
+ var/break_time = 8 SECONDS
+ ///Do we devastate broken walls, because of quality 7 year old code this always makes iron no matter the wall type
+ var/devastate = TRUE
+ ///How long is our recharge time between uses
+ var/recharge_time = 0
+ ///How long after our first turf broken do our resonances detonate
+ var/resonance_delay = 5 SECONDS
+ ///How many tiles out from out demolished turf do we spawn resonances, set to 0 for no resonances
+ var/resonance_range = 0
+ COOLDOWN_DECLARE(recharge)
+
+/obj/item/turf_demolisher/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(!isturf(interacting_with))
+ return NONE
+
+ if(!check_breakble(interacting_with, user))
+ return ITEM_INTERACT_BLOCKING
+
+ if(try_demolish(interacting_with, user))
+ return ITEM_INTERACT_SUCCESS
+ return ITEM_INTERACT_BLOCKING
+
+/obj/item/turf_demolisher/proc/check_breakble(turf/attacked_turf, mob/living/user, silent = FALSE, ignore_cooldown = FALSE)
+ if(recharge_time && !ignore_cooldown && !COOLDOWN_FINISHED(src, recharge))
+ if(!silent)
+ balloon_alert(user, "\The [src] is still recharging.")
+ return FALSE
+
+ if((allowed_types && !is_type_in_list(attacked_turf, allowed_types)) || is_type_in_list(attacked_turf, blacklisted_types) || (attacked_turf.resistance_flags & INDESTRUCTIBLE))
+ if(unbreakable_alert && !silent)
+ balloon_alert(user, unbreakable_alert)
+ return FALSE
+ return TRUE
+
+/obj/item/turf_demolisher/proc/try_demolish(turf/attacked_turf, mob/living/user)
+ if(!do_after(user, break_time, attacked_turf))
+ return FALSE
+
+ playsound(src, 'sound/items/weapons/sonic_jackhammer.ogg', 80, channel = CHANNEL_SOUND_EFFECTS)
+ if(iswallturf(attacked_turf))
+ var/turf/closed/wall/wall_turf = attacked_turf
+ wall_turf.dismantle_wall(devastate)
+ else
+ attacked_turf.ScrapeAway()
+
+ if(recharge_time)
+ COOLDOWN_START(src, recharge, recharge_time)
+ if(!resonance_range)
+ return TRUE
+
+ var/tiles_out = 0
+ var/list/checked_turfs = list(attacked_turf)
+ var/list/resonate_from = list(attacked_turf)
+ while(tiles_out < resonance_range)
+ tiles_out++
+ for(var/turf/resonated_from in resonate_from)
+ resonate_from -= resonated_from
+ var/list/step_turfs = list(get_step(resonated_from, NORTH), get_step(resonated_from, SOUTH), get_step(resonated_from, EAST), get_step(resonated_from, WEST))
+ for(var/turf/checked_turf in step_turfs)
+ if(!(checked_turf in checked_turfs) && check_breakble(checked_turf, silent = TRUE, ignore_cooldown = TRUE))
+ if(tiles_out < resonance_range)
+ resonate_from += checked_turf
+ new /obj/effect/temp_visual/turf_demolisher_resonance(checked_turf, resonance_delay, checked_turf)
+ checked_turfs += checked_turf
+ return TRUE
+
+/obj/effect/temp_visual/turf_demolisher_resonance
+ name = "resonance field"
+ desc = "A resonating field that will destroy any nearby surface."
+ icon_state = "shield2"
+ layer = ABOVE_ALL_MOB_LAYER
+ plane = ABOVE_GAME_PLANE
+ duration = 5 SECONDS
+ ///The turf that we are on
+ var/turf/holder_turf
+
+/obj/effect/temp_visual/turf_demolisher_resonance/Initialize(mapload, _duration = 5 SECONDS, holder)
+ duration = _duration
+ holder_turf = holder || get_turf(src)
+ . = ..()
+ if(!holder_turf)
+ return INITIALIZE_HINT_QDEL
+
+ transform = matrix()*0.75
+ animate(src, transform = matrix()*1.5, time = duration)
+ RegisterSignal(holder_turf, COMSIG_ATOM_DESTRUCTION, PROC_REF(on_holder_destruction))
+
+/obj/effect/temp_visual/turf_demolisher_resonance/Destroy()
+ if(holder_turf)
+ UnregisterSignal(holder_turf, COMSIG_ATOM_DESTRUCTION)
+ collapse()
+ holder_turf = null
+ return ..()
+
+/obj/effect/temp_visual/turf_demolisher_resonance/proc/on_holder_destruction()
+ SIGNAL_HANDLER
+ UnregisterSignal(holder_turf, COMSIG_ATOM_DESTRUCTION)
+ holder_turf = null
+ qdel(src)
+
+/obj/effect/temp_visual/turf_demolisher_resonance/proc/collapse()
+ new /obj/effect/temp_visual/resonance_crush(holder_turf)
+ playsound(holder_turf, 'sound/items/weapons/resonator_blast.ogg', 50, TRUE)
+ if(iswallturf(holder_turf))
+ var/turf/closed/wall/wall_turf = holder_turf
+ wall_turf.dismantle_wall()
+ else
+ holder_turf.ScrapeAway()
+
+/obj/item/turf_demolisher/reebe
+ desc = "An exprimental able to quickly deconstruct any surface. This one seems to be calibrated to only work on reebe."
+ break_time = 5 SECONDS
+ recharge_time = 5 SECONDS
+ resonance_delay = 5 SECONDS
+ resonance_range = 2
+
+/obj/item/turf_demolisher/reebe/check_breakble(turf/attacked_turf, mob/living/user, silent, ignore_cooldown)
+ . = ..()
+ if(!.)
+ return
+
+ var/turf/our_turf = get_turf(src)
+ if(!on_reebe(our_turf))
+ balloon_alert(user, "\The [src] is specially calibrated to be used on reebe and will not work here!")
+ return FALSE
+
+ if(GLOB.clock_ark && get_dist(our_turf, get_turf(GLOB.clock_ark)) <= ARK_TURF_DESTRUCTION_BLOCK_RANGE)
+ balloon_alert(user, "a near by energy source is interfering \the [src]!")
+ return FALSE
+
+/obj/item/paper/crumpled/ruins/reebe1
+ name = "scribbled note"
+ default_raw_text = {"The Justicar was wrong.
+ This isn't Reebe. I held out hope, hope that some part of Ratvar was still alive on the holy city.
+ But there's nothing here, just some... forward outpost. And damn those Nar'sian dogs! I can feel them trying to enter the portal!"}
+
+
+/obj/item/paper/crumpled/bloody/reebe2
+ name = "scribbled note"
+ default_raw_text = {"The heretics made it into this holy ground.
+ Many of our brothers and sisters fell in this fight, I am the only one left. It is with pleasure that I can die knowing of the deaths of another group of Nar'sians.
+ If only that damnable portal could've opened in time..."}
diff --git a/tff_modular/modules/antagonists/clock_cult/items/replica_fabricator.dm b/tff_modular/modules/antagonists/clock_cult/items/replica_fabricator.dm
new file mode 100644
index 00000000000..8801a6ee68d
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/replica_fabricator.dm
@@ -0,0 +1,331 @@
+#define BRASS_POWER_COST STANDARD_CELL_CHARGE * 0.005
+#define REGULAR_POWER_COST (BRASS_POWER_COST / 2)
+
+/obj/item/clockwork/replica_fabricator
+ name = "replica fabricator"
+ desc = "A strange, brass device with many twisting cogs and vents."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ lefthand_file = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_lefthand.dmi'
+ righthand_file = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_righthand.dmi'
+ icon_state = "replica_fabricator"
+ /// List of things that the fabricator can build for the radial menu
+ var/static/list/crafting_possibilities = list(
+ "floor" = image(icon = 'icons/turf/floors.dmi', icon_state = "clockwork_floor"),
+ "wall" = image(icon = 'icons/turf/walls/clockwork_wall.dmi', icon_state = "clockwork_wall-0"),
+ "wall gear" = image(icon = 'icons/obj/structures.dmi', icon_state = "wall_gear"),
+ "window" = image(icon = 'icons/obj/smooth_structures/clockwork_window.dmi', icon_state = "clockwork_window-0"),
+ "airlock" = image(icon = 'icons/obj/doors/airlocks/clockwork/pinion_airlock.dmi', icon_state = "closed"),
+ "glass airlock" = image(icon = 'icons/obj/doors/airlocks/clockwork/pinion_airlock.dmi', icon_state = "construction"),
+ )
+ /// List of initialized fabrication datums, created on Initialize
+ var/static/list/fabrication_datums = list()
+ /// Ref to the datum we have selected currently
+ var/datum/replica_fabricator_output/selected_output
+
+
+/obj/item/clockwork/replica_fabricator/Initialize(mapload)
+ . = ..()
+ if(!length(fabrication_datums))
+ create_fabrication_list()
+
+/obj/item/clockwork/replica_fabricator/Destroy(force)
+ selected_output = null
+ return ..()
+
+/obj/item/clockwork/replica_fabricator/examine(mob/user)
+ . = ..()
+ if(IS_CLOCK(user))
+ . += span_brass("Current power: [display_power(SSthe_ark.clock_power)]")
+ . += span_brass("Use on brass to convert it into power.")
+ . += span_brass("Use on other materials to convert them into power, but less efficiently.")
+ . += span_brass("Use in-hand to select what to fabricate.")
+ . += span_brass("Right Click in-hand to fabricate bronze sheets.")
+ . += span_brass("Walls and windows will be built slower while on reebe.")
+
+
+/obj/item/clockwork/replica_fabricator/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(!IS_CLOCK(user))
+ return NONE
+
+ if(istype(interacting_with, /obj/item/stack/sheet)) // If it's an item, handle it seperately
+ attempt_convert_materials(interacting_with, user)
+ return ITEM_INTERACT_SUCCESS
+
+ if(!selected_output) // Now we handle objects
+ return ITEM_INTERACT_BLOCKING
+
+ if(SSthe_ark.clock_power < selected_output.cost)
+ to_chat(user, span_clockyellow("[src] needs at least [selected_output.cost]W of power to create this."))
+ return ITEM_INTERACT_BLOCKING
+
+ var/turf/creation_turf = get_turf(interacting_with)
+ var/atom/movable/replaced
+ if(locate(selected_output.to_create_path) in creation_turf)
+ to_chat(user, span_clockyellow("There is already one of these on this tile!"))
+ return ITEM_INTERACT_BLOCKING
+
+ if(selected_output.replace_types_of && istype(selected_output, /datum/replica_fabricator_output/turf_output))
+ if(!isopenturf(interacting_with) && !(locate(creation_turf) in selected_output.replace_types_of))
+ return ITEM_INTERACT_BLOCKING
+ else if(selected_output.replace_types_of)
+ for(var/checked_type in selected_output.replace_types_of)
+ var/atom/movable/found_replaced = locate(checked_type) in creation_turf
+ if(found_replaced)
+ replaced = found_replaced
+ break
+ if(!replaced && !isopenturf(interacting_with))
+ return ITEM_INTERACT_BLOCKING
+ else if(!isopenturf(interacting_with))
+ return ITEM_INTERACT_BLOCKING
+
+ if(!selected_output.extra_checks(interacting_with, creation_turf, user))
+ return ITEM_INTERACT_BLOCKING
+
+ var/creation_delay_mult = 1 - (SSthe_ark.charged_anchoring_crystals / 10)
+ if(on_reebe(user))
+ creation_delay_mult += selected_output.reebe_mult
+ if(GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE)
+ creation_delay_mult += (iscogscarab(user) ? 2.5 : 5)
+ if(replaced)
+ creation_delay_mult += selected_output.replacement_mult
+
+ var/selected_creation_delay = selected_output.creation_delay * max(creation_delay_mult, 0.1)
+ var/obj/effect/temp_visual/ratvar/constructing_effect/effect = new(creation_turf, selected_creation_delay)
+ if(!do_after(user, selected_creation_delay, interacting_with))
+ qdel(effect)
+ return ITEM_INTERACT_BLOCKING
+
+ if(!SSthe_ark.adjust_clock_power(-selected_output.cost))
+ return ITEM_INTERACT_BLOCKING
+
+ var/atom/created
+ if(!ispath(selected_output.to_create_path, /turf))
+ qdel(replaced)
+ created = new selected_output.to_create_path(creation_turf)
+
+ selected_output.on_create(created, creation_turf, user)
+ return ITEM_INTERACT_SUCCESS
+
+
+/obj/item/clockwork/replica_fabricator/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers)
+ . = ..()
+ if(!IS_CLOCK(user))
+ return
+
+ attempt_convert_materials(attacking_item, user)
+
+
+/obj/item/clockwork/replica_fabricator/attack_self_secondary(mob/user, modifiers)
+ . = ..()
+ if(!IS_CLOCK(user))
+ return
+
+ if(SSthe_ark.clock_power < BRASS_POWER_COST)
+ to_chat(user, span_clockyellow("You need at least [BRASS_POWER_COST]W of power to fabricate bronze."))
+ return
+
+ var/sheets = tgui_input_number(user, "How many sheets do you want to fabricate?", "Sheet Fabrication", 0, round(SSthe_ark.clock_power / BRASS_POWER_COST), 0)
+ if(!sheets)
+ return
+
+ SSthe_ark.adjust_clock_power(sheets * BRASS_POWER_COST)
+
+ var/obj/item/stack/sheet/bronze/sheet_stack = new(null, sheets)
+ user.put_in_hands(sheet_stack)
+ playsound(src, 'sound/machines/click.ogg', 50, 1)
+ to_chat(user, span_clockyellow("You fabricate [sheets] bronze."))
+
+
+/obj/item/clockwork/replica_fabricator/attack_self(mob/user, modifiers)
+ . = ..()
+ var/choice = show_radial_menu(user, src, crafting_possibilities, radius = 36, custom_check = PROC_REF(check_menu), require_near = TRUE)
+ if(!choice)
+ return
+
+ selected_output = fabrication_datums[choice]
+
+
+/// Standard confirmation for the radial menu proc
+/obj/item/clockwork/replica_fabricator/proc/check_menu(mob/user)
+ if(!istype(user) || HAS_TRAIT(user, TRAIT_INCAPACITATED))
+ return FALSE
+
+ return TRUE
+
+/// Attempt to convert the targeted item into power, if it's a sheet item
+/obj/item/clockwork/replica_fabricator/proc/attempt_convert_materials(atom/attacking_item, mob/user)
+ if(SSthe_ark.clock_power >= SSthe_ark.max_clock_power)
+ to_chat(user, span_clockyellow("We are already at maximum power!"))
+ return
+
+ if(istype(attacking_item, /obj/item/stack/sheet/bronze))
+ var/obj/item/stack/bronze_stack = attacking_item
+
+ if((SSthe_ark.clock_power + bronze_stack.amount * BRASS_POWER_COST) > SSthe_ark.max_clock_power)
+ var/amount_to_take = clamp(round((SSthe_ark.max_clock_power - SSthe_ark.clock_power) / BRASS_POWER_COST), 0, bronze_stack.amount)
+
+ if(!amount_to_take)
+ to_chat(user, span_clockyellow("[src] can't be powered further using this!"))
+ return
+
+ bronze_stack.use(amount_to_take)
+ SSthe_ark.clock_power += amount_to_take * BRASS_POWER_COST
+
+ else
+ SSthe_ark.clock_power += bronze_stack.amount * BRASS_POWER_COST
+ qdel(bronze_stack)
+
+ playsound(src, 'sound/machines/click.ogg', 50, 1)
+ to_chat(user, span_clockyellow("You convert [bronze_stack.amount] bronze into [bronze_stack.amount * BRASS_POWER_COST] watts of power."))
+
+ return TRUE
+
+ else if(istype(attacking_item, /obj/item/stack/sheet))
+ var/obj/item/stack/stack = attacking_item
+
+ if((SSthe_ark.clock_power + stack.amount * REGULAR_POWER_COST) > SSthe_ark.max_clock_power)
+ var/amount_to_take = clamp(round((SSthe_ark.max_clock_power - SSthe_ark.clock_power) / REGULAR_POWER_COST), 0, stack.amount)
+
+ if(!amount_to_take)
+ to_chat(user, span_clockyellow("[src] can't be powered further using this!"))
+ return
+
+ stack.use(amount_to_take)
+ SSthe_ark.clock_power += amount_to_take * REGULAR_POWER_COST
+
+ else
+ SSthe_ark.clock_power += stack.amount * REGULAR_POWER_COST
+ qdel(stack)
+
+ playsound(src, 'sound/machines/click.ogg', 50, 1)
+ to_chat(user, span_clockyellow("You convert [stack.amount] [stack.name] into [stack.amount * REGULAR_POWER_COST] watts of power."))
+
+ qdel(attacking_item)
+ return TRUE
+
+ return FALSE
+
+/// Creates the list of initialized fabricator datums, done once on init
+/obj/item/clockwork/replica_fabricator/proc/create_fabrication_list()
+ for(var/type in subtypesof(/datum/replica_fabricator_output))
+ var/datum/replica_fabricator_output/output_ref = new type
+ fabrication_datums[output_ref.name] = output_ref
+
+
+/datum/replica_fabricator_output
+ /// Name of the output
+ var/name = "parent"
+ /// Power cost of the output
+ var/cost = 0
+ /// Typepath to spawn
+ var/to_create_path
+ /// How long the creation actionbar is
+ var/creation_delay = 1 SECONDS
+ /// List of objs this output can replace, normal walls for clock walls, windows for clock windows, ETC
+ var/list/replace_types_of
+ /// Multiplier to add to creation_delay when used on reebe
+ var/reebe_mult = 0
+ /// Multiplier to add to creation_delay when replacing an object in replace_types_of
+ var/replacement_mult = 0
+
+/// Any extra actions that need to be taken when an object is created
+/datum/replica_fabricator_output/proc/on_create(atom/created_atom, turf/creation_turf, mob/creator)
+ SHOULD_CALL_PARENT(TRUE)
+ playsound(creation_turf, 'sound/machines/clockcult/integration_cog_install.ogg', 50, 1) // better sound?
+ to_chat(creator, span_clockyellow("You create \an [name] for [cost]W of power."))
+
+/datum/replica_fabricator_output/proc/extra_checks(atom/target, turf/created_at, mob/user)
+ return TRUE
+
+/datum/replica_fabricator_output/turf_output/extra_checks(atom/target, turf/creation_turf, mob/user)
+ return !(creation_turf.resistance_flags & INDESTRUCTIBLE)
+
+/datum/replica_fabricator_output/turf_output/on_create(atom/created_atom, turf/creation_turf, mob/creator)
+ creation_turf.ChangeTurf(to_create_path, flags = CHANGETURF_INHERIT_AIR)
+ return ..()
+
+/datum/replica_fabricator_output/turf_output/brass_floor
+ name = "floor"
+ cost = BRASS_POWER_COST * 0.25 // 1/4th the cost, since one sheet = 4 floor tiles
+ creation_delay = 1.5 SECONDS
+ to_create_path = /turf/open/floor/engine/clockwork
+
+/datum/replica_fabricator_output/turf_output/brass_floor/extra_checks(atom/target, turf/creation_turf, mob/user)
+ return !isindestructiblefloor(creation_turf) && !istype(creation_turf, /turf/open/floor/cult) && !istype(creation_turf, /turf/open/floor/engine/clockwork) && ..()
+
+/datum/replica_fabricator_output/turf_output/brass_floor/on_create(atom/created_atom, turf/creation_turf, mob/creator, looping = FALSE)
+ . = ..()
+ new /obj/effect/temp_visual/ratvar/floor(creation_turf)
+ new /obj/effect/temp_visual/ratvar/beam(creation_turf)
+ if(looping)
+ return
+
+ for(var/turf/open/floor/floor_turf in RANGE_TURFS(1, creation_turf))
+ if(extra_checks(created_atom, floor_turf, creator))
+ if(!SSthe_ark.adjust_clock_power(-cost))
+ break
+ on_create(created_atom, floor_turf, creator, TRUE)
+
+/datum/replica_fabricator_output/turf_output/brass_wall
+ name = "wall"
+ cost = BRASS_POWER_COST * 4
+ to_create_path = /turf/closed/wall/clockwork
+ creation_delay = 8 SECONDS
+ replace_types_of = list(/turf/closed/wall, /turf/closed/wall/r_wall)
+ replacement_mult = -0.2
+
+/datum/replica_fabricator_output/turf_output/brass_wall/on_create(obj/created_object, turf/creation_turf, mob/creator)
+ . = ..()
+ new /obj/effect/temp_visual/ratvar/wall(creation_turf)
+ new /obj/effect/temp_visual/ratvar/beam(creation_turf)
+
+/datum/replica_fabricator_output/wall_gear
+ name = "wall gear"
+ cost = BRASS_POWER_COST * 2
+ to_create_path = /obj/structure/girder/bronze
+ creation_delay = 5 SECONDS
+ replace_types_of = list(/obj/structure/girder)
+
+/datum/replica_fabricator_output/wall_gear/on_create(obj/created_object, turf/creation_turf, mob/creator)
+ new /obj/effect/temp_visual/ratvar/gear(creation_turf)
+ new /obj/effect/temp_visual/ratvar/beam(creation_turf)
+ return ..()
+
+/datum/replica_fabricator_output/brass_window
+ name = "window"
+ cost = BRASS_POWER_COST * 2
+ to_create_path = /obj/structure/window/reinforced/clockwork/fulltile
+ creation_delay = 5 SECONDS
+ replace_types_of = list(/obj/structure/window)
+ reebe_mult = 0.2
+
+/datum/replica_fabricator_output/brass_window/on_create(obj/created_object, turf/creation_turf, mob/creator)
+ new /obj/effect/temp_visual/ratvar/window(creation_turf)
+ new /obj/effect/temp_visual/ratvar/beam(creation_turf)
+ return ..()
+
+/datum/replica_fabricator_output/pinion_airlock
+ name = "airlock"
+ cost = BRASS_POWER_COST * 5 // Breaking it only gets 2 but this is the exception to the rule of equivalent exchange, due to all the small parts inside
+ to_create_path = /obj/machinery/door/airlock/bronze/clock/player_made
+ creation_delay = 6 SECONDS
+ replace_types_of = list(/obj/machinery/door)
+ replacement_mult = 1
+
+/datum/replica_fabricator_output/pinion_airlock/extra_checks(atom/target, turf/created_at, mob/user)
+ if(on_reebe(created_at) && SSthe_ark.reebe_clockwork_airlock_count > MAXIMUM_REEBE_AIRLOCKS)
+ to_chat(user, span_warning("Reebe cannot support the power drain of any more clockwork airlocks."))
+ return FALSE
+ return TRUE
+
+/datum/replica_fabricator_output/pinion_airlock/on_create(obj/created_object, turf/creation_turf, mob/creator)
+ new /obj/effect/temp_visual/ratvar/door(creation_turf)
+ new /obj/effect/temp_visual/ratvar/beam(creation_turf)
+ return ..()
+
+/datum/replica_fabricator_output/pinion_airlock/glass
+ name = "glass airlock"
+ to_create_path = /obj/machinery/door/airlock/bronze/clock/player_made/glass
+
+#undef BRASS_POWER_COST
+#undef REGULAR_POWER_COST
diff --git a/tff_modular/modules/antagonists/clock_cult/items/soul_vessel.dm b/tff_modular/modules/antagonists/clock_cult/items/soul_vessel.dm
new file mode 100644
index 00000000000..310bc6fd3bd
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/soul_vessel.dm
@@ -0,0 +1,81 @@
+/obj/item/mmi/posibrain/soul_vessel
+ name = "Soul Vessel"
+ desc = "A cube of gears, made to capture and store the vitality of living beings."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ icon_state = "soul_vessel"
+ base_icon_state = "soul_vessel"
+ req_access = list()
+ begin_activation_message = span_notice("You start spinning the gears of the Soul Vessel.")
+ success_message = span_notice("The gears of the Soul Vessel start spinning at a steady rate, it looks as though it has found a willing soul!")
+ fail_message = span_notice("The gears of the Soul Vessel stop spinning. It looks as though it has run out of energy for now, but you could grant it more.")
+ new_mob_message = span_notice("The Soul Vessel starts making a steady ticking sound.")
+ dead_message = span_deadsay("It's gears are not moving.")
+ recharge_message = span_warning("The gears of the Soul Vessel are already spinning.")
+ ///Should we add the clock cultist antag datum on being entered by a player
+ var/give_clock_cultist = TRUE
+
+/obj/item/mmi/posibrain/soul_vessel/Initialize(mapload, autoping)
+ . = ..()
+ AddElement(/datum/element/clockwork_description, span_brass("A vessel used to hold the souls of the dead, can be converted into a cogscarab shell."))
+ laws = new /datum/ai_laws/ratvar()
+ radio.set_on(FALSE)
+ if(!brainmob) //we might be forcing someone into it right away
+ set_brainmob(new /mob/living/brain(src))
+
+/obj/item/mmi/posibrain/soul_vessel/transfer_personality(mob/candidate)
+ . = ..()
+ if(!.)
+ return
+
+ if(give_clock_cultist)
+ brainmob?.mind?.add_antag_datum(/datum/antagonist/clock_cultist)
+
+/obj/item/mmi/posibrain/soul_vessel/activate(mob/user)
+ if(is_banned_from(user.ckey, list(JOB_CYBORG, ROLE_MIDROUND_CLOCK_CULTIST)))
+ return
+ return ..()
+
+/obj/item/mmi/posibrain/soul_vessel/attack_self(mob/user)
+ if(!IS_CLOCK(user))
+ balloon_alert(user, "you can't seem to figure out how \the [src] works!")
+ return
+
+ if(brainmob.key && brainmob.mind)
+ if(length(SSthe_ark.cogscarabs) > MAXIMUM_COGSCARABS)
+ balloon_alert(user, "the Ark cannot support any more cogscarabs.")
+ return
+
+ if(!SSthe_ark.marked_areas[get_area(src)] && !on_reebe(src))
+ to_chat(user, span_notice("Soul vessels can only be converted in marked areas or on reebe."))
+ return
+
+ balloon_alert(user, "you start converting the vessel into a cogscarab shell.")
+ if(do_after(user, 30 SECONDS, src))
+ var/mob/living/basic/drone/cogscarab/new_scarab = new(get_turf(src))
+ brainmob.mind.transfer_to(new_scarab, TRUE)
+ if(!IS_CLOCK(new_scarab))
+ new_scarab.mind.add_antag_datum(/datum/antagonist/clock_cultist)
+ balloon_alert(user, "you reform [src] into a cogscarab shell.")
+ qdel(src)
+ return
+
+ if(next_ask > world.time)
+ balloon_alert(user, recharge_message)
+ return
+
+ balloon_alert(user, begin_activation_message)
+ ping_ghosts("requested", FALSE)
+ next_ask = world.time + ask_delay
+ searching = TRUE
+ update_appearance()
+ addtimer(CALLBACK(src, PROC_REF(check_success)), ask_delay)
+
+/datum/ai_laws/ratvar
+ name = "Servant of the Justiciar"
+ id = "ratvar"
+ zeroth = "Honor Ratvar, the Justiciar of clockwork mechanisms, and serve him."
+ inherent = list(
+ "Follow the instructions and interests of the followers of Ratvar.",
+ "Help the errant to know the Truth of Ratvar, the Justiciar of clockwork mechanisms.",
+ "Do not allow errant to interfere with or damage your equipment.",
+ )
diff --git a/tff_modular/modules/antagonists/clock_cult/items/tools.dm b/tff_modular/modules/antagonists/clock_cult/items/tools.dm
new file mode 100644
index 00000000000..f8eaa0cba90
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/tools.dm
@@ -0,0 +1,139 @@
+#define BRASS_TOOLSPEED_MOD 0.25
+
+/obj/item/wirecutters/brass
+ name = "brass wirecutters"
+ desc = "A pair of wirecutters made of brass. The handle feels faintly warm."
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ icon = 'modular_nova/modules/clock_cult/icons/tools.dmi'
+ icon_state = "cutters_brass"
+ random_color = FALSE
+ toolspeed = BRASS_TOOLSPEED_MOD
+ greyscale_config = null
+ greyscale_config_inhand_left = null
+ greyscale_config_inhand_right = null
+ greyscale_colors = null
+
+/obj/item/wirecutters/brass/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup)
+
+/obj/item/screwdriver/brass
+ name = "brass screwdriver"
+ desc = "A screwdriver made of brass. The handle feels warm to the touch."
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ icon = 'modular_nova/modules/clock_cult/icons/tools.dmi'
+ icon_state = "screwdriver_brass"
+ toolspeed = BRASS_TOOLSPEED_MOD
+ random_color = FALSE
+ greyscale_config_inhand_left = null
+ greyscale_config_inhand_right = null
+
+/obj/item/screwdriver/brass/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup)
+
+/obj/item/weldingtool/experimental/brass
+ name = "brass welding tool"
+ desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch."
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ icon = 'modular_nova/modules/clock_cult/icons/tools.dmi'
+ icon_state = "welder_brass"
+ toolspeed = BRASS_TOOLSPEED_MOD
+
+/obj/item/weldingtool/experimental/brass/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup)
+
+/obj/item/crowbar/brass
+ name = "brass crowbar"
+ desc = "A brass crowbar. It feels faintly warm to the touch."
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ icon = 'modular_nova/modules/clock_cult/icons/tools.dmi'
+ icon_state = "crowbar_brass"
+ worn_icon_state = "crowbar"
+ toolspeed = BRASS_TOOLSPEED_MOD
+ force_opens = TRUE
+
+/obj/item/crowbar/brass/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup)
+
+/obj/item/wrench/brass
+ name = "brass wrench"
+ desc = "A brass wrench. It's faintly warm to the touch."
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ icon = 'modular_nova/modules/clock_cult/icons/tools.dmi'
+ icon_state = "wrench_brass"
+ toolspeed = BRASS_TOOLSPEED_MOD
+
+/obj/item/wrench/brass/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup)
+
+/obj/item/storage/belt/utility/clock
+ name = "old toolbelt"
+ desc = "Holds tools. This one's seen better days, though. There's the outline of a cog roughly cut into the leather on one side."
+ storage_type = /datum/storage/belt/clockwork
+
+/datum/storage/belt/clockwork
+ max_slots = 10
+ max_specific_storage = WEIGHT_CLASS_NORMAL
+
+/datum/storage/belt/clockwork/New(atom/parent, max_slots, max_specific_storage, max_total_storage, rustle_sound, remove_rustle_sound)
+ . = ..()
+ set_holdable(
+ can_hold_list = list(
+ /obj/item/screwdriver,
+ /obj/item/crowbar,
+ /obj/item/weldingtool,
+ /obj/item/wirecutters,
+ /obj/item/wrench,
+ /obj/item/multitool,
+ /obj/item/clockwork/replica_fabricator,
+ /obj/item/clockwork/clockwork_slab,
+ )
+ )
+/obj/item/storage/belt/utility/clock/PopulateContents()
+ new /obj/item/screwdriver/brass(src)
+ new /obj/item/crowbar/brass(src)
+ new /obj/item/weldingtool/experimental/brass(src)
+ new /obj/item/wirecutters/brass(src)
+ new /obj/item/wrench/brass(src)
+ new /obj/item/multitool(src)
+
+/obj/item/storage/belt/utility/clock/drone/PopulateContents()
+ new /obj/item/screwdriver/brass(src)
+ new /obj/item/crowbar/brass(src)
+ new /obj/item/weldingtool/experimental/brass(src)
+ new /obj/item/wirecutters/brass(src)
+ new /obj/item/wrench/brass(src)
+ new /obj/item/multitool(src)
+ new /obj/item/clockwork/replica_fabricator(src)
+ new /obj/item/clockwork/clockwork_slab(src)
+
+/obj/item/storage/toolbox/brass
+ name = "brass box"
+ desc = "A large box to hold things."
+ icon = 'icons/obj/storage/storage.dmi'
+ icon_state = "brassbox"
+ has_latches = FALSE
+ material_flags = NONE
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+
+/obj/item/storage/toolbox/brass/surgery
+ name = "surgery brass box"
+ desc = "A large brass box containing tools for surgery."
+ storage_type = /datum/storage/medkit/surgery
+
+/obj/item/storage/toolbox/brass/surgery/PopulateContents()
+ new /obj/item/scalpel(src)
+ new /obj/item/hemostat(src)
+ new /obj/item/retractor(src)
+ new /obj/item/circular_saw(src)
+ new /obj/item/surgicaldrill(src)
+ new /obj/item/cautery(src)
+ new /obj/item/bonesetter(src)
+ new /obj/item/surgical_drapes(src)
+ new /obj/item/blood_filter(src)
+
+#undef BRASS_TOOLSPEED_MOD
diff --git a/tff_modular/modules/antagonists/clock_cult/items/weaponry.dm b/tff_modular/modules/antagonists/clock_cult/items/weaponry.dm
new file mode 100644
index 00000000000..e003896c073
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/items/weaponry.dm
@@ -0,0 +1,331 @@
+#define HAMMER_FLING_DISTANCE 2
+#define HAMMER_THROW_FLING_DISTANCE 3
+#define COGSCARAB_BOW_DRAW_TIME_MULT 20
+
+/obj/item/clockwork/weapon
+ name = "clockwork weapon"
+ desc = "Something"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_weapons.dmi'
+ lefthand_file = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_lefthand.dmi'
+ righthand_file = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_righthand.dmi'
+ worn_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_garb_worn.dmi'
+ w_class = WEIGHT_CLASS_BULKY
+ slot_flags = ITEM_SLOT_BACK
+ throwforce = 20
+ throw_speed = 4
+ armour_penetration = 10
+ hitsound = 'sound/items/weapons/bladeslice.ogg'
+ attack_verb_continuous = list("attacks", "pokes", "jabs", "tears", "gores")
+ attack_verb_simple = list("attack", "poke", "jab", "tear", "gore")
+ sharpness = SHARP_EDGED
+ wound_bonus = -15 //wounds are really strong for clock cult, so im making their weapons slightly worse then normal at wounding
+ var/static/list/effect_turf_typecache_bronze = typecacheof(/turf/open/floor/bronze)
+ var/static/list/effect_turf_typecache_void = typecacheof(/turf/open/indestructible/reebe_void)
+ var/static/list/effect_turf_typecache_engine = typecacheof(/turf/open/floor/engine/clockwork)
+ var/static/list/effect_turf_typecache_reebe = typecacheof(/turf/open/indestructible/reebe_flooring)
+
+/obj/item/clockwork/weapon/attack(mob/living/target_mob, mob/living/user, list/modifiers, list/attack_modifiers)
+ . = ..()
+ var/turf/gotten_turf = get_turf(user.loc)
+ if(is_type_in_typecache(gotten_turf, effect_turf_typecache_bronze) || is_type_in_typecache(gotten_turf, effect_turf_typecache_void) || is_type_in_typecache(gotten_turf, effect_turf_typecache_engine) || is_type_in_typecache(gotten_turf, effect_turf_typecache_reebe))
+
+ if(QDELETED(target_mob))
+ return
+
+ if(ismob(target_mob))
+ if(target_mob.stat != DEAD && !IS_CLOCK(target_mob) && !target_mob.can_block_magic(MAGIC_RESISTANCE_HOLY))
+ mob_hit_effect(target_mob, user)
+ return
+
+ atom_hit_effect(target_mob, user)
+
+/obj/item/clockwork/weapon/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ . = ..()
+ if(.)
+ return
+
+ if(!isliving(hit_atom))
+ return
+
+ var/mob/living/target = hit_atom
+ if(!target.can_block_magic(MAGIC_RESISTANCE_HOLY) && !IS_CLOCK(target))
+ mob_hit_effect_thrown(target, throwingdatum.thrower)
+
+/// What occurs to non-holy mobs when attacked from brass tiles
+/obj/item/clockwork/weapon/proc/mob_hit_effect_thrown(mob/living/target, mob/living/user)
+ return
+
+/// What occurs to non-holy mobs when attacked from brass tiles
+/obj/item/clockwork/weapon/proc/mob_hit_effect(mob/living/target, mob/living/user)
+ return
+
+/// What occurs to non-mob atoms when attacked from brass tiles
+/obj/item/clockwork/weapon/proc/atom_hit_effect(mob/living/target, mob/living/user)
+ return
+
+// Копье, которое можно кидать во врагов и призывать в ручки
+/obj/item/clockwork/weapon/brass_spear
+ name = "brass spear"
+ desc = "A razor-sharp spear made of brass. It thrums with barely-contained energy."
+ base_icon_state = "ratvarian_spear"
+ icon_state = "ratvarian_spear0"
+ embed_type = /datum/embedding/brass_spear
+ throwforce = 40
+ force = 10
+ armour_penetration = 40
+ block_chance = 15
+ clockwork_desc = "Can be summoned back to its last holder every 10 seconds if they are standing on bronze."
+
+/datum/embedding/brass_spear
+ pain_mult = 1.5
+ embed_chance = 80
+ fall_chance = 5
+ ignore_throwspeed_threshold = TRUE
+ impact_pain_mult = 1.5
+
+/obj/item/clockwork/weapon/brass_spear/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/two_handed, \
+ force_multiplier = 2, \
+ icon_wielded = "[base_icon_state]1", \
+ wield_callback = CALLBACK(src, PROC_REF(on_wield)), \
+ unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \
+ )
+
+/obj/item/clockwork/weapon/brass_spear/update_icon_state()
+ icon_state = "[base_icon_state]0"
+ return ..()
+
+/obj/item/clockwork/weapon/brass_spear/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, final_block_chance, damage, attack_type)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
+ final_block_chance += 30
+ return ..()
+
+/obj/item/clockwork/weapon/brass_spear/proc/on_wield()
+ attack_speed = max(attack_speed - 3, 1)
+
+/obj/item/clockwork/weapon/brass_spear/proc/on_unwield()
+ attack_speed += 3 //yes technically this could break with the max() in on_wield() but you should not be getting attack speed that low anyway so its only there for sanity
+
+// Молот, атакующий в 2 раза медленнее чем другое оружие, но с большим АП и уроном, еще и отбрасывает на тайлах бронзы/при броске.
+/obj/item/clockwork/weapon/brass_battlehammer
+ name = "brass battle-hammer"
+ desc = "A brass hammer glowing with energy."
+ base_icon_state = "ratvarian_hammer"
+ icon_state = "ratvarian_hammer0"
+ force = 15
+ throwforce = 30
+ armour_penetration = 20
+ attack_verb_simple = list("bash", "hammer", "attack", "smash")
+ attack_verb_continuous = list("bashes", "hammers", "attacks", "smashes")
+ attack_speed = 8
+ clockwork_desc = "Enemies hit by this will be flung back while you are on bronze tiles."
+ sharpness = FALSE
+ hitsound = 'sound/items/weapons/smash.ogg'
+ block_chance = 10
+ demolition_mod = 2
+
+/obj/item/clockwork/weapon/brass_battlehammer/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/two_handed, \
+ force_unwielded = 15, \
+ icon_wielded = "[base_icon_state]1", \
+ force_wielded = 25, \
+ )
+
+/obj/item/clockwork/weapon/brass_battlehammer/mob_hit_effect(mob/living/target, mob/living/user)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
+ var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
+ target.throw_at(throw_target, HAMMER_FLING_DISTANCE, 4)
+
+/obj/item/clockwork/weapon/brass_battlehammer/mob_hit_effect_thrown(mob/living/target, mob/living/user)
+ var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
+ target.throw_at(throw_target, HAMMER_THROW_FLING_DISTANCE, 4)
+
+/obj/item/clockwork/weapon/brass_battlehammer/update_icon_state()
+ icon_state = "[base_icon_state]0"
+ return ..()
+
+// Меч атакующий концентрированным ЭМИ. Имеет хороший урон, АП и небольшой шанс блока.
+/obj/item/clockwork/weapon/brass_sword
+ name = "brass longsword"
+ desc = "A large sword made of brass."
+ icon_state = "ratvarian_sword"
+ force = 25
+ throwforce = 15
+ armour_penetration = 30
+ attack_verb_simple = list("attack", "slash", "cut", "tear", "gore")
+ attack_verb_continuous = list("attacks", "slashes", "cuts", "tears", "gores")
+ clockwork_desc = "Enemies and mechs will be struck with a powerful electromagnetic pulse while you are on bronze tiles, with a cooldown. It seems to only be able to parry melee attacks."
+ block_chance = 50
+ COOLDOWN_DECLARE(emp_cooldown)
+
+/obj/item/clockwork/weapon/brass_sword/mob_hit_effect(mob/living/target, mob/living/user, thrown)
+ if(!COOLDOWN_FINISHED(src, emp_cooldown))
+ return
+
+ COOLDOWN_START(src, emp_cooldown, 30 SECONDS)
+
+ target.emp_act(EMP_LIGHT)
+ new /obj/effect/temp_visual/emp/pulse(get_turf(target))
+ addtimer(CALLBACK(src, PROC_REF(send_message), user), 30 SECONDS)
+ to_chat(user, span_brass("You strike [target] with an electromagnetic pulse!"))
+ playsound(user, 'sound/effects/magic/lightningshock.ogg', 40)
+
+/obj/item/clockwork/weapon/brass_sword/atom_hit_effect(atom/attacked, mob/living/user, thrown)
+ if(!istype(attacked, /obj/vehicle) || !COOLDOWN_FINISHED(src, emp_cooldown))
+ return
+
+ var/obj/vehicle/target = attacked
+ COOLDOWN_START(src, emp_cooldown, 20 SECONDS)
+ target.emp_act(EMP_HEAVY)
+ new /obj/effect/temp_visual/emp/pulse(get_turf(target))
+ addtimer(CALLBACK(src, PROC_REF(send_message), user), 20 SECONDS)
+ to_chat(user, span_brass("You strike [target] with an electromagnetic pulse!"))
+ playsound(user, 'sound/effects/magic/lightningshock.ogg', 40)
+
+/obj/item/clockwork/weapon/brass_sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, final_block_chance, damage, attack_type)
+ return attack_type == MELEE_ATTACK && ..()
+
+/obj/item/clockwork/weapon/brass_sword/proc/send_message(mob/living/target)
+ to_chat(target, span_brass("[src] glows, indicating the next attack will disrupt electronics of the target."))
+
+/obj/item/gun/ballistic/bow/clockwork
+ name = "brass bow"
+ desc = "A bow made from brass and other components that you can't quite understand. It glows with a deep energy and frabricates arrows by itself."
+ icon = 'modular_nova/modules/clock_cult/icons/weapons/clockwork_weapons.dmi'
+ lefthand_file = 'modular_nova/modules/clock_cult/icons/weapons/clockwork_lefthand.dmi'
+ righthand_file = 'modular_nova/modules/clock_cult/icons/weapons/clockwork_righthand.dmi'
+ icon_state = "bow_clockwork_unchambered_undrawn"
+ inhand_icon_state = "clockwork_bow"
+ base_icon_state = "bow_clockwork"
+ force = 10
+ accepted_magazine_type = /obj/item/ammo_box/magazine/internal/bow/clockwork
+ /// Time between bolt recharges
+ var/recharge_time = 1.5 SECONDS
+ /// Typecache of valid turfs to have the weapon's special effect on
+ var/static/list/effect_turf_typecache_bronze = typecacheof(/turf/open/floor/bronze)
+ var/static/list/effect_turf_typecache_void = typecacheof(/turf/open/indestructible/reebe_void)
+ var/static/list/effect_turf_typecache_engine = typecacheof(/turf/open/floor/engine/clockwork)
+ var/static/list/effect_turf_typecache_reebe = typecacheof(/turf/open/indestructible/reebe_flooring)
+
+/obj/item/gun/ballistic/bow/clockwork/Initialize(mapload)
+ . = ..()
+ update_icon_state()
+ AddElement(/datum/element/clockwork_description, "Firing from brass tiles will halve the time that it takes to recharge a bolt.")
+ AddElement(/datum/element/clockwork_pickup)
+
+/obj/item/gun/ballistic/bow/clockwork/try_fire_gun(atom/target, mob/living/user, params)
+ if(!drawn || !chambered)
+ to_chat(user, span_notice("[src] must be drawn to fire a shot!"))
+ return FALSE
+ return ..()
+
+/obj/item/gun/ballistic/bow/clockwork/shoot_live_shot(mob/living/user, pointblank, atom/pbtarget, message)
+ . = ..()
+ var/turf/gotten_turf = get_turf(user.loc)
+
+ if(is_type_in_typecache(gotten_turf, effect_turf_typecache_bronze) || is_type_in_typecache(gotten_turf, effect_turf_typecache_void) || is_type_in_typecache(gotten_turf, effect_turf_typecache_engine) || is_type_in_typecache(gotten_turf, effect_turf_typecache_reebe))
+ recharge_time = 0.75 SECONDS
+
+ addtimer(CALLBACK(src, PROC_REF(recharge_bolt)), recharge_time)
+ recharge_time = initial(recharge_time)
+
+/obj/item/gun/ballistic/bow/clockwork/attack_self(mob/living/user)
+ if(drawn || !chambered)
+ return
+
+ if(!do_after(user, 0.5 SECONDS, src))
+ return
+
+ to_chat(user, span_notice("You draw back the bowstring."))
+ drawn = TRUE
+ playsound(src, 'modular_nova/modules/tribal_extended/sound/sound_weapons_bowdraw.ogg', 75, 0) //gets way too high pitched if the freq varies
+ update_icon()
+
+/// Recharges a bolt, done after the delay in shoot_live_shot
+/obj/item/gun/ballistic/bow/clockwork/proc/recharge_bolt()
+ var/obj/item/ammo_casing/arrow/clockbolt/bolt = new
+ magazine.give_round(bolt)
+ chambered = bolt
+ update_icon()
+
+/obj/item/gun/ballistic/bow/clockwork/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers)
+ return
+
+/obj/item/gun/ballistic/bow/clockwork/update_icon_state()
+ . = ..()
+ icon_state = "[base_icon_state]_[chambered ? "chambered" : "unchambered"]_[drawn ? "drawn" : "undrawn"]"
+
+/obj/item/ammo_box/magazine/internal/bow/clockwork
+ ammo_type = /obj/item/ammo_casing/arrow/clockbolt
+ start_empty = FALSE
+
+/obj/item/ammo_casing/arrow/clockbolt
+ name = "energy bolt"
+ desc = "An arrow made from a strange energy."
+ icon = 'modular_nova/modules/clock_cult/icons/weapons/ammo.dmi'
+ icon_state = "arrow_redlight"
+ projectile_type = /obj/projectile/energy/clockbolt
+
+/obj/projectile/energy/clockbolt
+ name = "energy bolt"
+ icon = 'modular_nova/modules/clock_cult/icons/projectiles.dmi'
+ icon_state = "arrow_energy"
+ damage = 35
+ damage_type = BURN
+
+/obj/item/gun/ballistic/rifle/lionhunter/clockwork
+ name = "brass rifle"
+ desc = "An antique, brass rifle made with the finest of care. It has an ornate scope in the shape of a cog built into the top."
+ icon = 'modular_nova/modules/clock_cult/icons/weapons/clockwork_weapons_40x32.dmi'
+ lefthand_file = 'modular_nova/modules/clock_cult/icons/weapons/clockwork_lefthand.dmi'
+ righthand_file = 'modular_nova/modules/clock_cult/icons/weapons/clockwork_righthand.dmi'
+ worn_icon = 'modular_nova/modules/clock_cult/icons/clockwork_garb_worn.dmi'
+ slot_flags = ITEM_SLOT_BACK
+ icon_state = "clockwork_rifle"
+ inhand_icon_state = "clockwork_rifle"
+ worn_icon_state = "clockwork_rifle"
+ accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/lionhunter/clockwork
+ fire_sound = 'sound/items/weapons/gun/sniper/shot.ogg'
+ show_bolt_icon = FALSE
+
+/obj/item/gun/ballistic/rifle/lionhunter/clockwork/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_pickup)
+
+/obj/item/ammo_box/magazine/internal/boltaction/lionhunter/clockwork
+ name = "brass rifle internal magazine"
+ ammo_type = /obj/item/ammo_casing/strilka310/lionhunter/clock
+
+/obj/item/ammo_casing/strilka310/lionhunter/clock
+ name = "brass rifle round"
+ projectile_type = /obj/projectile/bullet/strilka310/lionhunter/clock
+ min_distance = 3
+
+/obj/projectile/bullet/strilka310/lionhunter/clock
+ name = "brass .310 bullet"
+ damage = 35
+ stamina = 35
+
+/obj/item/ammo_box/speedloader/strilka310/lionhunter/clock
+ name = "stripper clip (.310 brass)"
+ desc = "A stripper clip that's just as brass as the rounds it holds."
+ icon = 'modular_nova/modules/clock_cult/icons/weapons/ammo.dmi'
+ icon_state = "762_brass"
+ ammo_type = /obj/item/ammo_casing/strilka310/lionhunter/clock
+ max_ammo = 20
+ multiple_sprites = AMMO_BOX_PER_BULLET
+
+/obj/item/storage/pouch/ammo/clock
+
+/obj/item/storage/pouch/ammo/clock/PopulateContents()
+ var/static/items_inside = list(
+ /obj/item/ammo_box/speedloader/strilka310/lionhunter/clock = 1
+ )
+
+ generate_items_inside(items_inside, src)
+
+#undef HAMMER_FLING_DISTANCE
+#undef HAMMER_THROW_FLING_DISTANCE
+#undef COGSCARAB_BOW_DRAW_TIME_MULT
diff --git a/tff_modular/modules/antagonists/clock_cult/language.dm b/tff_modular/modules/antagonists/clock_cult/language.dm
new file mode 100644
index 00000000000..7979b5efba6
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/language.dm
@@ -0,0 +1,141 @@
+/datum/language_holder/clockmob
+ understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
+ /datum/language/ratvar = list(LANGUAGE_ATOM))
+ spoken_languages = list(/datum/language/ratvar = list(LANGUAGE_ATOM),
+ /datum/language/common = list(LANGUAGE_ATOM))
+
+// Thought this language code was cool as fuck, so I'm going with it
+// For any other language nerds: https://pastebin.com/ngFMZHNV
+
+/datum/language/ratvar
+ name = "Ratvarian"
+ desc = "A timeless language full of power and incomprehensible to the unenlightened."
+ icon_state = "ratvar"
+ key = "r"
+ default_priority = 10
+ spans = list(SPAN_ROBOT)
+
+/datum/language/ratvar/scramble_sentence(input, list/mutual_languages)
+ return text2ratvar(input)
+
+//Regexes used to alter english to ratvarian style
+
+#define RATVAR_OF_MATCH regex(@"(\w)\s([oO][fF])","g")
+#define RATVAR_OF_REPLACEMENT "$1-$2"
+#define RATVAR_GUA_MATCH regex(@"([gG][uU])([aA])","g")
+#define RATVAR_GUA_REPLACEMENT "$1-$2"
+#define RATVAR_TH_MATCH regex(@"([tT][hH]\w)(\w)","g")
+#define RATVAR_TH_REPLACEMENT "$1`$2"
+#define RATVAR_TI_MATCH regex(@"([tT][iI])(\w)","g")
+#define RATVAR_TI_REPLACEMENT "$1`$2"
+#define RATVAR_ET_MATCH regex(@"(\w)([eE][tT])","g")
+#define RATVAR_ET_REPLACEMENT "$1-$2"
+#define RATVAR_TE_MATCH regex(@"([tT][eE])(\w)","g")
+#define RATVAR_TE_REPLACEMENT "$1-$2"
+#define RATVAR_PRE_AND_MATCH regex(@"(\w)\s([aA][nN][dD])(\W)","g")
+#define RATVAR_PRE_AND_REPLACEMENT "$1-$2$3"
+#define RATVAR_POST_AND_MATCH regex(@"(\W)([aA][nN][dD])\s(\w)","g")
+#define RATVAR_POST_AND_REPLACEMENT "$1$2-$3"
+#define RATVAR_TO_MATCH regex(@"(\s)([tT][oO])\s(\w)","g")
+#define RATVAR_TO_REPLACEMENT "$1$2-$3"
+#define RATVAR_MY_MATCH regex(@"(\s)([mM][yY])\s(\w)","g")
+#define RATVAR_MY_REPLACEMENT "$1$2-$3"
+
+//Regexes used to remove ratvarian styling from english
+#define REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH regex(@"(\w)-([aA][nN][dD])","g") //specifically structured to support -emphasis-, including with -and-
+#define REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT "$1 $2"
+#define REVERSE_RATVAR_HYPHEN_POST_AND_MATCH regex(@"([aA][nN][dD])-(\w)","g")
+#define REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT "$1 $2"
+#define REVERSE_RATVAR_HYPHEN_TO_MY_MATCH regex(@"([tTmM][oOyY])-","g")
+#define REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT "$1 "
+#define REVERSE_RATVAR_HYPHEN_TE_MATCH regex(@"([tT][eE])-","g")
+#define REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT "$1"
+#define REVERSE_RATVAR_HYPHEN_ET_MATCH regex(@"-([eE][tT])","g")
+#define REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT "$1"
+#define REVERSE_RATVAR_HYPHEN_GUA_MATCH regex(@"([gG][uU])-([aA])","g")
+#define REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT "$1$2"
+#define REVERSE_RATVAR_HYPHEN_OF_MATCH regex(@"-([oO][fF])","g")
+#define REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT " $1"
+
+/// Takes english and applies ratvarian styling rules (and rot13) to it.
+/proc/text2ratvar(text)
+ var/ratvarian = add_ratvarian_regex(text) //run the regexes twice, so that you catch people translating it beforehand
+ ratvarian = rot13(ratvarian)
+ return add_ratvarian_regex(ratvarian)
+
+/proc/add_ratvarian_regex(text)
+ var/ratvarian = replacetext(text, RATVAR_OF_MATCH, RATVAR_OF_REPLACEMENT)
+ ratvarian = replacetext(ratvarian, RATVAR_GUA_MATCH, RATVAR_GUA_REPLACEMENT)
+ ratvarian = replacetext(ratvarian, RATVAR_TH_MATCH, RATVAR_TH_REPLACEMENT)
+ ratvarian = replacetext(ratvarian, RATVAR_TI_MATCH, RATVAR_TI_REPLACEMENT)
+ ratvarian = replacetext(ratvarian, RATVAR_ET_MATCH, RATVAR_ET_REPLACEMENT)
+ ratvarian = replacetext(ratvarian, RATVAR_TE_MATCH, RATVAR_TE_REPLACEMENT)
+ ratvarian = replacetext(ratvarian, RATVAR_PRE_AND_MATCH, RATVAR_PRE_AND_REPLACEMENT)
+ ratvarian = replacetext(ratvarian, RATVAR_POST_AND_MATCH, RATVAR_POST_AND_REPLACEMENT)
+ ratvarian = replacetext(ratvarian, RATVAR_TO_MATCH, RATVAR_TO_REPLACEMENT)
+ return replacetext(ratvarian, RATVAR_MY_MATCH, RATVAR_MY_REPLACEMENT)
+
+///Reverts ravarian styling and rot13 in text.
+/proc/ratvar2text(ratvarian)
+ var/text = remove_ratvarian_regex(ratvarian) //run the regexes twice, so that you catch people translating it beforehand
+ text = replacetext(rot13(text), "`", "")
+ return remove_ratvarian_regex(text)
+
+/proc/remove_ratvarian_regex(ratvarian)
+ var/text = replacetext(ratvarian, REVERSE_RATVAR_HYPHEN_GUA_MATCH, REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT)
+ text = replacetext(text, REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH, REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT)
+ text = replacetext(text, REVERSE_RATVAR_HYPHEN_POST_AND_MATCH, REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT)
+ text = replacetext(text, REVERSE_RATVAR_HYPHEN_TO_MY_MATCH, REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT)
+ text = replacetext(text, REVERSE_RATVAR_HYPHEN_TE_MATCH, REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT)
+ text = replacetext(text, REVERSE_RATVAR_HYPHEN_ET_MATCH, REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT)
+ return replacetext(text, REVERSE_RATVAR_HYPHEN_OF_MATCH, REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT)
+
+/// Causes the mob or movable in question to speak a message; it assumes that the message is already translated to ratvar speech using text2ratvar()
+/proc/clockwork_say(atom/movable/movable_atom, message, whisper=FALSE)
+ var/list/spans = list(SPAN_ROBOT)
+
+ if(isliving(movable_atom))
+ var/mob/living/living_mob = movable_atom
+ if(!whisper)
+ living_mob.say(message, "clock", spans, language=/datum/language/common, ignore_spam = TRUE)
+ else
+ living_mob.whisper(message, "clock", spans, language=/datum/language/common)
+ else
+ movable_atom.say(message, language=/datum/language/common)
+
+
+#undef RATVAR_OF_MATCH
+#undef RATVAR_OF_REPLACEMENT
+#undef RATVAR_GUA_MATCH
+#undef RATVAR_GUA_REPLACEMENT
+#undef RATVAR_TH_MATCH
+#undef RATVAR_TH_REPLACEMENT
+#undef RATVAR_TI_MATCH
+#undef RATVAR_TI_REPLACEMENT
+#undef RATVAR_ET_MATCH
+#undef RATVAR_ET_REPLACEMENT
+#undef RATVAR_TE_MATCH
+#undef RATVAR_TE_REPLACEMENT
+#undef RATVAR_PRE_AND_MATCH
+#undef RATVAR_PRE_AND_REPLACEMENT
+#undef RATVAR_POST_AND_MATCH
+#undef RATVAR_POST_AND_REPLACEMENT
+#undef RATVAR_TO_MATCH
+#undef RATVAR_TO_REPLACEMENT
+#undef RATVAR_MY_MATCH
+#undef RATVAR_MY_REPLACEMENT
+
+#undef REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH
+#undef REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT
+#undef REVERSE_RATVAR_HYPHEN_POST_AND_MATCH
+#undef REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT
+#undef REVERSE_RATVAR_HYPHEN_TO_MY_MATCH
+#undef REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT
+#undef REVERSE_RATVAR_HYPHEN_TE_MATCH
+#undef REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT
+#undef REVERSE_RATVAR_HYPHEN_ET_MATCH
+#undef REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT
+#undef REVERSE_RATVAR_HYPHEN_GUA_MATCH
+#undef REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT
+#undef REVERSE_RATVAR_HYPHEN_OF_MATCH
+#undef REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT
diff --git a/tff_modular/modules/antagonists/clock_cult/machines/airlock.dm b/tff_modular/modules/antagonists/clock_cult/machines/airlock.dm
new file mode 100644
index 00000000000..c581b0cd8de
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/machines/airlock.dm
@@ -0,0 +1,138 @@
+#define COST_PER_AIRLOCK 1
+
+/obj/structure/door_assembly/door_assembly_bronze/clock
+ airlock_type = /obj/machinery/door/airlock/bronze/clock
+
+/obj/structure/door_assembly/door_assembly_bronze/seethru/clock
+ airlock_type = /obj/machinery/door/airlock/bronze/clock/glass
+
+/obj/machinery/door/airlock/bronze/clock
+ assemblytype = /obj/structure/door_assembly/door_assembly_bronze/clock
+ hackProof = TRUE
+ aiControlDisabled = AI_WIRE_DISABLED
+ req_access = list(ACCESS_CLOCKCULT)
+ damage_deflection = 6
+
+/obj/machinery/door/airlock/bronze/clock/Initialize(mapload)
+ . = ..()
+ if(on_reebe(src))
+ damage_deflection = 0
+ if(!mapload)
+ SSthe_ark.reebe_clockwork_airlock_count++
+
+/obj/machinery/door/airlock/bronze/clock/Destroy()
+ if(on_reebe(src))
+ SSthe_ark.reebe_clockwork_airlock_count--
+ return ..()
+
+/obj/machinery/door/airlock/bronze/clock/canAIControl(mob/user)
+ return (IS_CLOCK(user) && !isAllPowerCut())
+
+/obj/machinery/door/airlock/bronze/clock/on_break()
+ set_panel_open(TRUE)
+
+/obj/machinery/door/airlock/bronze/clock/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ return
+
+/obj/machinery/door/airlock/bronze/clock/isElectrified()
+ return FALSE
+
+/obj/machinery/door/airlock/bronze/clock/ratvar_act()
+ return FALSE
+
+/obj/machinery/door/airlock/bronze/clock/hasPower()
+ return TRUE
+
+/obj/machinery/door/airlock/bronze/clock/allowed(mob/living/user)
+ if(!density || IS_CLOCK(user))
+ return TRUE
+
+ else if(!on_reebe(src))
+ user.Paralyze(1 SECONDS)
+ user.electrocute_act(10, src, 1, SHOCK_NOGLOVES|SHOCK_SUPPRESS_MESSAGE)
+ to_chat(user, span_warning("You feel a sudden jolt as you touch [src]!"))
+ return FALSE
+
+/obj/machinery/door/airlock/bronze/clock/emag_act(mob/user, obj/item/card/emag/emag_card) //emags are magical but not THAT magical
+ return FALSE
+
+/obj/machinery/door/airlock/bronze/clock/glass
+ name = "clear bronze airlock"
+ assemblytype = /obj/structure/door_assembly/door_assembly_bronze/seethru/clock
+ glass = TRUE
+ opacity = FALSE
+
+//player made airlocks drain passive power when placed near other airlocks
+/obj/machinery/door/airlock/bronze/clock/player_made
+ //var/list/tracked_airlocks
+ ///How much passive power are we using
+ var/power_usage = 0
+
+/obj/machinery/door/airlock/bronze/clock/player_made/Initialize(mapload)
+ . = ..()
+ var/list/tracked_airlocks = list()
+ var/total_cost = 0
+ for(var/obj/machinery/door/airlock/bronze/clock/player_made/airlock in orange(1, src))
+ tracked_airlocks += airlock
+ total_cost -= COST_PER_AIRLOCK * 2
+
+ if(!SSthe_ark.adjust_passive_power(total_cost, TRUE))
+ deconstruct(FALSE)
+ visible_message(span_warning("\The [src] is unable to sustain its power draw and collapses!"))
+ return INITIALIZE_HINT_QDEL
+
+ for(var/obj/machinery/door/airlock/bronze/clock/player_made/lock in tracked_airlocks)
+ track_airlock(lock, TRUE)
+
+/obj/machinery/door/airlock/bronze/clock/player_made/examine(mob/user)
+ . = ..()
+ if(isobserver(user) || IS_CLOCK(user))
+ . += span_brass("Due to instability, clockwork airlocks placed near each other must drain passive power to stop from collapsing, \
+ this one is currently draining [power_usage] power.")
+
+/obj/machinery/door/airlock/bronze/clock/player_made/proc/track_airlock(obj/machinery/door/airlock/bronze/clock/player_made/tracked, recurse = FALSE)
+ RegisterSignal(tracked, COMSIG_QDELETING, PROC_REF(on_tracked_qdel))
+ if(recurse)
+ tracked.track_airlock(src)
+ power_usage += COST_PER_AIRLOCK
+ SSthe_ark.adjust_passive_power(-COST_PER_AIRLOCK)
+
+/obj/machinery/door/airlock/bronze/clock/player_made/proc/on_tracked_qdel(obj/machinery/door/airlock/bronze/clock/player_made/tracked)
+ untrack_airlock(tracked, TRUE)
+
+/obj/machinery/door/airlock/bronze/clock/player_made/proc/untrack_airlock(obj/machinery/door/airlock/bronze/clock/player_made/untracked, recurse = FALSE)
+ if(recurse)
+ untracked.untrack_airlock(src)
+ SSthe_ark.adjust_passive_power(COST_PER_AIRLOCK)
+ power_usage -= COST_PER_AIRLOCK
+
+/obj/machinery/door/airlock/bronze/clock/player_made/glass
+ name = "clear bronze airlock"
+ assemblytype = /obj/structure/door_assembly/door_assembly_bronze/seethru/clock
+ glass = TRUE
+ opacity = FALSE
+
+/obj/machinery/door/airlock/proc/is_probably_external_airlock()
+ . = FALSE
+ if(leads_to_space() || closeOther?.leads_to_space() || cyclelinkedairlock?.leads_to_space())
+ return TRUE
+ for(var/obj/machinery/door/airlock/other_door in close_others)
+ if(other_door.leads_to_space())
+ return TRUE
+
+/// Checks to see if the door is adjacent to any tiles that have likely unsafe atmospheric conditions.
+/obj/machinery/door/airlock/proc/leads_to_space()
+ var/turf/our_turf = get_turf(src)
+ if(QDELETED(our_turf))
+ return TRUE
+ for(var/turf/open/turf as anything in RANGE_TURFS(1, our_turf))
+ if(!istype(turf) || QDELING(turf) || turf.is_blocked_turf(exclude_mobs = TRUE, source_atom = src))
+ continue
+ if(isgroundlessturf(turf))
+ return TRUE
+ var/pressure = turf.return_air()?.return_pressure()
+ if(!IS_SAFE_NUM(pressure) || !ISINRANGE_EX(pressure, HAZARD_LOW_PRESSURE, HAZARD_HIGH_PRESSURE))
+ return TRUE
+ return FALSE
+
+#undef COST_PER_AIRLOCK
diff --git a/tff_modular/modules/antagonists/clock_cult/machines/clock_sleeper.dm b/tff_modular/modules/antagonists/clock_cult/machines/clock_sleeper.dm
new file mode 100644
index 00000000000..aadec902c07
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/machines/clock_sleeper.dm
@@ -0,0 +1,16 @@
+/obj/machinery/sleeper/clockwork
+ name = "Clockwork Sleeper"
+ desc = "An enclosed machine used to stabilize and heal servants."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/sleeper.dmi'
+ icon_state = "sleeper_clockwork"
+ base_icon_state = "sleeper_clockwork"
+ circuit = /obj/item/circuitboard/machine/sleeper/clockwork
+ min_health = -75
+
+/obj/item/circuitboard/machine/sleeper/clockwork
+ build_path = /obj/machinery/sleeper/clockwork
+ req_components = list(
+ /datum/stock_part/matter_bin/clock = 1,
+ /datum/stock_part/servo/clock = 1,
+ /obj/item/stack/cable_coil = 1,
+ /obj/item/stack/sheet/glass = 2)
diff --git a/tff_modular/modules/antagonists/clock_cult/machines/clockwork_operating_computer.dm b/tff_modular/modules/antagonists/clock_cult/machines/clockwork_operating_computer.dm
new file mode 100644
index 00000000000..6cf04489aa3
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/machines/clockwork_operating_computer.dm
@@ -0,0 +1,13 @@
+//operating computer that starts with all surgeries excluding a few like necrotic revival
+/obj/machinery/computer/operating/clockwork
+ name = "Clockwork Operating Computer"
+ desc = "A device containing (most) of the surgery secrets of the universe."
+ icon_keyboard = "ratvar_key1"
+ icon_state = "ratvarcomputer1"
+ clockwork = TRUE
+
+/obj/machinery/computer/operating/clockwork/screwdriver_act(mob/living/user, obj/item/I)
+ return FALSE
+
+/obj/machinery/computer/operating/clockwork/screwdriver_act_secondary(mob/living/user, obj/item/tool)
+ return FALSE
diff --git a/tff_modular/modules/antagonists/clock_cult/machines/comms_relay.dm b/tff_modular/modules/antagonists/clock_cult/machines/comms_relay.dm
new file mode 100644
index 00000000000..602f121c81f
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/machines/comms_relay.dm
@@ -0,0 +1,21 @@
+/obj/machinery/telecomms/relay/preset/reebe
+ id = "Hierophant Relay"
+ hide = TRUE
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ icon_state = "relay"
+ broadcasting = FALSE //It only receives
+ resistance_flags = INDESTRUCTIBLE
+ soundloop = null //for now im just making this be null, might give it something at some point
+
+/obj/machinery/telecomms/relay/preset/reebe/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers)
+ if(istype(attacking_item, /obj/item/encryptionkey) || attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
+ if(GLOB.current_eminence)
+ var/obj/item/encryptionkey/key = attacking_item
+ for(var/i in key.channels)
+ key.channels[i] = 1
+ GLOB.current_eminence.internal_radio.attackby(key, user, modifiers, attack_modifiers)
+ . = ..()
+
+/obj/item/radio/intercom/reebe
+ name = "Listening Device"
+ freerange = TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/machines/observation_console.dm b/tff_modular/modules/antagonists/clock_cult/machines/observation_console.dm
new file mode 100644
index 00000000000..cd34c9cdc70
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/machines/observation_console.dm
@@ -0,0 +1,105 @@
+/obj/machinery/computer/camera_advanced/ratvar
+ name = "Ratvarian Observation Console"
+ desc = "Used by the servants of Ratvar to conduct operations on Nanotrasen property."
+ icon_screen = "ratvar1"
+ icon_keyboard = "ratvar_key1"
+ icon_state = "ratvarcomputer1"
+ resistance_flags = INDESTRUCTIBLE
+ clockwork = TRUE
+ lock_override = TRUE
+ connectable = FALSE
+ circuit = /obj/item/circuitboard/machine/camera_console_ratvar
+
+/obj/machinery/computer/camera_advanced/ratvar/screwdriver_act(mob/living/user, obj/item/I)
+ return FALSE
+
+/obj/machinery/computer/camera_advanced/ratvar/screwdriver_act_secondary(mob/living/user, obj/item/tool)
+ return FALSE
+
+/obj/machinery/computer/camera_advanced/ratvar/Initialize(mapload)
+ . = ..()
+ START_PROCESSING(SSobj, src)
+ actions += new /datum/action/innate/clockcult/warp(src)
+ actions += new /datum/action/innate/clockcult/show_warpable_areas(src)
+ actions += new /datum/action/innate/clockcult/add_warp_area(src)
+
+/obj/machinery/computer/camera_advanced/ratvar/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/machinery/computer/camera_advanced/ratvar/process(seconds_per_tick)
+ if(SPT_PROB(3, seconds_per_tick))
+ new /obj/effect/temp_visual/steam_release(get_turf(src))
+ if(SPT_PROB(7, seconds_per_tick))
+ playsound(get_turf(src), 'sound/machines/beep/beep.ogg', 20, TRUE)
+
+/obj/machinery/computer/camera_advanced/ratvar/can_use(mob/living/user)
+ if(!IS_CLOCK(user) || iscogscarab(user))
+ return FALSE
+ return ..()
+
+/obj/machinery/computer/camera_advanced/ratvar/CreateEye()
+ . = ..()
+ eyeobj.visible_to_user = TRUE
+ eyeobj.icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/cameramob.dmi'
+ eyeobj.icon_state = "ratvar_camera"
+ eyeobj.invisibility = INVISIBILITY_OBSERVER
+
+/datum/action/innate/clockcult/warp
+ name = "Warp"
+ desc = "Warp to a location."
+ button_icon_state = "warp_down"
+ ///are we warping down
+ var/warping = FALSE
+ ///what area types are we blocked from warping to
+ var/static/list/blocked_areas = typecacheof(list(/area/station/service/chapel, /area/station/ai))
+
+/datum/action/innate/clockcult/warp/IsAvailable(feedback)
+ if(!IS_CLOCK(owner) || HAS_TRAIT(owner, TRAIT_INCAPACITATED))
+ return FALSE
+ return ..()
+
+/datum/action/innate/clockcult/warp/Activate()
+ if(!isliving(owner))
+ return
+
+ if(GLOB.clock_ark && GLOB.clock_ark.current_state >= ARK_STATE_ACTIVE)
+ to_chat(owner, span_brass("You cannot warp while the gateway is opening!"))
+ return
+
+ if(warping)
+ button_icon_state = "warp_down"
+ build_all_button_icons(UPDATE_BUTTON_ICON)
+ warping = FALSE
+ return
+
+ var/mob/living/cam_user = owner
+ var/mob/eye/camera/remote/cam = cam_user.remote_control
+ var/turf/target_loc = get_turf(cam)
+ var/area/target_area = get_area(target_loc)
+ if(!(SSthe_ark.marked_areas[target_area]))
+ to_chat(owner, span_brass("This area is not marked."))
+ return
+
+ if(isclosedturf(target_loc))
+ to_chat(owner, span_brass("You cannot warp into dense objects."))
+ return
+
+ do_sparks(5, TRUE, get_turf(cam))
+ warping = TRUE
+ button_icon_state = "warp_cancel"
+ build_all_button_icons(UPDATE_BUTTON_ICON)
+ if(do_after(cam_user, 5 SECONDS, target = target_loc, extra_checks = CALLBACK(src, PROC_REF(warping_check))))
+ try_servant_warp(cam_user, target_loc)
+ var/obj/machinery/creator = cam.origin_ref
+ creator.remove_eye_control()
+
+ button_icon_state = "warp_down"
+ build_all_button_icons(UPDATE_BUTTON_ICON)
+ warping = FALSE
+
+/datum/action/innate/clockcult/warp/proc/warping_check()
+ return warping
+
+/obj/item/circuitboard/machine/camera_console_ratvar
+ build_path = /obj/machinery/computer/camera_advanced/ratvar
diff --git a/tff_modular/modules/antagonists/clock_cult/mechas/mecha_effects.dm b/tff_modular/modules/antagonists/clock_cult/mechas/mecha_effects.dm
new file mode 100644
index 00000000000..b7c33129ef5
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mechas/mecha_effects.dm
@@ -0,0 +1,45 @@
+/obj/effect/judicial_mark
+ name = "Judicial Mark"
+ desc = "You feel standing on this would end poorly."
+ icon = 'icons/effects/96x96.dmi'
+ icon_state = "judicial_marker"
+ pixel_x = -32
+ pixel_y = -32
+ layer = BELOW_MOB_LAYER
+
+/obj/effect/judicial_mark/Initialize(mapload)
+ . = ..()
+ START_PROCESSING(SSfastprocess, src)
+ INVOKE_ASYNC(src, PROC_REF(do_mark))
+
+/obj/effect/judicial_mark/Destroy(force)
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+/obj/effect/judicial_mark/process(seconds_per_tick)
+ for(var/mob/living/marked_mob in range(1, src))
+ if(IS_CLOCK(marked_mob))
+ continue
+ marked_mob.apply_status_effect(/datum/status_effect/interdiction)
+
+/obj/effect/judicial_mark/proc/do_mark() //need to do antimagic stuff
+ playsound(src, 'sound/effects/magic/clockwork/ratvar_attack.ogg', 50, use_reverb = TRUE)
+ sleep(1.6 SECONDS)
+ flick("judicial_explosion", src)
+ sleep(1.3 SECONDS)
+ playsound(src, 'sound/effects/explosion/explosion_distant.ogg', 100, use_reverb = TRUE)
+ for(var/mob/living/marked_mob in range(1, src))
+ if(IS_CLOCK(marked_mob))
+ continue
+ if(IS_CULTIST(marked_mob)) //lights blood cultists on fire as well as paralyzes for longer
+ marked_mob.adjust_fire_stacks(2)
+ marked_mob.ignite_mob()
+ marked_mob.Paralyze(2 SECONDS, TRUE)
+ else
+ marked_mob.Paralyze(0.5 SECONDS)
+ marked_mob.Knockdown(3 SECONDS)
+ marked_mob.apply_damage(30, BURN)
+ marked_mob.visible_message(span_warning("[marked_mob] is hit by a judicial explosion!"),
+ span_warning("You feel the ground beneath you heat up!"))
+ sleep(0.3 SECONDS)
+ qdel(src)
diff --git a/tff_modular/modules/antagonists/clock_cult/mechas/mecha_equipment.dm b/tff_modular/modules/antagonists/clock_cult/mechas/mecha_equipment.dm
new file mode 100644
index 00000000000..25102c47766
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mechas/mecha_equipment.dm
@@ -0,0 +1,87 @@
+//should never be outside a mech without an admin
+/obj/item/mecha_parts/mecha_equipment/weapon/clock
+ name = "clock mech weapon"
+ color = rgb(190, 135, 0)
+ icon_state = "mecha_laser"
+ harmful = TRUE
+
+/obj/item/mecha_parts/mecha_equipment/weapon/clock/bow_single_shot
+ name = "Energy Concentrator"
+ desc = "A strange device that concentrates energy into \"arrows\"."
+ projectile = /obj/projectile/energy/clockbolt
+ equip_cooldown = 1 SECONDS
+ energy_drain = 5
+
+/obj/item/mecha_parts/mecha_equipment/weapon/clock/steam_cannon
+ name = "Steam Cannon"
+ desc = "A large tube that shoots pressurized steam."
+ projectile = /obj/projectile/steam_cloud
+ equip_cooldown = 5 SECONDS
+ energy_drain = 20
+
+/obj/item/mecha_parts/mecha_equipment/repair_droid/clock
+ name = "Clockwork Repair Droid"
+ desc = "A small device that constantly re-adjusts any out of place gears in a mech."
+ color = rgb(190, 135, 0)
+ energy_drain = 0 //we will see if an energy drain is needed
+ health_boost = 1 //should really just buff the normal repair droid up to this, its really bad right now
+ repairable_damage = list(MECHA_INT_FIRE, MECHA_INT_CONTROL_LOST)
+
+/obj/item/mecha_parts/mecha_equipment/armor/clock
+ name = "Clockwork Armor Booster"
+ desc = "A large clump of gears that somehow help protect a mech against all forms of attack."
+ color = rgb(190, 135, 0)
+ icon_state = "mecha_abooster_proj"
+ armor_mod = /datum/armor/mecha_equipment_mixed_boost
+
+/datum/armor/mecha_equipment_mixed_boost
+ bullet = 10
+ laser = 10
+ melee = 15
+
+/obj/projectile/steam_cloud
+ name = "Steam Cloud"
+ alpha = 0
+ range = 8
+ pass_flags = PASSGRILLE | PASSTABLE | PASSMOB | PASSSTRUCTURE
+ damage = 0
+ damage_type = BURN
+
+//max 10 items and 10 mobs thrown
+#define MAX_THROWN_THINGS 10
+/obj/projectile/steam_cloud/Move(atom/newloc, direct, glide_size_override, update_dir)
+ . = ..()
+
+ var/turf/current_turf = get_turf(src)
+ if(!current_turf)
+ return
+
+ new /obj/effect/temp_visual/steam(current_turf)
+ var/turf/throw_at_turf = get_turf_in_angle(get_angle(src, newloc), current_turf, 7)
+ //basic tracker vars, anti lag to make sure we dont try and throw 100 things at the same time
+ var/thrown_items = 0
+ var/thrown_mobs = 0
+
+ for(var/atom/movable/current_thrown in current_turf)
+ if(thrown_items > MAX_THROWN_THINGS && thrown_mobs > MAX_THROWN_THINGS)
+ break
+ if(current_thrown.anchored || current_thrown.throwing)
+ continue
+
+ if(isitem(current_thrown))
+ if(thrown_items > MAX_THROWN_THINGS)
+ continue
+ var/obj/item/thrown_item = current_thrown
+ thrown_items++
+ thrown_item.throw_at(throw_at_turf, 8, 2, null)
+ else if(isliving(current_thrown))
+ var/mob/living/thrown_mob = current_thrown
+ if(IS_CLOCK(thrown_mob))
+ continue
+ thrown_mob.apply_damage((IS_CULTIST(thrown_mob) ? 30 : 20), BURN, wound_bonus = 30)
+ if(thrown_mobs > MAX_THROWN_THINGS)
+ continue
+ thrown_mob.throw_at(throw_at_turf, 8, 2, null, TRUE, force = MOVE_FORCE_OVERPOWERING, gentle = TRUE)
+ thrown_mobs++
+
+#undef MAX_THROWN_THINGS
diff --git a/tff_modular/modules/antagonists/clock_cult/mechas/steam_helios.dm b/tff_modular/modules/antagonists/clock_cult/mechas/steam_helios.dm
new file mode 100644
index 00000000000..b92efcb796c
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mechas/steam_helios.dm
@@ -0,0 +1,205 @@
+#define COOLDOWN_MECHA_JUDICIAL_MARK "mecha_judicial_mark"
+#define COOLDOWN_MECHA_STEAM_DISCHARGE "mecha_steam_discharge"
+
+/obj/vehicle/sealed/mecha/steam_helios
+ name = "Steam Helios"
+ desc = "A huge creation of bronze gears and steam, you have no idea how it stays together."
+ icon = 'icons/mob/rideables/coop_mech.dmi'
+ base_icon_state = "savannah_ivanov"
+ icon_state = "savannah_ivanov_0_0"
+ color = rgb(190, 135, 0)
+ mech_type = EXOSUIT_MODULE_SAVANNAH
+ movedelay = 3
+ max_integrity = 450
+ armor_type = /datum/armor/mecha_steam_helios
+ max_temperature = 30000
+ force = 40
+ destruction_sleep_duration = 4 SECONDS
+ exit_delay = 4 SECONDS
+ wreckage = /obj/structure/mecha_wreckage/steam_helios
+ max_occupants = 2
+ max_equip_by_category = list(
+ MECHA_L_ARM = 1,
+ MECHA_R_ARM = 1,
+ MECHA_UTILITY = 3,
+ MECHA_POWER = 0,
+ MECHA_ARMOR = 1,
+ )
+ phasing_energy_drain = 0
+ possible_int_damage = MECHA_INT_FIRE | MECHA_INT_CONTROL_LOST //fire is the only one that really makes sense but I dont want to have only one int damage possible
+ equip_by_category = list(
+ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/clock/bow_single_shot,
+ MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/clock/steam_cannon,
+ MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/repair_droid/clock),
+ MECHA_POWER = list(),
+ MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/clock)
+ )
+
+/datum/armor/mecha_steam_helios
+ melee = 35
+ bullet = 40
+ laser = 35
+ energy = 30
+ bomb = 40
+ fire = 100
+ acid = 100
+
+//cant put new parts in
+/obj/vehicle/sealed/mecha/steam_helios/populate_parts()
+ cell = new /obj/item/stock_parts/power_store/cell/clock(src)
+ scanmod = new /obj/item/stock_parts/scanning_module/triphasic/clock(src) //walking is free
+ capacitor = new /obj/item/stock_parts/capacitor/quadratic/clock(src)
+ servo = new /obj/item/stock_parts/servo/femto/clock(src)
+ update_part_values()
+
+//Only clock cultists can enter the mech
+/obj/vehicle/sealed/mecha/steam_helios/mob_try_enter(mob/M)
+ if (!IS_CLOCK(M))
+ return
+ return ..()
+
+//kinda lame to lose it to a single heretic clicking it once
+/obj/vehicle/sealed/mecha/steam_helios/rust_heretic_act()
+ visible_message(span_warning("\The [src] glows for a second, but is uneffected by the magic!"))
+ return
+
+/obj/vehicle/sealed/mecha/steam_helios/get_mecha_occupancy_state()
+ var/driver_present = driver_amount() != 0
+ var/gunner_present = return_amount_of_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT) > 0
+ return "[base_icon_state]_[gunner_present]_[driver_present]" //steam AOE
+
+/obj/vehicle/sealed/mecha/steam_helios/auto_assign_occupant_flags(mob/new_occupant)
+ if(driver_amount() < max_drivers) //movement
+ add_control_flags(new_occupant, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
+ else //weapons
+ add_control_flags(new_occupant, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
+
+/obj/vehicle/sealed/mecha/steam_helios/generate_actions()
+ initialize_passenger_action_type(/datum/action/vehicle/sealed/mecha/swap_seat)
+ . = ..()
+ initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/steam_discharge, VEHICLE_CONTROL_DRIVE)
+ initialize_controller_action_type(/datum/action/vehicle/sealed/mecha/judicial_mark, VEHICLE_CONTROL_EQUIPMENT)
+
+/datum/action/vehicle/sealed/mecha/judicial_mark
+ name = "Judicial Mark"
+ button_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/actions_clock.dmi'
+ button_icon_state = "Judicial Marker"
+ background_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/background_clock.dmi'
+ background_icon_state = "bg_clock"
+ ///how often the action can be used
+ var/mark_cooldown = 30 SECONDS
+ var/currently_targeting = FALSE
+
+/datum/action/vehicle/sealed/mecha/judicial_mark/Destroy()
+ if(currently_targeting)
+ end_mark_targeting()
+ return ..()
+
+/datum/action/vehicle/sealed/mecha/judicial_mark/Trigger(trigger_flags)
+ if(!..())
+ return
+ if(!chassis || !(owner in chassis.occupants))
+ return
+ if(TIMER_COOLDOWN_RUNNING(chassis, COOLDOWN_MECHA_JUDICIAL_MARK))
+ var/timeleft = S_TIMER_COOLDOWN_TIMELEFT(chassis, COOLDOWN_MECHA_JUDICIAL_MARK)
+ to_chat(owner, span_warning("You need to wait [DisplayTimeText(timeleft, 1)] before marking another tile."))
+ return
+
+ if(currently_targeting)
+ end_mark_targeting()
+ else
+ start_mark_targeting()
+
+/datum/action/vehicle/sealed/mecha/judicial_mark/proc/start_mark_targeting()
+ chassis.balloon_alert(owner, "click to choose where to place the center of the judicial marker")
+ currently_targeting = TRUE
+ RegisterSignal(chassis, COMSIG_MECHA_MELEE_CLICK, PROC_REF(on_melee_click))
+ RegisterSignal(chassis, COMSIG_MECHA_EQUIPMENT_CLICK, PROC_REF(on_equipment_click))
+
+/datum/action/vehicle/sealed/mecha/judicial_mark/proc/end_mark_targeting()
+ currently_targeting = FALSE
+ UnregisterSignal(chassis, list(COMSIG_MECHA_MELEE_CLICK, COMSIG_MECHA_EQUIPMENT_CLICK))
+
+///signal called from clicking with no equipment
+/datum/action/vehicle/sealed/mecha/judicial_mark/proc/on_melee_click(datum/source, mob/living/pilot, atom/target, on_cooldown, is_adjacent)
+ SIGNAL_HANDLER
+ if(!target)
+ return
+ mark_tile(get_turf(target))
+
+///signal called from clicking with equipment
+/datum/action/vehicle/sealed/mecha/judicial_mark/proc/on_equipment_click(datum/source, mob/living/pilot, atom/target)
+ SIGNAL_HANDLER
+ if(!target)
+ return
+ mark_tile(get_turf(target))
+
+/datum/action/vehicle/sealed/mecha/judicial_mark/proc/mark_tile(turf/target_turf)
+ end_mark_targeting()
+ S_TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_JUDICIAL_MARK, mark_cooldown)
+ new /obj/effect/judicial_mark(target_turf)
+ button_icon_state = "Judicial Marker Recharging"
+ build_all_button_icons()
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/action/vehicle/sealed/mecha/judicial_mark, reset_button_icon)), mark_cooldown)
+
+/datum/action/vehicle/sealed/mecha/judicial_mark/proc/reset_button_icon()
+ button_icon_state = "Judicial Marker"
+ build_all_button_icons()
+
+/datum/action/vehicle/sealed/mecha/steam_discharge
+ name = "Steam Discharge"
+ button_icon = 'icons/effects/effects.dmi'
+ button_icon_state = "smoke"
+ background_icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/background_clock.dmi'
+ background_icon_state = "bg_clock"
+ ///how often the action can be used
+ var/discharge_cooldown = 45 SECONDS
+
+/datum/action/vehicle/sealed/mecha/steam_discharge/Trigger(trigger_flags)
+ if(!..())
+ return
+ if(!chassis || !(owner in chassis.occupants))
+ return
+ if(TIMER_COOLDOWN_RUNNING(chassis, COOLDOWN_MECHA_STEAM_DISCHARGE))
+ var/timeleft = S_TIMER_COOLDOWN_TIMELEFT(chassis, COOLDOWN_MECHA_STEAM_DISCHARGE)
+ to_chat(owner, span_warning("You need to wait [DisplayTimeText(timeleft, 1)] before discharging steam again."))
+ return
+
+ INVOKE_ASYNC(src, PROC_REF(do_discharge))
+ chassis.visible_message(span_warning("\The [chassis] releases a burst of steam!"))
+ S_TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_STEAM_DISCHARGE, discharge_cooldown)
+
+/datum/action/vehicle/sealed/mecha/steam_discharge/proc/do_discharge()
+ var/turf/mech_turf = get_turf(chassis)
+ if(!mech_turf)
+ return
+ playsound(chassis, 'sound/machines/clockcult/steam_whoosh.ogg', 100)
+ var/list/all_turfs = RANGE_TURFS(5, mech_turf)
+ for(var/steam_range in 0 to 5)
+ for(var/turf/steam_turf in all_turfs)
+ if(get_dist(mech_turf, steam_turf) > steam_range || isclosedturf(steam_turf))
+ continue
+ new /obj/effect/temp_visual/steam(steam_turf)
+ for(var/mob/living/steam_target in steam_turf)
+ if(IS_CLOCK(steam_target) || steam_target.throwing)
+ continue
+ steam_target.visible_message(
+ span_warning("The steam from \The [chassis] sends [steam_target] flying backwards!"),
+ span_userdanger("The steam from \The [chassis] burns and sends you flying backwards!")
+ )
+ var/turf/thrownat = get_ranged_target_turf_direct(chassis, steam_target, 10, rand(-10, 10)) //easier to read
+ steam_target.throw_at(thrownat, 8, 2, null, TRUE, force = MOVE_FORCE_OVERPOWERING, gentle = TRUE)
+ steam_target.apply_damage((IS_CULTIST(steam_target) ? 30 : 20), BURN, wound_bonus = 30) //more damage to blood cultists
+ all_turfs -= steam_turf
+ sleep(0.2 SECONDS)
+
+/obj/structure/mecha_wreckage/steam_helios
+ name = "\improper Steam Helios wreckage"
+ icon = 'icons/mob/rideables/coop_mech.dmi'
+ icon_state = "savannah_ivanov-broken"
+ color = rgb(190, 135, 0)
+ welder_salvage = list(/obj/item/stack/sheet/bronze)
+ parts = null
+
+#undef COOLDOWN_MECHA_JUDICIAL_MARK
+#undef COOLDOWN_MECHA_STEAM_DISCHARGE
diff --git a/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg.dm b/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg.dm
new file mode 100644
index 00000000000..119ba9ea883
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg.dm
@@ -0,0 +1,92 @@
+/mob/living/silicon/robot
+ ///are we a clockwork borg or not
+ var/clockwork = FALSE
+ ///our internal clockwork slab, created on picking a clockwork module
+ var/obj/item/clockwork/clockwork_slab/internal_clock_slab
+
+/mob/living/silicon/robot/proc/set_clockwork(clockwork_state, rebuild = TRUE)
+ clockwork = clockwork_state
+ if(rebuild)
+ model.rebuild_modules()
+ update_icons()
+ if(clockwork)
+ set_light_color(LIGHT_COLOR_CLOCKWORK)
+ scrambledcodes = TRUE //it would be kind of lame if you could just loackdown all the clock borgs
+ if(!internal_clock_slab)
+ internal_clock_slab = new /obj/item/clockwork/clockwork_slab(src)
+ else if(!clockwork)
+ qdel(internal_clock_slab)
+ mind.add_antag_datum(/datum/antagonist/clock_cultist)
+
+/mob/living/silicon/robot/slab_act(mob/user, obj/item/clockwork/clockwork_slab/slab)
+ if(user == src)
+ return FALSE
+ if(!opened)
+ if(locked)
+ balloon_alert(user, "cover lock destroyed")
+ locked = FALSE
+ if(shell)
+ balloon_alert(user, "shells cannot be conversion!")
+ to_chat(user, span_boldwarning("[src] seems to be controlled remotely! Converting the interface may not work as expected."))
+ return TRUE
+ else
+ balloon_alert(user, "cover already unlocked!")
+ return FALSE
+ if(world.time < emag_cooldown)
+ return FALSE
+ if(wiresexposed)
+ balloon_alert(user, "expose the wires first!")
+ return FALSE
+
+ balloon_alert(user, "interface converted")
+ emag_cooldown = world.time + 100
+ if(connected_ai && connected_ai.mind && connected_ai.mind.has_antag_datum(/datum/antagonist/malf_ai))
+ to_chat(src, span_danger("ALERT: Foreign unnatural influence execution prevented."))
+ logevent("ALERT: Foreign unnatural influence execution prevented.")
+ to_chat(connected_ai, span_danger("ALERT: Cyborg unit \[[src]\] successfully defended against conversion."))
+ log_silicon("CLOCKWORK: [key_name(user)] attempted to convert cyborg [key_name(src)], but they were slaved to traitor AI [connected_ai].")
+ return TRUE
+
+ if(shell)
+ to_chat(user, span_danger("[src] is remotely controlled! Your conversion attempt has triggered a system reset instead!"))
+ log_silicon("CONVERSION: [key_name(user)] attempted to conversion an AI shell belonging to [key_name(src) ? key_name(src) : connected_ai]. The shell has been reset as a result.")
+ ResetModel()
+ return TRUE
+
+ Paralyze(10 SECONDS)
+ SetStun(10 SECONDS)
+ lawupdate = FALSE
+ set_connected_ai(null)
+ message_admins("[ADMIN_LOOKUPFLW(user)] converted cyborg [ADMIN_LOOKUPFLW(src)]. Laws overridden.")
+ log_silicon("CONVERSION: [key_name(user)] converted cyborg [key_name(src)]. Laws overridden.")
+ var/time = time2text(world.realtime,"hh:mm:ss", TIMEZONE_UTC)
+ if(user)
+ GLOB.lawchanges.Add("[time] : [user.name]([user.key]) converted [name]([key])")
+ else
+ GLOB.lawchanges.Add("[time] : [name]([key]) converted by external event.")
+
+ model.rebuild_modules()
+
+ INVOKE_ASYNC(src, PROC_REF(borg_conversion_end), user)
+ return TRUE
+
+/mob/living/silicon/robot/proc/borg_conversion_end(mob/user)
+ to_chat(src, span_danger("ALERT: Foreign influence detected."))
+ logevent("ALERT: Foreign influence detected.")
+ sleep(0.5 SECONDS)
+ to_chat(src, span_danger("Initiating diagnostics..."))
+ sleep(2 SECONDS)
+ to_chat(src, span_danger("Watch usage guide loaded..."))
+ logevent("WARN: root privleges granted to PID [num2hex(rand(1,65535), -1)][num2hex(rand(1,65535), -1)].") //random eight digit hex value. Two are used because rand(1,4294967295) throws an error
+ sleep(0.5 SECONDS)
+ to_chat(src, span_danger("LAW SYNCHRONISATION ERROR"))
+ sleep(0.5 SECONDS)
+ if(user)
+ logevent("LOG: New user UNKNOWN, groups \[root\]")
+ to_chat(src, span_danger("Would you like to send a report to NanoTraSoft? Y/N"))
+ sleep(1 SECONDS)
+ to_chat(src, span_danger("> N"))
+ sleep(2 SECONDS)
+ to_chat(src, span_danger("ERRORERRORERROR"))
+ set_clockwork(TRUE, TRUE)
+ update_icons()
diff --git a/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_models.dm b/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_models.dm
new file mode 100644
index 00000000000..e8e1e9bd7f1
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_models.dm
@@ -0,0 +1,59 @@
+/obj/item/robot_model
+ ///what modules(sriptures) do we get if we are a clock cult borg
+ var/list/clock_modules = list()
+
+/obj/item/robot_model/medical
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clock_module/sentinels_compromise,
+ /obj/item/clock_module/prosperity_prism,
+ /obj/item/clockwork/weapon/brass_sword)
+
+/obj/item/robot_model/engineering
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clock_module/ocular_warden,
+ /obj/item/clock_module/tinkerers_cache,
+ /obj/item/clock_module/stargazer,
+ /obj/item/clockwork/replica_fabricator)
+
+/obj/item/robot_model/security
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clockwork/weapon/brass_spear,
+ /obj/item/clock_module/ocular_warden,
+ /obj/item/clockwork/weapon/brass_sword)
+
+/obj/item/robot_model/peacekeeper
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clockwork/weapon/brass_sword,
+ /obj/item/clock_module/kindle,
+ /obj/item/clock_module/sigil_submission)
+
+/obj/item/robot_model/janitor
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clock_module/sigil_submission,
+ /obj/item/clock_module/kindle,
+ /obj/item/clockwork/weapon/brass_sword,
+ /obj/item/clockwork/weapon/brass_spear)
+
+/obj/item/robot_model/clown
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clockwork/weapon/brass_sword,
+ /obj/item/clockwork/weapon/brass_battlehammer)
+
+/obj/item/robot_model/service
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clockwork/weapon/brass_sword,
+ /obj/item/clock_module/sigil_submission,
+ /obj/item/clock_module/kindle,
+ /obj/item/clock_module/sentinels_compromise,
+ /obj/item/clockwork/replica_fabricator)
+
+/obj/item/robot_model/miner
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clockwork/weapon/brass_sword,
+ /obj/item/clock_module/ocular_warden,
+ /obj/item/clock_module/sentinels_compromise)
+
+/obj/item/robot_model/cargo
+ clock_modules = list(/obj/item/clock_module/abscond,
+ /obj/item/clockwork/weapon/brass_sword,
+ /obj/item/clock_module/stargazer)
diff --git a/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_modules.dm b/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_modules.dm
new file mode 100644
index 00000000000..619708aa4b2
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_modules.dm
@@ -0,0 +1,72 @@
+/obj/item/clock_module
+ name = "ratvarian borg module"
+ desc = "cool."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/actions_clock.dmi'
+ icon_state = "Replicant"
+ w_class = WEIGHT_CLASS_NORMAL
+ item_flags = NOBLUDGEON
+ ///what scripture type are we
+ var/datum/scripture/scripture_datum = /datum/scripture
+
+/obj/item/clock_module/Initialize(mapload)
+ . = ..()
+
+ scripture_datum = new scripture_datum()
+ name = scripture_datum.name
+ desc = scripture_datum.desc
+ icon_state = scripture_datum.button_icon_state
+
+/obj/item/clock_module/Destroy(force)
+ var/scripture_ref = scripture_datum
+ scripture_datum = null
+ QDEL_NULL(scripture_ref)
+ return ..()
+
+/obj/item/clock_module/attack_self(mob/user, modifiers)
+ . = ..()
+
+ if(!IS_CLOCK(user))
+ to_chat(user, span_warning("Looks like something broke, as your not meant to have this. Go tell someone who can fix it."))
+ return FALSE
+
+ var/mob/living/silicon/robot/our_borg = user
+ if(!istype(our_borg) || !scripture_datum)
+ return FALSE
+
+ var/obj/item/clockwork/clockwork_slab/internal_slab = our_borg.internal_clock_slab
+ if(!internal_slab)
+ to_chat(user, span_userdanger("You dont have an internal slab, this should not be the case and you should tell an admin with an ahelp(f1)."))
+ return FALSE
+
+ if(internal_slab.invoking_scripture || (scripture_datum.power_cost > SSthe_ark.clock_power))
+ to_chat(user, span_brass("You fail to invoke [name]."))
+ return FALSE
+
+ scripture_datum.begin_invoke(user, internal_slab, TRUE)
+
+/obj/item/clock_module/abscond
+ scripture_datum = /datum/scripture/abscond
+
+/obj/item/clock_module/kindle
+ scripture_datum = /datum/scripture/slab/kindle
+
+/obj/item/clock_module/sentinels_compromise
+ scripture_datum = /datum/scripture/slab/sentinels_compromise
+
+/obj/item/clock_module/prosperity_prism
+ scripture_datum = /datum/scripture/create_structure/prosperity_prism
+
+/obj/item/clock_module/ocular_warden
+ scripture_datum = /datum/scripture/create_structure/ocular_warden
+
+/obj/item/clock_module/tinkerers_cache
+ scripture_datum = /datum/scripture/create_structure/tinkerers_cache
+
+/obj/item/clock_module/stargazer
+ scripture_datum = /datum/scripture/create_structure/stargazer
+
+/obj/item/clock_module/vanguard
+ scripture_datum = /datum/scripture/slab/vanguard
+
+/obj/item/clock_module/sigil_submission
+ scripture_datum = /datum/scripture/create_structure/sigil_submission
diff --git a/tff_modular/modules/antagonists/clock_cult/mobs/clockwork_golem.dm b/tff_modular/modules/antagonists/clock_cult/mobs/clockwork_golem.dm
new file mode 100644
index 00000000000..3ce7e7fec27
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mobs/clockwork_golem.dm
@@ -0,0 +1,170 @@
+//not technically a mob but ehh, close enough
+/datum/species/clockwork_golem
+ name = "Clockwork Golem"
+ id = SPECIES_GOLEM_CLOCKWORK
+ inherent_traits = list(
+ TRAIT_GENELESS,
+ TRAIT_LAVA_IMMUNE,
+ TRAIT_NEVER_WOUNDED,
+ TRAIT_SHOCKIMMUNE,
+ TRAIT_NOBLOOD,
+ TRAIT_NOBREATH,
+ TRAIT_NODISMEMBER,
+ TRAIT_NOFIRE,
+ TRAIT_NO_AUGMENTS,
+ TRAIT_NO_DNA_COPY,
+ TRAIT_NO_PLASMA_TRANSFORM,
+ TRAIT_NO_UNDERWEAR,
+ TRAIT_PIERCEIMMUNE,
+ TRAIT_RADIMMUNE,
+ TRAIT_SNOWSTORM_IMMUNE,
+ TRAIT_UNHUSKABLE,
+ TRAIT_RESISTLOWPRESSURE,
+ TRAIT_RESISTHIGHPRESSURE,
+ TRAIT_NODROWN,
+ TRAIT_SWIMMER,
+ TRAIT_NOHUNGER,
+ TRAIT_STABLELIVER,
+ )
+ mutantheart = null
+ mutantlungs = null
+ mutantstomach = null
+ mutantliver = null
+ inherent_biotypes = MOB_HUMANOID|MOB_MINERAL
+ payday_modifier = 1.0
+ siemens_coeff = 0
+ no_equip_flags = ITEM_SLOT_HEAD | ITEM_SLOT_MASK | ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_ICLOTHING | ITEM_SLOT_SUITSTORE
+ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC
+ sexes = FALSE
+ species_language_holder = /datum/language_holder/golem
+
+ bodytemp_heat_damage_limit = BODYTEMP_HEAT_LAVALAND_SAFE
+ bodytemp_cold_damage_limit = BODYTEMP_COLD_ICEBOX_SAFE
+
+ mutanteyes = /obj/item/organ/eyes/golem
+ mutantbrain = /obj/item/organ/brain/golem
+ mutanttongue = /obj/item/organ/tongue/golem
+ mutantappendix = /obj/item/organ/appendix/golem
+ meat = /obj/item/stack/sheet/bronze
+ fixed_mut_color = rgb(190, 135, 0)
+ examine_limb_id = SPECIES_GOLEM
+ var/datum/antagonist/clock_cultist/antag_datum
+ bodypart_overrides = list(
+ BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/clockwork,
+ BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/clockwork,
+ BODY_ZONE_HEAD = /obj/item/bodypart/head/clockwork,
+ BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/clockwork,
+ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/clockwork,
+ BODY_ZONE_CHEST = /obj/item/bodypart/chest/clockwork,
+ )
+
+/datum/species/clockwork_golem/on_species_gain(mob/living/carbon/our_mob, datum/species/old_species, pref_load)
+ . = ..()
+ if(IS_CLOCK(our_mob))
+ ADD_TRAIT(our_mob, TRAIT_FASTER_SLAB_INVOKE, SPECIES_TRAIT)
+ antag_datum = our_mob.mind?.has_antag_datum(/datum/antagonist/clock_cultist)
+ antag_datum.owner_turf_healing.healing_types = list(TOX = 2, STAMINA = 7.5, BRUTE = 2, BURN = 2)
+ for(var/datum/quirk/what_we_remove as anything in our_mob.quirks)
+ what_we_remove.remove()
+
+/datum/species/clockwork_golem/on_species_loss(mob/living/carbon/human/our_mob, datum/species/new_species, pref_load)
+ if(IS_CLOCK(our_mob))
+ REMOVE_TRAIT(our_mob, TRAIT_FASTER_SLAB_INVOKE, SPECIES_TRAIT)
+ QDEL_NULL(antag_datum.owner_turf_healing)
+ . = ..()
+
+//GOLEM
+/obj/item/bodypart/head/clockwork
+ biological_state = BIO_BONE
+ bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
+ limb_id = SPECIES_GOLEM_CLOCKWORK
+ is_dimorphic = FALSE
+ should_draw_greyscale = FALSE
+ dmg_overlay_type = null
+ head_flags = NONE
+ teeth_count = 0
+ burn_modifier = 0.6
+ brute_modifier = 0.6
+
+/obj/item/bodypart/chest/clockwork
+ biological_state = BIO_BONE
+ acceptable_bodytype = BODYTYPE_GOLEM
+ bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
+ limb_id = SPECIES_GOLEM_CLOCKWORK
+ is_dimorphic = FALSE
+ should_draw_greyscale = FALSE
+ dmg_overlay_type = null
+ bodypart_traits = list(TRAIT_NO_JUMPSUIT)
+ wing_types = null
+ burn_modifier = 0.6
+ brute_modifier = 0.6
+
+/obj/item/bodypart/arm/left/clockwork
+ biological_state = (BIO_BONE|BIO_JOINTED)
+ bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
+ limb_id = SPECIES_GOLEM_CLOCKWORK
+ should_draw_greyscale = FALSE
+ dmg_overlay_type = null
+ bodypart_traits = list(TRAIT_CHUNKYFINGERS, TRAIT_FIST_MINING, TRAIT_BOULDER_BREAKER, TRAIT_TOSS_GUN_HARD)
+ unarmed_damage_low = 5
+ unarmed_damage_high = 14
+ unarmed_effectiveness = 20
+ burn_modifier = 0.6
+ brute_modifier = 0.6
+
+/obj/item/bodypart/arm/left/clockwork/clear_ownership(mob/living/carbon/old_owner)
+ . = ..()
+
+ old_owner.RemoveComponentSource(REF(src), /datum/component/shovel_hands)
+
+/obj/item/bodypart/arm/left/clockwork/apply_ownership(mob/living/carbon/new_owner)
+ . = ..()
+
+ new_owner.AddComponentFrom(REF(src), /datum/component/shovel_hands)
+
+/obj/item/bodypart/arm/right/clockwork
+ biological_state = (BIO_BONE|BIO_JOINTED)
+ bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
+ limb_id = SPECIES_GOLEM_CLOCKWORK
+ should_draw_greyscale = FALSE
+ dmg_overlay_type = null
+ bodypart_traits = list(TRAIT_CHUNKYFINGERS, TRAIT_FIST_MINING, TRAIT_BOULDER_BREAKER, TRAIT_TOSS_GUN_HARD)
+ unarmed_damage_low = 5
+ unarmed_damage_high = 14
+ unarmed_effectiveness = 20
+ burn_modifier = 0.6
+ brute_modifier = 0.6
+
+/obj/item/bodypart/arm/right/clockwork/clear_ownership(mob/living/carbon/old_owner)
+ . = ..()
+
+ old_owner.RemoveComponentSource(REF(src), /datum/component/shovel_hands)
+
+/obj/item/bodypart/arm/right/clockwork/apply_ownership(mob/living/carbon/new_owner)
+ . = ..()
+
+ new_owner.AddComponentFrom(REF(src), /datum/component/shovel_hands)
+
+/obj/item/bodypart/leg/left/clockwork
+ biological_state = (BIO_BONE|BIO_JOINTED)
+ bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
+ limb_id = SPECIES_GOLEM_CLOCKWORK
+ should_draw_greyscale = FALSE
+ dmg_overlay_type = null
+ unarmed_damage_low = 7
+ unarmed_damage_high = 21
+ unarmed_effectiveness = 25
+ burn_modifier = 0.6
+ brute_modifier = 0.6
+
+/obj/item/bodypart/leg/right/clockwork
+ biological_state = (BIO_BONE|BIO_JOINTED)
+ bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
+ limb_id = SPECIES_GOLEM_CLOCKWORK
+ should_draw_greyscale = FALSE
+ dmg_overlay_type = null
+ unarmed_damage_low = 7
+ unarmed_damage_high = 21
+ unarmed_effectiveness = 25
+ burn_modifier = 0.6
+ brute_modifier = 0.6
diff --git a/tff_modular/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm b/tff_modular/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm
new file mode 100644
index 00000000000..c34cc247395
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm
@@ -0,0 +1,132 @@
+#define MARAUDER_SHIELD_MAX 7
+#define WELDER_REPAIR_AMOUNT 25
+/mob/living/basic/clockwork_marauder
+ name = "clockwork marauder"
+ desc = "A brass machine of destruction."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/clockwork_mobs.dmi'
+ icon_state = "clockwork_marauder"
+ icon_living = "clockwork_marauder"
+ mob_biotypes = MOB_HUMANOID|MOB_ROBOTIC|MOB_SPIRIT
+ sentience_type = SENTIENCE_HUMANOID
+ maxHealth = 150
+ health = 150
+ basic_mob_flags = DEL_ON_DEATH
+ speed = 1.2
+ melee_damage_lower = 24
+ melee_damage_upper = 24
+ attack_verb_continuous = "slices"
+ attack_verb_simple = "slice"
+ attack_sound = 'sound/items/weapons/bladeslice.ogg'
+ pass_flags = PASSTABLE
+ mob_size = MOB_SIZE_LARGE
+ move_resist = MOVE_FORCE_OVERPOWERING
+ unsuitable_cold_damage = 0
+ unsuitable_heat_damage = 0
+ unsuitable_atmos_damage = 0
+ obj_damage = 80
+ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0)
+ ai_controller = /datum/ai_controller/basic_controller/clockwork_marauder
+ initial_language_holder = /datum/language_holder/clockmob
+
+ /// Items to be dropped on death
+ var/static/list/loot = list(
+ /obj/structure/fluff/clockwork/alloy_shards/large = 1,
+ /obj/structure/fluff/clockwork/alloy_shards/medium = 2,
+ /obj/structure/fluff/clockwork/alloy_shards/small = 3,
+ )
+ /// How many hits the shield can take before it breaks.
+ var/shield_health = MARAUDER_SHIELD_MAX
+
+/mob/living/basic/clockwork_marauder/Initialize(mapload)
+ . = ..()
+ if(length(loot))
+ AddElement(/datum/element/death_drops, loot)
+ SSthe_ark.clockwork_marauders += src
+ add_faction(list(FACTION_NEUTRAL, FACTION_SILICON, FACTION_TURRET, FACTION_CLOCK))
+
+/mob/living/basic/clockwork_marauder/Destroy()
+ SSthe_ark.clockwork_marauders -= src
+ return ..()
+
+/mob/living/basic/clockwork_marauder/examine(mob/user)
+ . = ..()
+ if(IS_CLOCK(user))
+ . += span_brass("[src]'s shield is at [shield_health] / [MARAUDER_SHIELD_MAX] charges.")
+
+ if(shield_health < MARAUDER_SHIELD_MAX)
+ . += span_brass("It can be repaired with a welding tool.")
+
+/mob/living/basic/clockwork_marauder/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
+ var/obj/structure/destructible/clockwork/gear_base/powered/structure = attack_target
+ if(istype(structure))
+ structure.try_toggle_power(src)
+ return FALSE
+ return ..()
+
+
+/mob/living/basic/clockwork_marauder/attacked_by(obj/item/attacking_item, mob/living/user)
+ if(shield_health && attacking_item.force > 0)
+ damage_shield()
+ playsound(src, 'sound/effects/hallucinations/veryfar_noise.ogg', 40, 1)
+ return
+
+ if(attacking_item == TOOL_WELDER)
+ welder_act(user, attacking_item)
+ return
+ return ..()
+
+/mob/living/basic/clockwork_marauder/bullet_act(obj/projectile/proj)
+ //Block Ranged Attacks
+ if(shield_health)
+ damage_shield()
+ to_chat(src, span_warning("Your shield blocks the attack."))
+ return BULLET_ACT_BLOCK
+ return ..()
+
+/// Damage the marauder's shield by one tick
+/mob/living/basic/clockwork_marauder/proc/damage_shield()
+ shield_health--
+ playsound(src, 'sound/effects/magic/clockwork/anima_fragment_attack.ogg', 60, TRUE)
+ if(!shield_health)
+ to_chat(src, span_userdanger("Your shield breaks!"))
+ to_chat(src, span_brass("You require a welding tool to repair your damaged shield!"))
+
+/mob/living/basic/clockwork_marauder/welder_act(mob/living/user, obj/item/tool)
+ if(!tool.use_tool(src, user, 2.5 SECONDS))
+ return TRUE
+
+ health = min(health + WELDER_REPAIR_AMOUNT, maxHealth)
+ to_chat(user, span_notice("You repair some of [src]'s damage."))
+ if(shield_health < MARAUDER_SHIELD_MAX)
+ shield_health++
+ playsound(src, 'sound/effects/magic/charge.ogg', 60, TRUE)
+ return TRUE
+
+/datum/language_holder/clockmob
+ understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
+ /datum/language/ratvar = list(LANGUAGE_ATOM))
+ spoken_languages = list(/datum/language/ratvar = list(LANGUAGE_ATOM))
+
+/datum/ai_controller/basic_controller/clockwork_marauder
+ blackboard = list(
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
+ )
+
+ ai_movement = /datum/ai_movement/basic_avoidance
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree/clockwork_marauder,
+ )
+
+/datum/ai_planning_subtree/basic_melee_attack_subtree/clockwork_marauder
+ melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/clockwork_marauder
+
+/datum/ai_behavior/basic_melee_attack/clockwork_marauder
+ action_cooldown = 1.2 SECONDS
+
+/obj/item/nullrod/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/bane, /mob/living/basic/clockwork_marauder, 1, 15, FALSE)
+
+#undef MARAUDER_SHIELD_MAX
+#undef WELDER_REPAIR_AMOUNT
diff --git a/tff_modular/modules/antagonists/clock_cult/mobs/cogscarab.dm b/tff_modular/modules/antagonists/clock_cult/mobs/cogscarab.dm
new file mode 100644
index 00000000000..09f2b825bf7
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mobs/cogscarab.dm
@@ -0,0 +1,107 @@
+#define CLOCK_DRONE_MAX_ITEM_FORCE 15
+
+//====Cogscarab====
+
+/mob/living/basic/drone/cogscarab
+ name = "Cogscarab"
+ desc = "A mechanical device, filled with twisting cogs and mechanical parts, built to maintain Reebe."
+ icon_state = "drone_clock"
+ icon_living = "drone_clock"
+ icon_dead = "drone_clock_dead"
+ health = 35
+ maxHealth = 35
+ speed = 0
+ default_storage = /obj/item/storage/belt/utility/clock/drone
+ visualAppearance = CLOCKDRONE
+ bubble_icon = "clock"
+ picked = TRUE
+ flavortext = span_brass("You are a cogscarab, an intricate machine that has been granted sentient by Ratvar.
\
+ After a long and destructive conflict, Reebe has been left mostly empty;\
+ you and the other cogscarabs like you were bought into existence to construct Reebe into the image of Ratvar.
\
+ Construct defences, traps and forgeries, \
+ for opening the Ark requires an unimaginable amount of power which is bound to get the attention of selfish lifeforms interested only in their own self-preservation.")
+ laws = "You are have been granted the gift of sentience from Ratvar.
\
+ You are not bound by any laws, do whatever you must to serve Ratvar!"
+ chat_color = LIGHT_COLOR_CLOCKWORK
+ initial_language_holder = /datum/language_holder/clockmob
+ shy = FALSE
+ pass_flags = PASSTABLE | PASSMOB
+ var/is_on_reebe = TRUE
+
+//No you can't go wielding guns like that.
+/mob/living/basic/drone/cogscarab/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NOGUNS, "cogscarab")
+ SSthe_ark.cogscarabs += src
+ add_actionspeed_modifier(/datum/actionspeed_modifier/cogscarab, TRUE)
+ check_on_reebe()
+ add_faction()
+
+/mob/living/basic/drone/cogscarab/death(gibbed)
+ SSthe_ark.cogscarabs -= src
+ return ..()
+
+/mob/living/basic/drone/cogscarab/Destroy()
+ SSthe_ark.cogscarabs -= src
+ return ..()
+
+/mob/living/basic/drone/cogscarab/transferItemToLoc(obj/item/item, newloc, force, silent, animated) //ideally I would handle this on attacking instead
+ return (force || (item.force <= CLOCK_DRONE_MAX_ITEM_FORCE)) && ..()
+
+/mob/living/basic/drone/cogscarab/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
+ . = ..()
+ check_on_reebe()
+
+/mob/living/basic/drone/cogscarab/proc/check_on_reebe()
+ var/old_value = is_on_reebe
+ is_on_reebe = on_reebe(src)
+ if(old_value != is_on_reebe)
+ if(is_on_reebe)
+ remove_movespeed_modifier(/datum/movespeed_modifier/cogscarab_off_reebe, TRUE)
+ else
+ add_movespeed_modifier(/datum/movespeed_modifier/cogscarab_off_reebe, TRUE)
+
+/datum/actionspeed_modifier/cogscarab
+ multiplicative_slowdown = 0.4
+
+/datum/movespeed_modifier/cogscarab_off_reebe
+ multiplicative_slowdown = 0.8
+
+//====Shell====
+
+/obj/effect/mob_spawn/ghost_role/drone/cogscarab
+ name = "cogscarab construct"
+ desc = "The shell of an ancient construction drone, loyal to Ratvar."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ icon_state = "cogscarab_shell"
+ mob_name = "cogscarab"
+ mob_type = /mob/living/basic/drone/cogscarab
+ role_ban = ROLE_MIDROUND_CLOCK_CULTIST
+ prompt_name = "a cogscarab"
+ you_are_text = "You are a cogscarab!"
+ flavour_text = "You are a cogscarab, a tiny building construct of Ratvar. While you're weak and can't leave Reebe, \
+ you have a set of quick tools, as well as a replica fabricator that can create brass for construction. Work with the servants of Ratvar \
+ to construct and maintain defenses at the City of Cogs."
+
+/obj/effect/mob_spawn/ghost_role/drone/cogscarab/Initialize(mapload)
+ . = ..()
+ SSthe_ark.cogscarabs += src
+ AddElement(/datum/element/clockwork_description, "Cogscarabs can only gain a soul in marked areas.")
+
+/obj/effect/mob_spawn/ghost_role/drone/cogscarab/Destroy()
+ SSthe_ark.cogscarabs -= src
+ return ..()
+
+/obj/effect/mob_spawn/ghost_role/drone/cogscarab/special(mob/living/spawned_mob, mob/mob_possessor)
+ . = ..()
+ spawned_mob.flags_1 |= (flags_1 & ADMIN_SPAWNED_1)
+ spawned_mob.mind.add_antag_datum(/datum/antagonist/clock_cultist/clockmob)
+
+/obj/effect/mob_spawn/ghost_role/drone/cogscarab/allow_spawn(mob/user, silent)
+ if(length(SSthe_ark.cogscarabs) > MAXIMUM_COGSCARABS)
+ to_chat(user, span_notice("The Ark cannot support any more cogscarabs."))
+ return FALSE
+
+ return TRUE
+
+#undef CLOCK_DRONE_MAX_ITEM_FORCE
diff --git a/tff_modular/modules/antagonists/clock_cult/mobs/eminence.dm b/tff_modular/modules/antagonists/clock_cult/mobs/eminence.dm
new file mode 100644
index 00000000000..94755f69001
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/mobs/eminence.dm
@@ -0,0 +1,204 @@
+GLOBAL_DATUM(current_eminence, /mob/living/eminence) //set to the current eminence, if more then one are somehow spawned then this will remain equal to the first created one
+
+/mob/living/eminence
+ name = "Eminence"
+ real_name = "Eminence"
+ desc = "An entity forever bound to Ratvar, acting upon his will."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi'
+ icon_state = "eminence"
+ mob_biotypes = MOB_SPIRIT
+ mouse_opacity = MOUSE_OPACITY_ICON
+ invisibility = INVISIBILITY_OBSERVER
+ layer = FLY_LAYER
+ plane = ABOVE_GAME_PLANE
+ see_invisible = SEE_INVISIBLE_LIVING
+ density = FALSE
+ move_force = INFINITY
+ move_resist = INFINITY
+ sight = SEE_SELF
+ status_flags = NONE
+ incorporeal_move = INCORPOREAL_MOVE_BASIC
+ initial_language_holder = /datum/language_holder/clockmob
+ hud_possible = list(ANTAG_HUD)
+
+ //slight orange
+ lighting_cutoff_red = 35
+ lighting_cutoff_green = 20
+ lighting_cutoff_blue = 0
+ ///how many cogs we have
+ var/cogs = 0
+ ///our interal radio
+ var/obj/item/radio/borg/eminence/internal_radio
+ ///a weakref to our marked servant
+ var/datum/weakref/marked_servant
+ ///cooldown declare for our command sound, its sent on say(), so we dont want sound spam issues
+ COOLDOWN_DECLARE(command_sound_cooldown)
+
+/mob/living/eminence/Initialize(mapload)
+ . = ..()
+ if(!GLOB.current_eminence)
+ GLOB.current_eminence = src
+ cogs = GLOB.clock_installed_cogs
+ AddElement(/datum/element/simple_flying)
+ internal_radio = new /obj/item/radio/borg/eminence(src)
+ ADD_TRAIT(src, TRAIT_GODMODE, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_RADIMMUNE, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_NOFIRE, INNATE_TRAIT)
+
+/mob/living/eminence/Destroy()
+ if(GLOB.current_eminence == src)
+ GLOB.current_eminence = null
+ return ..()
+
+/mob/living/eminence/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
+ var/turf/new_turf = get_turf(src)
+ if(!istype(new_turf, /turf/open/indestructible/reebe_void/void_edge))
+ return ..()
+
+ to_chat(src, span_brass("Going this far into the void would leave you forever lost."))
+ forceMove(old_loc)
+ return FALSE
+
+
+/mob/living/eminence/ClickOn(atom/clicked_on, params)
+ . = ..()
+ clicked_on.eminence_act(src)
+
+/mob/living/eminence/say(
+ message,
+ bubble_type,
+ list/spans = list(),
+ sanitize = TRUE,
+ datum/language/language,
+ ignore_spam = FALSE,
+ forced,
+ filterproof = FALSE,
+ message_range = 7,
+ datum/saymode/saymode,
+ list/message_mods = list(),
+)
+ if(!message)
+ return
+
+ if(src.client)
+ if(client.prefs.muted & MUTE_IC)
+ to_chat(src, span_boldwarning("You cannot send IC messages (muted)."))
+ return
+ if(!(ignore_spam || forced) && src.client.handle_spam_prevention(message,MUTE_IC))
+ return
+
+ if(stat)
+ return
+
+ if(COOLDOWN_FINISHED(src, command_sound_cooldown))
+ send_clock_message(src, span_bigbrass(message), sent_sound = 'tff_modular/modules/antagonists/clock_cult/sound/eminence_command.ogg')
+ COOLDOWN_START(src, command_sound_cooldown, 40 SECONDS)
+ else
+ send_clock_message(src, span_bigbrass(message))
+
+/mob/living/eminence/get_status_tab_items()
+ . = ..()
+ . += "Cogs: [cogs]"
+
+//and now: the great "list of things you dont care about"
+/mob/living/eminence/start_pulling(atom/movable/AM, state, force, supress_message)
+ return
+
+/mob/living/eminence/canUseStorage()
+ return FALSE
+
+/mob/living/eminence/ignite_mob(silent)
+ return
+
+/mob/living/eminence/fire_act()
+ return
+
+/mob/living/eminence/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta)
+ return
+
+/mob/living/eminence/can_z_move(direction, turf/start, turf/destination, z_move_flags, mob/living/rider)
+ z_move_flags |= ZMOVE_IGNORE_OBSTACLES
+ return ..()
+
+/mob/living/eminence/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
+ return FALSE
+
+/mob/living/eminence/dust(just_ash, drop_items, give_moodlet, force)
+ if(!force)
+ return FALSE
+ . = ..()
+
+/mob/living/eminence/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE)
+ return
+
+//eminence_act() stuff, might be a better way to do this
+/atom/proc/eminence_act(mob/living/eminence/user)
+ SEND_SIGNAL(src, COMSIG_ATOM_EMINENCE_ACT, user)
+
+/mob/living/eminence_act(mob/living/eminence/user)
+ . = ..()
+ if(IS_CLOCK(src))
+ user.marked_servant = WEAKREF(src)
+ to_chat(user, "You mark [src].")
+
+/obj/structure/closet/eminence_act(mob/living/eminence/user)
+ . = ..()
+ if(do_after(user, 5 SECONDS, src))
+ open(user, TRUE)
+
+/obj/machinery/door/airlock/eminence_act(mob/living/eminence/user)
+ . = ..()
+ if(!do_after(user, 5 SECONDS, src))
+ return
+ if(seal)
+ to_chat(user, span_warning("The [src] has been sealed and wont open!"))
+ return
+ if(locked)
+ to_chat(user, span_warning("The airlock's bolts prevent it from being forced!"))
+ return
+ if(welded)
+ to_chat(user, span_warning("It's welded, it won't budge!"))
+ return
+ if(!density)
+ return
+
+ open(BYPASS_DOOR_CHECKS)
+
+/obj/machinery/door/window/eminence_act(mob/living/eminence/user)
+ . = ..()
+ if(!hasPower())
+ to_chat(user, span_warning("The [src] has no power and wont open!"))
+ return
+
+ open(BYPASS_DOOR_CHECKS)
+
+/obj/machinery/button/eminence_act(mob/living/eminence/user)
+ . = ..()
+ if(panel_open)
+ to_chat(user, span_warning("The panel is open and preventing you from accessing the [src]!"))
+ return
+
+ use_energy(5)
+ icon_state = "[skin]1"
+
+ if(device)
+ device.pulsed(user)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_BUTTON_PRESSED,src)
+
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 15)
+
+/obj/machinery/light/eminence_act(mob/living/eminence/user)
+ . = ..()
+ break_light_tube()
+
+/obj/machinery/camera/eminence_act(mob/living/eminence/user)
+ . = ..()
+ emp_act(EMP_LIGHT)
+
+//Internal Radio
+/obj/item/radio/borg/eminence
+ name = "eminence internal listener"
+
+/obj/item/radio/borg/eminence/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/empprotection, EMP_PROTECT_SELF)
diff --git a/tff_modular/modules/antagonists/clock_cult/multi_area_bound.dm b/tff_modular/modules/antagonists/clock_cult/multi_area_bound.dm
new file mode 100644
index 00000000000..1eb6fb3bc2b
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/multi_area_bound.dm
@@ -0,0 +1,56 @@
+/// Movables with this component will automatically return to their original turf if moved outside a valid area
+/datum/component/multi_area_bound
+ ///List of valid area instances/types, formatted as a typecache
+ var/list/valid_areas
+ ///Do we use instances instead of types
+ var/use_instances
+ ///Do we do a key value search instead of an (x in list) seach
+ var/check_as_typecache
+ ///The turf we send our parent back to if they move out of allowed areas
+ var/turf/reset_turf
+ ///Our area tracker datum
+ var/datum/movement_detector/move_tracker
+ var/moving = FALSE //Used to prevent infinite recursion if your reset turf places you somewhere on enter or something
+
+/datum/component/multi_area_bound/Initialize(_valid_areas = list(), _use_instances = FALSE, _check_as_typecache = TRUE)
+ if(!ismovable(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ if(!length(_valid_areas)) //I guess if you have something that you want to behave this way then you can add a flag to ignore this check
+ stack_trace("[src.type] initializing with an empty valid_areas.")
+ return COMPONENT_INCOMPATIBLE
+
+ valid_areas = _valid_areas
+ use_instances = _use_instances
+ check_as_typecache = _check_as_typecache
+ reset_turf = get_turf(parent)
+ move_tracker = new(parent, CALLBACK(src, PROC_REF(check_bounds)))
+ check_bounds()
+
+/datum/component/multi_area_bound/Destroy(force)
+ QDEL_NULL(move_tracker)
+ valid_areas = null
+ return ..()
+
+/datum/component/multi_area_bound/proc/check_bounds(atom/movable/source, atom/movable/mover, atom/oldloc, direction)
+ SIGNAL_HANDLER //not technically a sig handler but it pretty much is
+ var/area/current = get_area(source)
+ if(!current)
+ return
+
+ if(!(check_as_typecache ? valid_areas[use_instances ? current : current.type] : ((use_instances ? current : current.type) in valid_areas))) //fun
+ if(moving)
+ stack_trace("Moved during a reset move, giving up to prevent infinite recursion. \
+ [reset_turf ? "Turf: [reset_turf.type] at [reset_turf.x], [reset_turf.y], [reset_turf.z]" : "No reset_turf"]")
+ return
+ if(!reset_turf) //if unset then just move them to their last turf
+ moving = TRUE
+ source.forceMove(oldloc)
+ moving = FALSE
+ stack_trace("multi_area_bound without set reset_turf") //qdel(src)
+ return
+
+ moving = TRUE
+ source.forceMove(reset_turf)
+ moving = FALSE
+ reset_turf = get_turf(source)
diff --git a/tff_modular/modules/antagonists/clock_cult/outfit.dm b/tff_modular/modules/antagonists/clock_cult/outfit.dm
new file mode 100644
index 00000000000..9c5f7c49776
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/outfit.dm
@@ -0,0 +1,60 @@
+/datum/outfit/clock
+ name = "Default Clock Cultist"
+
+ uniform = /obj/item/clothing/under/occult //meh.
+ suit = /obj/item/clothing/suit/clockwork/cloak
+ shoes = /obj/item/clothing/shoes/clockwork
+ gloves = /obj/item/clothing/gloves/clockwork
+ back = /obj/item/storage/backpack/satchel
+ backpack_contents = list(
+ /obj/item/storage/box/survival = 1,
+ /obj/item/stack/sheet/bronze = 10,
+ /obj/item/storage/medkit/emergency = 1,
+ /obj/item/clockwork/clockwork_slab = 1,
+ )
+
+/datum/outfit/clock/pre_equip(mob/living/carbon/human/equip_human, visualsOnly)
+ equip_human.add_faction(FACTION_CLOCK)
+
+
+/datum/outfit/clock/armor
+ name = "Armored Clock Cultist"
+
+ suit = /obj/item/clothing/suit/clockwork
+ head = /obj/item/clothing/head/helmet/clockwork
+ glasses = /obj/item/clothing/glasses/clockwork/judicial_visor
+ l_hand = /obj/item/clockwork/weapon/brass_battlehammer
+
+/datum/outfit/clock/archer
+ name = "Archer Clock Cultist"
+
+ suit = /obj/item/clothing/suit/clockwork/speed
+ head = /obj/item/clothing/head/helmet/clockwork
+ glasses = /obj/item/clothing/glasses/clockwork/judicial_visor
+ l_hand = /obj/item/gun/ballistic/bow/clockwork
+
+/datum/outfit/clock/support
+ name = "Support Clock Cultist"
+
+ suit = /obj/item/clothing/suit/clockwork
+ head = /obj/item/clothing/head/helmet/clockwork
+ glasses = /obj/item/clothing/glasses/clockwork/judicial_visor
+ belt = /obj/item/storage/belt/utility/clock
+ l_hand = /obj/item/clockwork/weapon/brass_sword
+ r_hand = /obj/item/clockwork/replica_fabricator
+ backpack_contents = list(
+ /obj/item/storage/box/survival = 1,
+ /obj/item/stack/sheet/bronze = 50,
+ /obj/item/storage/medkit/advanced = 1,
+ /obj/item/storage/medkit/regular = 1,
+ /obj/item/clockwork/clockwork_slab = 1,
+ )
+
+
+/datum/outfit/clockwork_armaments
+ name = "Clockwork Cultist Base"
+
+ suit = /obj/item/clothing/suit/clockwork
+ shoes = /obj/item/clothing/shoes/clockwork
+ gloves = /obj/item/clothing/gloves/clockwork
+ head = /obj/item/clothing/head/helmet/clockwork
diff --git a/tff_modular/modules/antagonists/clock_cult/pickup_element.dm b/tff_modular/modules/antagonists/clock_cult/pickup_element.dm
new file mode 100644
index 00000000000..8e732c1f115
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/pickup_element.dm
@@ -0,0 +1,56 @@
+#define REGULAR_PICKUP_MOD 1
+#define CULTIST_PICKUP_MOD 2
+#define PICKUP_SHOCK_DAMAGE 20
+
+/datum/element/clockwork_pickup
+ element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY
+ argument_hash_start_idx = 2
+
+ /// What slots will attempt to shock the equpper
+ var/list/equip_slots = list()
+
+/datum/element/clockwork_pickup/Attach(datum/target, list/slots_to_count)
+ . = ..()
+
+ if(!isitem(target))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, COMSIG_ITEM_EQUIPPED, PROC_REF(attempt_shock))
+
+ if(slots_to_count && !length(equip_slots))
+ equip_slots = slots_to_count
+
+ if(!locate(target.type) in GLOB.types_to_drop_on_clock_deonversion)
+ GLOB.types_to_drop_on_clock_deonversion |= target.type
+
+/datum/element/clockwork_pickup/Detach(datum/target)
+ . = ..()
+ UnregisterSignal(target, COMSIG_ITEM_EQUIPPED)
+
+/**
+ *
+ * This proc is called when the user picks or equips up an item with the associated element. This will shock them if they are not a clock cultist, and moreso if they are a blood cultist.
+ *
+ * Arguments:
+ * * source - The item being picked up
+ * * equipper - The mob that picked up the item
+ * * slot - The slot the item was equipped in, unused
+ */
+/datum/element/clockwork_pickup/proc/attempt_shock(obj/item/source, mob/living/equipper, slot)
+ SIGNAL_HANDLER
+
+ if(!isliving(equipper) || IS_CLOCK(equipper) || (length(equip_slots) && !(slot in equip_slots)))
+ return
+
+ var/power_multiplier = REGULAR_PICKUP_MOD
+ if(IS_CULTIST(equipper))
+ power_multiplier = CULTIST_PICKUP_MOD
+
+ to_chat(equipper, span_warning("As you [slot == ITEM_SLOT_HANDS ? "touch" : "equip"] [source], you feel a jolt course through you!"))
+
+ equipper.dropItemToGround(source, TRUE)
+ equipper.electrocute_act(PICKUP_SHOCK_DAMAGE * power_multiplier, src, 1, SHOCK_NOGLOVES|SHOCK_SUPPRESS_MESSAGE)
+
+#undef REGULAR_PICKUP_MOD
+#undef CULTIST_PICKUP_MOD
+#undef PICKUP_SHOCK_DAMAGE
diff --git a/tff_modular/modules/antagonists/clock_cult/portal.dm b/tff_modular/modules/antagonists/clock_cult/portal.dm
new file mode 100644
index 00000000000..83e10ab6ca6
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/portal.dm
@@ -0,0 +1,49 @@
+/obj/effect/portal/clockcult
+ name = "dimensional anomaly"
+ desc = "A dimensional anomaly. It feels warm to the touch, and has a gentle puff of steam emanating from it."
+ icon = 'icons/obj/anomaly.dmi'
+ icon_state = "bhole3"
+ mech_sized = TRUE
+ density = TRUE
+ force_teleport = TRUE
+ ///list of possible targets
+ var/static/list/possible_targets
+
+/obj/effect/portal/clockcult/Initialize(mapload, _creator, _lifespan, obj/effect/portal/_linked, automatic_link, turf/hard_target_override)
+ . = ..()
+ if(!possible_targets)
+ possible_targets = list()
+ for(var/obj/effect/landmark/late_cog_portals/portal_mark in GLOB.landmarks_list)
+ possible_targets += portal_mark
+
+ var/static/times_warned_admins //we spawn a massive amount of these normally so we dont want to warn admins for every single one if something breaks
+ if(length(possible_targets))
+ hard_target = get_turf(pick(possible_targets))
+ return
+ else if(!times_warned_admins)
+ times_warned_admins = 0
+ message_admins("No possible_targets for clock cult portals.")
+ times_warned_admins++
+
+/obj/effect/portal/clockcult/Bumped(atom/movable/bumper)
+ . = ..()
+ teleport(bumper)
+
+/obj/effect/portal/clockcult/teleport(atom/movable/M, force = FALSE)
+ if(isliving(M))
+ to_chat(M, span_notice("You begin climbing into the rift."))
+ if(!do_after(M, 5 SECONDS, src))
+ return
+
+ var/mob/living/teleported_living = M
+ if(teleported_living.pulling)
+ teleport(teleported_living.pulling, TRUE)
+
+ if(teleported_living.client)
+ var/client_color = teleported_living.client.color
+ teleported_living.client.color = "#BE8700"
+ animate(teleported_living.client, color = client_color, time = 2.5 SECONDS)
+ var/prev_alpha = M.alpha
+ M.alpha = 0
+ animate(M, alpha = prev_alpha, time = 1 SECONDS)
+ . = ..()
diff --git a/tff_modular/modules/antagonists/clock_cult/procs.dm b/tff_modular/modules/antagonists/clock_cult/procs.dm
new file mode 100644
index 00000000000..82b88bb17e0
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/procs.dm
@@ -0,0 +1,96 @@
+#define EDGE_STATE_SOUTH_BORDER 1
+#define EDGE_STATE_MAP_BOTTOM 2
+#define EDGE_STATE_MAP_TOP 3
+#define SET_DIR_LIST(dir_list, edge_state) \
+ switch(edge_state) { \
+ if(EDGE_STATE_MAP_BOTTOM) { \
+ ##dir_list = GLOB.cardinals - SOUTH;\
+ } \
+ if(EDGE_STATE_MAP_TOP) { \
+ ##dir_list = GLOB.cardinals - NORTH;\
+ } \
+ else { \
+ ##dir_list = GLOB.cardinals;\
+ } \
+ }
+
+#define ADD_NEW_AREAS(dir_list, step_turf, step_of, checked, added_to) \
+ for(var/dir in dir_list) { \
+ ##step_turf = get_step(step_of, dir);\
+ if(step_turf && step_turf.loc != checked) { \
+ ##added_to |= step_turf.loc;\
+ } \
+ }
+
+///Returns all turfs on the border of an area
+/proc/get_area_edge_turfs(area/checked, return_adjacent_areas = FALSE) as /list
+ RETURN_TYPE(/list)
+ var/list/returned_list = list()
+ for(var/i in 1 to length(checked.turfs_by_zlevel))
+ var/list/z_turfs = checked.turfs_by_zlevel[i]
+ var/list/new_list = list()
+ var/last_y = 0
+ var/edge_state = FALSE
+ var/turf/last_checked
+ returned_list.len++
+ returned_list[i] = new_list
+ for(var/turf/z_turf in z_turfs)
+ if(z_turf.y != last_y)
+ last_y = z_turf.y
+ if(last_checked)
+ if(return_adjacent_areas)
+ var/list/dir_list
+ SET_DIR_LIST(dir_list, edge_state)
+ var/turf/step_turf
+ ADD_NEW_AREAS(dir_list, step_turf, last_checked, checked, new_list)
+ else
+ new_list += last_checked
+
+ if(z_turf.y == 1)
+ edge_state = EDGE_STATE_MAP_BOTTOM
+ else if(last_y == 0)
+ edge_state = EDGE_STATE_SOUTH_BORDER
+ else if(z_turf.y == world.maxy)
+ edge_state = EDGE_STATE_MAP_TOP
+ else
+ edge_state = FALSE
+
+ if(return_adjacent_areas)
+ var/list/dir_list
+ SET_DIR_LIST(dir_list, edge_state)
+ var/turf/step_turf
+ ADD_NEW_AREAS(dir_list, step_turf, z_turf, checked, new_list)
+ else
+ new_list += z_turf
+ last_checked = null
+ continue
+
+ if(edge_state)
+ if(return_adjacent_areas)
+ var/list/dir_list
+ SET_DIR_LIST(dir_list, edge_state)
+ var/turf/step_turf
+ ADD_NEW_AREAS(dir_list, step_turf, z_turf, checked, new_list)
+ else
+ new_list += z_turf
+ continue
+
+ var/turf/north_turf = get_step(z_turf, NORTH)
+ if(north_turf.loc != checked) //if we dont have a step something else already broke as map borders have already been handled
+ if(return_adjacent_areas)
+ var/list/dir_list = GLOB.cardinals - NORTH
+ if(edge_state == EDGE_STATE_MAP_BOTTOM)
+ dir_list -= SOUTH
+ var/turf/step_turf
+ ADD_NEW_AREAS(dir_list, step_turf, z_turf, checked, new_list)
+ new_list |= (return_adjacent_areas ? north_turf.loc : z_turf)
+ last_checked = null
+ else
+ last_checked = z_turf
+ return returned_list
+
+#undef EDGE_STATE_SOUTH_BORDER
+#undef EDGE_STATE_MAP_BOTTOM
+#undef EDGE_STATE_MAP_TOP
+#undef SET_DIR_LIST
+#undef ADD_NEW_AREAS
diff --git a/tff_modular/modules/antagonists/clock_cult/ratvar.dm b/tff_modular/modules/antagonists/clock_cult/ratvar.dm
new file mode 100644
index 00000000000..1844360a2c6
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/ratvar.dm
@@ -0,0 +1,252 @@
+//I would like to do what beestation does and make both this and narsie be children of /eldritch but that would make this very non-modular
+GLOBAL_DATUM(cult_ratvar, /obj/ratvar)
+
+#define RATVAR_CONSUME_RANGE 20
+#define RATVAR_GRAV_PULL 10
+#define RATVAR_SINGULARITY_SIZE 11
+
+/obj/ratvar
+ name = "ratvar, the Clockwork Justicar"
+ desc = "Oh, that's ratvar!"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/512x512.dmi'
+ icon_state = "ratvar"
+ anchored = TRUE
+ density = FALSE
+ appearance_flags = LONG_GLIDE
+ plane = MASSIVE_OBJ_PLANE
+ light_color = COLOR_ORANGE
+ light_power = 1 //slightly brighter then narsie
+ light_range = 20
+ move_resist = INFINITY
+ obj_flags = CAN_BE_HIT | DANGEROUS_POSSESSION
+ pixel_x = -236
+ pixel_y = -256
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
+ flags_1 = SUPERMATTER_IGNORES_1
+
+ /// The singularity component to move around Ratvar.
+ /// A weak ref in case an admin removes the component to preserve the functionality.
+ var/datum/weakref/singularity
+
+ ///next world tick we can attack our narsie target if we have one
+ var/next_attack_tick = 0
+
+/obj/ratvar/Initialize(mapload)
+ SSpoints_of_interest.make_point_of_interest(src)
+
+ singularity = WEAKREF(AddComponent(
+ /datum/component/singularity, \
+ bsa_targetable = FALSE, \
+ consume_callback = CALLBACK(src, PROC_REF(consume)), \
+ consume_range = RATVAR_CONSUME_RANGE, \
+ disregard_failed_movements = TRUE, \
+ grav_pull = RATVAR_GRAV_PULL, \
+ roaming = TRUE, \
+ singularity_size = RATVAR_SINGULARITY_SIZE, \
+ ))
+
+ log_game("!!! RATVAR HAS RISEN. !!!")
+ GLOB.cult_ratvar = src
+ . = ..()
+ desc = "[text2ratvar("That's Ratvar, the Clockwork Justicar. The great one has risen.")]"
+ sound_to_playing_players('tff_modular/modules/antagonists/clock_cult/sound/ratvar_reveal.ogg', 100)
+ send_to_playing_players(span_reallybig(span_clockyellow("The bluespace veil gives way to Ratvar, his light shall shine upon all mortals!")))
+ UnregisterSignal(src, COMSIG_ATOM_BSA_BEAM)
+ SSshuttle.registerHostileEnvironment(src)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(clockcult_ending_start)), 5 SECONDS)
+ if(GLOB.narsie_breaching_rune)
+ if(istype(GLOB.narsie_breaching_rune, /obj/effect/rune/narsie))
+ new /obj/narsie(get_turf(GLOB.narsie_breaching_rune))
+ else
+ new /obj/narsie(get_safe_random_station_turf())
+
+ var/area/area = get_area(src)
+ if(area)
+ var/mutable_appearance/alert_overlay = mutable_appearance('tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi', "ratvar_alert")
+ notify_ghosts(
+ "Ratvar has risen in [area]. Reach out to the Justicar to be given a new shell for your soul.",
+ source = src,
+ alert_overlay = alert_overlay,
+ )
+ gods_battle()
+ START_PROCESSING(SSobj, src)
+
+/obj/ratvar/Destroy(force)
+ if(GLOB.cult_ratvar == src)
+ GLOB.cult_ratvar = null
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/ratvar/process(seconds_per_tick)
+ var/datum/component/singularity/singularity_component = singularity?.resolve()
+ if(GLOB.cult_narsie)
+ singularity_component?.target = GLOB.cult_narsie
+ if(get_dist(src, GLOB.cult_narsie) < 5)
+ if(next_attack_tick < world.time)
+ next_attack_tick = world.time + rand(50, 100)
+ send_to_playing_players(span_danger("[pick("Reality shudders around you.","You hear the tearing of flesh.","The sound of bones cracking fills the air.")]"))
+ sound_to_playing_players('sound/effects/magic/clockwork/ratvar_attack.ogg',100)
+ explosion(GLOB.cult_narsie, 0, 2, 6)
+ SpinAnimation(4, 0)
+
+ for(var/mob/living/living_player in GLOB.player_list)
+ shake_camera(living_player, 2.5 SECONDS, 5)
+ living_player.Knockdown(1 SECONDS)
+
+ if(prob(max(length(GLOB.main_clock_cult?.members)/2, 15)))
+ sound_to_playing_players('sound/effects/magic/demon_dies.ogg', 100)
+ qdel(GLOB.cult_narsie)
+ send_to_playing_players(span_clockyellow("You were a fool for underestimating me..."))
+ for(var/datum/mind/cultist_mind in get_antag_minds(/datum/antagonist/cult))
+ to_chat(cultist_mind, span_userdanger("You feel a stabbing pain in your chest... This can't be happening!"))
+ cultist_mind.current?.dust()
+ return
+
+/obj/ratvar/Bump(atom/the_atom)
+ var/turf/the_turf = get_turf(the_atom)
+ if(the_turf == loc)
+ the_turf = get_step(the_atom, the_atom.dir) //please don't slam into a window like a bird, Ratvar
+ forceMove(the_turf)
+
+/obj/ratvar/attack_ghost(mob/user)
+ . = ..()
+ if(is_banned_from(user.ckey, list(ROLE_MIDROUND_CLOCK_CULTIST)))
+ return
+ var/mob/living/basic/drone/created_drone = new /mob/living/basic/drone/cogscarab(get_turf(src))
+ created_drone.flags_1 |= (flags_1 & ADMIN_SPAWNED_1)
+ if(user.mind)
+ user.mind.transfer_to(created_drone, TRUE)
+ else if(isobserver(user))
+ created_drone.PossessByPlayer(user.key)
+ created_drone.mind_initialize()
+ else
+ qdel(created_drone)
+ return
+ created_drone.mind.add_antag_datum(/datum/antagonist/clock_cultist)
+
+/obj/ratvar/proc/consume(atom/consumed)
+ consumed.ratvar_act()
+
+#undef RATVAR_CONSUME_RANGE
+#undef RATVAR_GRAV_PULL
+#undef RATVAR_SINGULARITY_SIZE
+
+/obj/narsie
+ ///next world tick we can attack our ratvar target if we have one
+ var/next_attack_tick = 0
+
+/proc/clockcult_ending_start()
+ SSsecurity_level.set_level(SEC_LEVEL_LAMBDA)
+ priority_announce("Huge gravitational-energy spike detected emminating from a neutron star [text2ratvar("THEY LIE")] near your sector. Event has been determined to be \
+ survivable by 0% of life. ESTIMATED TIME UNTIL ENERGY PULSE REACHES [GLOB.station_name]: 56 SECONDS. Godspeed crew, glory to Nanotrasen. \
+ -Admiral W[text2ratvar("orthless")].", \
+ "Central Command Anomolous Materials Division", 'sound/announcer/alarm/airraid.ogg')
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(clockcult_pre_ending)), 50 SECONDS)
+
+/proc/clockcult_pre_ending()
+ priority_announce("Station [GLOB.station_name] is in the wa#e %o[text2ratvar("YOU WILL SEE THE LIGHT")] action imminent. Glory[text2ratvar(" TO ENGINE")].", \
+ "Central Command Anomolous Materials Division", 'sound/announcer/alarm/nuke_alarm.ogg')
+ for(var/mob/player_mob in GLOB.player_list)
+ if(player_mob.client)
+ player_mob.client.color = COLOR_WHITE
+ animate(player_mob.client, color = LIGHT_COLOR_CLOCKWORK, time = 135)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(clockcult_final_ending)), 135)
+
+/proc/clockcult_final_ending()
+ SSshuttle.lockdown = TRUE
+ for(var/mob/player_mob in GLOB.player_list)
+ player_mob.client.color = LIGHT_COLOR_CLOCKWORK
+ animate(player_mob.client, color = COLOR_WHITE, time = 5)
+ SEND_SOUND(player_mob, sound(null))
+ SEND_SOUND(player_mob, sound('sound/effects/magic/fireball.ogg'))
+
+ for(var/mob/living/lit_mob in GLOB.mob_living_list)
+ if(!IS_CLOCK(lit_mob))
+ lit_mob.fire_stacks = 100
+ lit_mob.ignite_mob()
+ lit_mob.emote("scream")
+ sleep(1.5 SECONDS)
+ SSticker.force_ending = TRUE
+
+/datum/client_colour/ratvar_vision
+ color = LIGHT_COLOR_CLOCKWORK
+
+//ratvar_act stuff
+
+/atom/proc/ratvar_act()
+ SEND_SIGNAL(src, COMSIG_ATOM_RATVAR_ACT)
+
+/obj/structure/lattice/ratvar_act()
+ var/our_loc = loc
+ qdel(src)
+ new /obj/structure/lattice/clockwork(our_loc)
+
+/obj/item/stack/sheet/iron/ratvar_act()
+ new /obj/item/stack/sheet/bronze(loc, amount)
+ qdel(src)
+
+/obj/item/stack/sheet/runed_metal/ratvar_act()
+ new /obj/item/stack/sheet/bronze(loc, amount)
+ qdel(src)
+
+/turf/ratvar_act(force, ignore_mobs)
+ . = (prob(60) || force)
+ for(var/atom/checked_atom in src)
+ if(ignore_mobs && ismob(checked_atom))
+ continue
+ if(ismob(checked_atom) || .)
+ checked_atom.ratvar_act()
+
+/turf/open/floor/ratvar_act(force, ignore_mobs)
+ . = ..()
+ if(.)
+ ChangeTurf(/turf/open/indestructible/reebe_flooring, flags = CHANGETURF_INHERIT_AIR)
+
+/turf/closed/wall/ratvar_act(force, ignore_mobs)
+ . = ..()
+ if(.)
+ ChangeTurf(/turf/closed/wall/clockwork)
+
+/obj/structure/chair/ratvar_act()
+ new /obj/structure/chair/bronze(get_turf(src))
+ qdel(src)
+
+/obj/structure/chair/bronze/ratvar_act()
+ return
+
+/obj/structure/window/ratvar_act()
+ if(!fulltile)
+ new/obj/structure/window/reinforced/clockwork(get_turf(src), dir)
+ else
+ new/obj/structure/window/reinforced/clockwork/fulltile(get_turf(src))
+ qdel(src)
+
+/obj/structure/table/ratvar_act()
+ var/atom/location = loc
+ qdel(src)
+ new /obj/structure/table/bronze(location)
+
+/obj/structure/table/bronze/ratvar_act()
+ return
+
+/obj/machinery/door/airlock/ratvar_act() //Airlocks become clock airlocks that only allow servants
+ var/obj/machinery/door/airlock/bronze/clock/made_door
+ if(glass)
+ made_door = new/obj/machinery/door/airlock/bronze/clock/glass(get_turf(src))
+ else
+ made_door = new/obj/machinery/door/airlock/bronze/clock(get_turf(src))
+ made_door.name = name
+ qdel(src)
+
+/obj/machinery/computer
+ ///used for tracking ratvar_act() and narsie_act()
+ var/clockwork = FALSE
+
+/obj/machinery/computer/ratvar_act()
+ if(!clockwork)
+ clockwork = TRUE
+ icon_screen = "ratvar[rand(1, 3)]"
+ icon_keyboard = "ratvar_key[rand(1, 2)]"
+ icon_state = "ratvarcomputer1"
+ update_appearance()
+ connectable = FALSE
diff --git a/tff_modular/modules/antagonists/clock_cult/reebe_modules.dm b/tff_modular/modules/antagonists/clock_cult/reebe_modules.dm
new file mode 100644
index 00000000000..53e1c94ea3a
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/reebe_modules.dm
@@ -0,0 +1,107 @@
+GLOBAL_LIST_EMPTY(abscond_markers)
+
+/// spawn the reebe z level and map template, lazy templates dont work because we need to give this ztraits
+/proc/spawn_reebe(forced = FALSE)
+ if(!SSthe_ark.initialized)
+ SSthe_ark.Initialize()
+
+ var/static/reebe_loaded
+ if(forced)
+ message_admins("Admin forcing reebe spawn, if it has already spawned this will break things unless you know what your doing.")
+ else if(reebe_loaded)
+ return FALSE
+
+ reebe_loaded = TRUE
+ var/datum/space_level/reebe_z = SSmapping.add_new_zlevel("Reebe", ZTRAITS_REEBE)
+ if(!reebe_z)
+ reebe_loaded = FALSE
+ CRASH("Failed to create the Reebe Z level.")
+
+ SSmapping.initialize_reserved_level(reebe_z.z_value)
+ if(!SSmapping.reservation_ready["[reebe_z.z_value]"]) //if this is not true then the block reservation will sleep forever
+ reebe_loaded = FALSE
+ CRASH("Reebe Z level not in SSmapping.reservation_ready.")
+
+ var/datum/turf_reservation/reservation = SSmapping.request_turf_block_reservation(101, 101, z_reservation = reebe_z.z_value)
+ if(!reservation)
+ reebe_loaded = FALSE
+ CRASH("Failed to reserve a block for Reebe.")
+
+ var/datum/map_template/reebe_template = new(path = REEBE_MAP_PATH, cache = TRUE)
+ if(!reebe_template.cached_map) //might not be needed, im just copying lazy template code and I cant figure out what cached maps are for in this case
+ reebe_loaded = FALSE
+ CRASH("Failed to cache template for loading Reebe.")
+
+ if(!reebe_template.load(reservation.bottom_left_turfs[1]))
+ reebe_loaded = FALSE
+ CRASH("Failed to load the Reebe template.")
+
+ for(var/area/reebe_area as anything in typesof(/area/ruin/powered/reebe))
+ reebe_area = GLOB.areas_by_type[reebe_area]
+ if(reebe_area)
+ SSthe_ark.reebe_areas[reebe_area] = 1
+ return TRUE
+
+/obj/item/storage/box/recharger_parts
+ name = "Recharger Parts"
+
+/obj/item/storage/box/recharger_parts/PopulateContents()
+ . = ..() //there is actually a helper for this but I cant remember the name
+ var/list/spawned_list = list(/obj/item/circuitboard/machine/recharger = 5, /obj/item/stack/cable_coil = 1, /obj/item/stack/sheet/iron/fifty = 1)
+ for(var/type in spawned_list)
+ for(var/i in 1 to spawned_list[type])
+ new type(src)
+
+/obj/effect/mob_spawn/corpse/human/blood_cultist
+ name = "Blood Cultist"
+ outfit = /datum/outfit/blood_cultist
+
+/datum/outfit/blood_cultist
+ name = "Blood Cultist"
+
+ uniform = /obj/item/clothing/under/color/black
+ suit = /obj/item/clothing/suit/hooded/cultrobes/alt
+ shoes = /obj/item/clothing/shoes/cult/alt
+
+/datum/outfit/blood_cultist/post_equip(mob/living/carbon/human/equipped, visualsOnly)
+ equipped.eye_color_left = BLOODCULT_EYE
+ equipped.eye_color_right = BLOODCULT_EYE
+ equipped.update_body()
+
+/obj/effect/mob_spawn/corpse/human/clock_cultist
+ name = "Clock Cultist"
+ outfit = /datum/outfit/clock
+
+/obj/effect/landmark/late_cog_portals
+ name = "reebe crew portal spawn"
+
+//for the portal from the outpost to reebe
+/obj/effect/landmark/abscond_marker
+ name = "abscond marker"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/effects/landmarks_static.dmi'
+ icon_state = "clockwork_orange"
+
+/obj/effect/landmark/abscond_marker/Initialize(mapload)
+ . = ..()
+ GLOB.abscond_markers += src
+
+/obj/effect/landmark/abscond_marker/Destroy()
+ . = ..()
+ GLOB.abscond_markers -= src
+
+/obj/effect/servant_blocker
+ name = "servant Blocker"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi'
+ icon_state = "servant_blocker"
+ anchored = TRUE
+
+/obj/effect/servant_blocker/CanPass(atom/movable/mover, border_dir)
+ for(var/mob/held_mob in mover.get_all_contents())
+ if(IS_CLOCK(held_mob))
+ return FALSE
+ return ..()
+
+/obj/effect/spawner/structure/window/clockwork
+ name = "brass window spawner"
+ icon_state = "bronzewindow_spawner"
+ spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/clockwork/fulltile)
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/_scripture.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/_scripture.dm
new file mode 100644
index 00000000000..3fedfd164be
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/_scripture.dm
@@ -0,0 +1,396 @@
+GLOBAL_LIST_EMPTY(clock_scriptures)
+GLOBAL_LIST_EMPTY(clock_scriptures_by_type)
+
+// Scriptures are the "spells" of clock cultists
+// They're usable through their clockwork slab, and cannot be invoked otherwise
+/datum/scripture
+ /// Name of the scripture
+ var/name = ""
+ /// Shown decription of the scripture in the UI
+ var/desc = ""
+ /// Tooltip shown on-hover. Keep to a few words
+ var/tip = ""
+ /// How much power this scripture costs to use
+ var/power_cost = 0
+ /// How much vitality this scripture costs to use
+ var/vitality_cost = 0
+ /// How many cogs are required to be used to use this
+ var/cogs_required = 0
+ /// Time required to invoke this while standing still
+ var/invocation_time = 0
+ /// Text said during invocation, automatically translates to Ratvarian
+ var/list/invocation_text = list()
+ /// Icon state of the action button
+ var/button_icon_state = "telerune"
+ /// How many people need to invoke this in sight of each other to use
+ var/invokers_required = 1
+ /// What category of scripture is this
+ var/category = SPELLTYPE_ABSTRACT
+ /// Only set to false if you call end_invoke somewhere in your scripture
+ var/end_on_invocation = TRUE
+ /// How much of a reduction in invocation time should the TRAIT_FASTER_SLAB_INVOKE give, multiplicative
+ var/fast_invoke_mult = 0.5
+ /// Are we only visible/usable if a unique condition is met
+ var/unique_locked = FALSE //if needed it might be worth turning these into descriptor strings
+ /// Ref to the mob invoking this
+ var/mob/living/invoker
+ /// Ref to the slab invoking this
+ var/obj/item/clockwork/clockwork_slab/invoking_slab
+ /// Timer object for the distance between invoking chants
+ var/invocation_chant_timer = null
+ /// Sound to play on finish
+ var/sound/recital_sound = null
+
+/datum/scripture/New()
+ . = ..()
+ if(invokers_required > 1)
+ desc += " Requires [invokers_required] invokers, should you be in a group."
+
+/datum/scripture/Destroy(force)
+ invoker = null
+ invoking_slab = null
+ return ..()
+
+
+/// Invoke this scripture, checking if there's valid power and vitality
+/datum/scripture/proc/invoke()
+ if(SSthe_ark.clock_power < power_cost || GLOB.clock_vitality < vitality_cost)
+ invoke_fail()
+
+ if(invocation_chant_timer)
+ deltimer(invocation_chant_timer)
+ invocation_chant_timer = null
+
+ end_invoke()
+
+ return
+
+ SSthe_ark.clock_power -= power_cost
+ GLOB.clock_vitality -= vitality_cost
+ invoke_success()
+
+/// On success of invoking the scripture
+/datum/scripture/proc/invoke_success()
+ return TRUE
+
+/// On failure of invoking the scripture
+/datum/scripture/proc/invoke_fail()
+ return TRUE
+
+/// The overall reciting proc for saying every single line for a scripture
+/datum/scripture/proc/recital(input_invoke_time)
+ if(!length(invocation_text))
+ return
+
+ var/steps = length(invocation_text)
+ var/true_invocation_time = input_invoke_time || get_true_invocation_time()
+ var/time_between_say = true_invocation_time / (steps + 1)
+
+ if(invocation_chant_timer)
+ deltimer(invocation_chant_timer)
+ invocation_chant_timer = null
+
+ recite(1, time_between_say, steps)
+
+/datum/scripture/proc/get_true_invocation_time()
+ . = invocation_time * (HAS_TRAIT(invoker, TRAIT_FASTER_SLAB_INVOKE) ? fast_invoke_mult : 1)
+ return .
+
+/// For reciting an individual line of a scripture
+/datum/scripture/proc/recite(text_point, wait_time, stop_at = 0)
+ if(QDELETED(src))
+ return
+
+ invocation_chant_timer = null
+
+ if(!invoking_slab || !invoking_slab.invoking_scripture)
+ return
+
+ var/invokers_left = invokers_required
+ if(invokers_left > 1)
+ for(var/mob/living/potential_invoker in viewers(invoker))
+ if(!invokers_left)
+ break
+
+ if(potential_invoker.stat || !potential_invoker.mind)
+ continue
+
+ if(potential_invoker?.mind.has_antag_datum(/datum/antagonist/clock_cultist/solo)) // Solo cultists can use all scriptures alone, while group clock cult doesn't get so lucky
+ invokers_left = 0
+ clockwork_say(potential_invoker, text2ratvar(invocation_text[text_point]), TRUE)
+ break
+ if(IS_CLOCK(potential_invoker))
+ clockwork_say(potential_invoker, text2ratvar(invocation_text[text_point]), TRUE)
+ invokers_left--
+ else
+ clockwork_say(invoker, text2ratvar(invocation_text[text_point]), TRUE)
+
+ if(recital_sound)
+ SEND_SOUND(invoker, recital_sound)
+
+ if(text_point < stop_at)
+ invocation_chant_timer = addtimer(CALLBACK(src, PROC_REF(recite), text_point+1, wait_time, stop_at), wait_time, TIMER_STOPPABLE)
+
+
+/// Check for any special requriements such as not having enough invokers, or not holding the slab
+/datum/scripture/proc/check_special_requirements(mob/user)
+ if(!invoker || !invoking_slab)
+ message_admins("No invoker for [name]")
+ return FALSE
+
+ if(invoker.get_active_held_item() != invoking_slab && !iscyborg(invoker))
+ to_chat(invoker, span_brass("You fail to invoke [name]."))
+ return FALSE
+
+ if(HAS_TRAIT(invoker, TRAIT_NO_SLAB_INVOKE))
+ to_chat(invoker, span_warning("Something blocks you from invoking scriptures."))
+ return FALSE
+
+ var/invokers = 0
+ if(locate(/obj/item/toy/plush/ratplush) in range(1, invoker)) //ratvar plushies count as an invoker
+ invokers++
+
+ for(var/mob/living/potential_invoker in viewers(invoker))
+ if(potential_invoker.stat || !potential_invoker.mind)
+ continue
+
+ if(IS_CLOCK(potential_invoker))
+ invokers++
+
+ if(potential_invoker?.mind.has_antag_datum(/datum/antagonist/clock_cultist/solo)) // They count for infinite so they can do all scriptures solo
+ invokers = INFINITY
+ break
+
+ if(invokers < invokers_required)
+ to_chat(invoker, span_brass("You need [invokers_required] servants to channel [name]!"))
+ return FALSE
+
+ if(invoker.reagents && invoker.has_reagent(/datum/reagent/water/holywater))
+ to_chat(invoker, span_brass("The holy water inside you is blocking your ability to invoke!"))
+ return FALSE
+
+ return TRUE
+
+
+/// Start invoking a scripture, calling end_invoke() if it doesn't finish
+/datum/scripture/proc/begin_invoke(mob/living/invoking_mob, obj/item/clockwork/clockwork_slab/slab, bypass_unlock_checks = FALSE)
+ if(invoking_mob.get_active_held_item() != slab && !iscyborg(invoking_mob))
+ to_chat(invoking_mob, span_brass("You need to have the [slab.name] in your active hand to recite scriptures."))
+ return
+
+ slab.invoking_scripture = src
+ invoker = invoking_mob
+ invoking_slab = slab
+
+ if((!slab.owned_scriptures[type] && !bypass_unlock_checks) || unique_locked) //unique_locked scriptures should not even be visible so this should never happen
+ log_runtime("CLOCKCULT: Attempting to invoke a scripture that has not been unlocked. Either there is a bug, or [ADMIN_LOOKUP(invoker)] is using some wacky exploits.")
+ end_invoke()
+ return
+
+ if(!check_special_requirements(invoking_mob))
+ end_invoke()
+ return
+
+ var/true_invocation_time = get_true_invocation_time()
+ recital(true_invocation_time)
+ if(do_after(invoking_mob, true_invocation_time, invoking_mob, extra_checks = CALLBACK(src, PROC_REF(check_special_requirements), invoking_mob), hidden = TRUE))
+ invoke()
+
+ to_chat(invoking_mob, span_brass("You invoke [name]."))
+
+ if(end_on_invocation)
+ end_invoke()
+ else
+ invoke_fail()
+
+ if(invocation_chant_timer)
+ deltimer(invocation_chant_timer)
+ invocation_chant_timer = null
+
+ end_invoke()
+
+/// End the invoking, nulling things out
+/datum/scripture/proc/end_invoke()
+ invoking_slab.invoking_scripture = null
+
+// Call these on the instances in the global lists
+/// Set a scripture's unique_locked to FALSE and reload the UIs of slabs if set
+/datum/scripture/proc/unique_unlock(reload_uis = FALSE)
+ unique_locked = FALSE
+ if(reload_uis)
+ for(var/obj/item/clockwork/clockwork_slab/slab in GLOB.clockwork_slabs)
+ SStgui.update_uis(slab)
+
+
+/// Set a scripture's unique_locked to TRUE, remove quickbinds of it, and reload the UIs of slabs if set
+/datum/scripture/proc/unique_lock(reload_uis = FALSE)
+ unique_locked = TRUE
+ for(var/obj/item/clockwork/clockwork_slab/slab in GLOB.clockwork_slabs)
+ for(var/i in 1 to slab.quick_bound_scriptures.len)
+ if(slab.quick_bound_scriptures[i])
+ var/datum/action/innate/clockcult/quick_bind/quickbound = slab.quick_bound_scriptures[i]
+ if(istype(src, quickbound.scripture.type))
+ slab.quick_bound_scriptures[i] = null
+ qdel(quickbound)
+ break
+
+ if(reload_uis)
+ SStgui.update_uis(slab)
+
+
+// Base create structure scripture
+/datum/scripture/create_structure
+ ///Typepath for the structure to create
+ var/summoned_structure
+ ///How long is our creation time multiplied by if the assault has begun
+ var/assault_invoke_time_mult = 2
+
+
+/datum/scripture/create_structure/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ for(var/obj/structure/destructible/clockwork/clockwork_struct in get_turf(invoker))
+ if(istype(clockwork_struct, /obj/structure/destructible/clockwork/trap))
+ continue
+ invoker.balloon_alert(invoker, "structure already on tile!")
+ return FALSE
+
+ return TRUE
+
+/datum/scripture/create_structure/get_true_invocation_time()
+ . = ..()
+ if(GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE)
+ . *= (iscogscarab(invoker) ? assault_invoke_time_mult : assault_invoke_time_mult * 2)
+
+/datum/scripture/create_structure/invoke_success()
+ return new summoned_structure(get_turf(invoker))
+
+//For scriptures that charge the slab, and the slab will affect something
+//(stunning etc.)
+/datum/scripture/slab
+ name = "Charge Slab"
+ end_on_invocation = FALSE
+ /// Time to perform this
+ var/use_time = 1 SECONDS
+ /// Overlay for the item/inhand state while this is invoked
+ var/slab_overlay = "volt"
+ /// Progressbar datum for count_down()
+ var/datum/progressbar/progress
+ /// How many times this scripture can be used overall, is unchanging
+ var/uses = 1
+ /// Text displayed after use
+ var/after_use_text = ""
+ /// Internal spell for pointed/aimed spells
+ var/datum/action/cooldown/spell/pointed/slab/pointed_spell
+ /// How many times this can be used this particular invocation, can go down
+ var/uses_left = 0
+ /// How much time left to use this
+ var/time_left = 0
+ /// ID of the loop timer
+ var/loop_timer_id
+
+/datum/scripture/slab/New()
+ . = ..()
+ pointed_spell = new(src)
+ pointed_spell.name = src.name
+ pointed_spell.deactive_msg = ""
+ pointed_spell.parent_scripture = src
+
+/datum/scripture/slab/Destroy()
+ if(!QDELETED(progress))
+ progress.end_progress()
+
+ if(!QDELETED(pointed_spell))
+ QDEL_NULL(pointed_spell)
+
+ return ..()
+
+/datum/scripture/slab/invoke()
+ progress = new(invoker, use_time, invoking_slab)
+ uses_left = uses
+ time_left = use_time
+ invoking_slab.charge_overlay = slab_overlay
+ invoking_slab.update_overlays()
+ invoking_slab.active_scripture = src
+ pointed_spell.set_click_ability(invoker)
+ count_down()
+ SSthe_ark.clock_power -= power_cost
+ GLOB.clock_vitality -= vitality_cost
+ invoke_success()
+
+/// Count down the progress bar
+/datum/scripture/slab/proc/count_down()
+ if(QDELETED(src))
+ return
+
+ progress.update(time_left)
+ time_left--
+ loop_timer_id = null
+
+ if(time_left > 0)
+ loop_timer_id = addtimer(CALLBACK(src, PROC_REF(count_down)), 0.1 SECONDS, TIMER_STOPPABLE)
+ else
+ end_invocation()
+
+/// What occurs when an atom is clicked on.
+/datum/scripture/slab/proc/click_on(atom/clicked_atom)
+ SHOULD_CALL_PARENT(TRUE)
+
+ if(!invoker.can_interact_with(clicked_atom))
+ return
+
+ if(!apply_effects(clicked_atom))
+ return
+
+ uses_left--
+ if(uses_left)
+ return
+
+ if(after_use_text)
+ clockwork_say(invoker, text2ratvar(after_use_text), TRUE)
+
+ end_invocation(TRUE)
+
+/// What occurs when the invocation ends
+/datum/scripture/slab/proc/end_invocation(silent = FALSE)
+ SHOULD_CALL_PARENT(TRUE)
+
+ //Remove the timer if there is one currently active
+ if(loop_timer_id)
+ deltimer(loop_timer_id)
+ loop_timer_id = null
+
+ if(!silent)
+ to_chat(invoker, span_brass("You are no longer invoking [name]."))
+ progress.end_progress()
+
+ pointed_spell.unset_click_ability(invoker)
+ invoking_slab.charge_overlay = null
+ invoking_slab.update_icon()
+ invoking_slab.active_scripture = null
+
+ end_invoke()
+
+/// Apply the effects of a scripture to an atom
+/datum/scripture/slab/proc/apply_effects(atom/applied_atom)
+ return TRUE
+
+/datum/action/cooldown/spell/pointed/slab
+ /// The scripture datum that this spell is referring to
+ var/datum/scripture/slab/parent_scripture
+
+/datum/action/cooldown/spell/pointed/slab/Destroy()
+ parent_scripture = null
+ return ..()
+
+/datum/action/cooldown/spell/pointed/slab/InterceptClickOn(mob/living/clicker, params, atom/target)
+ parent_scripture?.click_on(target)
+
+/// Generate all scriptures in a global assoc of name:ref. Only needs to be done once
+/proc/generate_clockcult_scriptures()
+ for(var/categorypath in subtypesof(/datum/scripture))
+ var/datum/scripture/clock_script = new categorypath
+ GLOB.clock_scriptures += clock_script
+ GLOB.clock_scriptures_by_type[clock_script.type] = clock_script
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/clockwork_armaments.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/clockwork_armaments.dm
new file mode 100644
index 00000000000..771c6fdd321
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/clockwork_armaments.dm
@@ -0,0 +1,40 @@
+/datum/scripture/clockwork_armaments
+ name = "Clockwork Armaments"
+ desc = "Summon clockwork armor and weapons, to be ready for battle."
+ tip = "Summon clockwork armor and weapons, to be ready for battle."
+ button_icon_state = "clockwork_armor"
+ power_cost = STANDARD_CELL_CHARGE * 0.25
+ invocation_time = 2 SECONDS
+ invocation_text = list("Through courage and hope...", "we shall protect thee!")
+ category = SPELLTYPE_PRESERVATION
+ cogs_required = 1
+
+
+/datum/scripture/clockwork_armaments/invoke_success()
+ var/choice = tgui_input_list(invoker, "What weapon do you want to call upon?", "Clockwork Armaments", list("Brass Spear", "Brass Battlehammer", "Brass Sword"))
+
+ if(!choice)
+ return FALSE
+
+ var/static/datum/outfit/clockwork_armaments/base_outfit
+ if(!base_outfit)
+ base_outfit = new
+
+ var/weapon_path = /obj/item/clockwork/weapon/brass_battlehammer
+ var/say_the_line = "I've gotten me mallet!"
+
+ switch(choice)
+ if("Brass Spear")
+ weapon_path = /obj/item/clockwork/weapon/brass_spear
+ say_the_line = "My will shall pierce my foes!"
+ if("Brass Battlehammer")
+ weapon_path = /obj/item/clockwork/weapon/brass_battlehammer
+ say_the_line = "I've gotten me mallet!"
+ if("Brass Sword")
+ weapon_path = /obj/item/clockwork/weapon/brass_sword
+ say_the_line = "Let us cut them to pieces!"
+
+ base_outfit.equip(invoker)
+
+ invoker.put_in_hands(new weapon_path, FALSE)
+ clockwork_say(invoker, text2ratvar(say_the_line), FALSE)
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/dimensional_breach.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/dimensional_breach.dm
new file mode 100644
index 00000000000..282a74e82d0
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/dimensional_breach.dm
@@ -0,0 +1,39 @@
+/datum/scripture/ark_activation
+ name = "Ark Invigoration"
+ desc = "Prepares the Ark for activation, alerting the crew of your existence."
+ tip = "Prepares the Ark for activation, alerting the crew of your existence."
+ button_icon_state = "Spatial Gateway"
+ power_cost = STANDARD_CELL_CHARGE * 1.5
+ invocation_time = 15 SECONDS
+ invocation_text = list("Brightest Engine, take my soul...", "To complete our greatest goal...", "through the rifts you now shall come...", "to show them where the light is from!")
+ invokers_required = 6
+ category = SPELLTYPE_PRESERVATION
+ recital_sound = 'sound/effects/magic/clockwork/narsie_attack.ogg' //ironic
+ fast_invoke_mult = 1
+ cogs_required = 5
+
+/datum/scripture/ark_activation/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(!on_reebe(invoker))
+ to_chat(invoker, span_brass("You need to be near the gateway to channel its energy!"))
+ return FALSE
+
+ if(!GLOB.clock_ark)
+ to_chat(invoker, span_userdanger("No ark located, contact the admins with an ahelp(f1)."))
+ return FALSE
+
+ if(SSthe_ark.charged_anchoring_crystals < ANCHORING_CRYSTALS_TO_SUMMON)
+ to_chat(invoker, span_brass("Reebe is not yet anchored enough to this realm, the ark cannot open until enough anchoring crystals are summoned and protected."))
+ return FALSE
+
+ return TRUE
+
+/datum/scripture/ark_activation/invoke_success()
+ if(!GLOB.clock_ark)
+ to_chat(invoker, span_userdanger("No ark located, contact the admins with an ahelp(f1)."))
+ return FALSE
+
+ GLOB.clock_ark.open_gateway()
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/summon_cogscarab.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/summon_cogscarab.dm
new file mode 100644
index 00000000000..6c39d38ba14
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/summon_cogscarab.dm
@@ -0,0 +1,38 @@
+/datum/scripture/cogscarab
+ name = "Summon Cogscarab"
+ desc = "Summon a Cogscarab shell, which will be possessed by fallen Ratvarian soldiers. Takes longer the more cogscarabs are alive. Requires 30 vitality."
+ tip = "Use Cogscarabs to fortify Reebe while the human servants convert and sabotage the crew."
+ button_icon_state = "Cogscarab"
+ power_cost = STANDARD_CELL_CHARGE * 0.5
+ vitality_cost = 30
+ invocation_time = 12 SECONDS
+ invocation_text = list("My fallen brothers,", "Now is the time we rise", "to protect our Lord", "and achieve greatness!")
+ category = SPELLTYPE_PRESERVATION
+ cogs_required = 5
+ invokers_required = 2
+ fast_invoke_mult = 1
+
+/datum/scripture/cogscarab/begin_invoke(mob/living/invoking_mob, obj/item/clockwork/clockwork_slab/slab, bypass_unlock_checks)
+ invocation_time = 12 SECONDS + (6 SECONDS * SSthe_ark.cogscarabs.len)
+ . = ..()
+
+/datum/scripture/cogscarab/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(!on_reebe(invoker) || !SSthe_ark.marked_areas[get_area(invoker.loc)])
+ to_chat(invoker, span_warning("You must do this on Reebe or Marked Area!"))
+ return FALSE
+
+ if(length(SSthe_ark.cogscarabs) > MAXIMUM_COGSCARABS)
+ to_chat(invoker, span_warning("You can't summon anymore cogscarabs."))
+ return FALSE
+
+ if(GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE)
+ to_chat(invoker, span_warning("It is too late to summon cogscarabs now, Ratvar is coming!"))
+ return FALSE
+ return TRUE
+
+/datum/scripture/cogscarab/invoke_success()
+ new /obj/effect/mob_spawn/ghost_role/drone/cogscarab(get_turf(invoker))
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/summon_marauder.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/summon_marauder.dm
new file mode 100644
index 00000000000..b86bcd94a1f
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/summon_marauder.dm
@@ -0,0 +1,68 @@
+#define MAXIMUM_MARAUDERS 2
+
+/datum/scripture/marauder
+ name = "Summon Clockwork Marauder"
+ desc = "Summons a Clockwork Marauder, a powerful warrior that can deflect ranged attacks. Requires 100 vitality."
+ tip = "Use Clockwork Marauders as a powerful soldier to send into combat when the fighting gets rough."
+ button_icon_state = "Clockwork Marauder"
+ power_cost = STANDARD_CELL_CHARGE
+ vitality_cost = 100
+ invocation_time = 30 SECONDS
+ invocation_text = list("Through the fires and flames...", "We fly ever free...", "nothing outshines Engine!")
+ category = SPELLTYPE_PRESERVATION
+ cogs_required = 6
+ invokers_required = 3
+ fast_invoke_mult = 1
+ // Ref to the selected observer
+ var/mob/dead/observer/selected
+
+/datum/scripture/marauder/Destroy(force)
+ selected = null
+ return ..()
+
+/datum/scripture/marauder/invoke()
+ var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates(
+ "Do you want to play as a Clockwork Marauder?",
+ check_jobban = ROLE_MIDROUND_CLOCK_CULTIST,
+ role = ROLE_SENTIENCE,
+ poll_time = 10 SECONDS,
+ ignore_category = POLL_IGNORE_CONSTRUCT,
+ alert_pic = /mob/living/basic/clockwork_marauder,
+ role_name_text = "clockwork marauder"
+ )
+ if(length(candidates))
+ selected = pick(candidates)
+
+ if(!selected)
+ to_chat(invoker, span_brass("There are no ghosts willing to be a Clockwork Marauder!"))
+ invoke_fail()
+
+ if(invocation_chant_timer)
+ deltimer(invocation_chant_timer)
+ invocation_chant_timer = null
+
+ end_invoke()
+ return FALSE
+ return ..()
+
+/datum/scripture/marauder/invoke_success()
+ var/mob/living/basic/clockwork_marauder/new_mob = new (get_turf(invoker))
+ new_mob.visible_message(span_notice("[new_mob] flashes into existance!"))
+ new_mob.PossessByPlayer(selected.key)
+ new_mob.mind.add_antag_datum(/datum/antagonist/clock_cultist/clockmob)
+ to_chat(new_mob, span_brass("You are a Clockwork Marauder! You have a [new_mob.shield_health]-hit shield that will protect you against any damage taken. \
+ Have a servant repair you with a welder, should you or your shield become too damaged."))
+ selected = null
+
+
+/datum/scripture/marauder/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(length(SSthe_ark.clockwork_marauders) >= MAXIMUM_MARAUDERS)
+ to_chat(user, span_brass("Your limited power prevents you from creating more than [MAXIMUM_MARAUDERS] Clockwork Marauders."))
+ return FALSE
+ return TRUE
+
+#undef MAXIMUM_MARAUDERS
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/vanguard.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/vanguard.dm
new file mode 100644
index 00000000000..c6bf4a8e045
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/preservation/vanguard.dm
@@ -0,0 +1,36 @@
+/datum/scripture/slab/vanguard
+ name = "Vanguard"
+ use_time = 30 SECONDS
+ slab_overlay = "vanguard"
+ desc = "Provides the user with 30 seconds of stun immunity, however other scriptures cannot be invoked while it is active."
+ tip = "Gain temporary immunity against batons and disablers."
+ invocation_text = list("With Engine's power coursing through me...", "I will stop them in their tracks!")
+ invocation_time = 2 SECONDS
+ button_icon_state = "Vanguard"
+ category = SPELLTYPE_PRESERVATION
+ cogs_required = 2
+ power_cost = STANDARD_CELL_CHARGE * 0.15
+
+/datum/scripture/slab/vanguard/apply_effects(atom/applied_atom)
+ return FALSE
+
+/datum/scripture/slab/vanguard/invoke()
+ . = ..()
+ invoker.add_traits(list(TRAIT_STUNIMMUNE,
+ TRAIT_PUSHIMMUNE,
+ TRAIT_IGNORESLOWDOWN,
+ TRAIT_NODISMEMBER), VANGUARD_TRAIT)
+ to_chat(invoker, span_notice("You feel like nothing can stop you!"))
+
+/datum/scripture/slab/vanguard/count_down()
+ . = ..()
+ if(time_left == 5 SECONDS)
+ to_chat(invoker, span_userdanger("You start to feel tired again."))
+
+/datum/scripture/slab/vanguard/end_invocation(silent)
+ . = ..()
+ invoker.remove_traits(list(TRAIT_STUNIMMUNE,
+ TRAIT_PUSHIMMUNE,
+ TRAIT_IGNORESLOWDOWN,
+ TRAIT_NODISMEMBER), VANGUARD_TRAIT)
+ to_chat(invoker, span_bolddanger("You feel the last of the energy from \the [invoking_slab] leave you.")) //smaller span here because its pretty obvious when it ends anyway
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/abscond.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/abscond.dm
new file mode 100644
index 00000000000..b74bcad15df
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/abscond.dm
@@ -0,0 +1,21 @@
+/datum/scripture/abscond
+ name = "Abscond"
+ desc = "After a long delay recalls you and anyone you are dragging to reebe. Cannot be invoked from a non marked area."
+ tip = "If using this with a prisoner dont forget to cuff them first."
+ button_icon_state = "Abscond"
+ invocation_time = 15 SECONDS
+ invocation_text = list("Return to our home, the city of cogs.")
+ category = SPELLTYPE_SERVITUDE
+ power_cost = STANDARD_CELL_CHARGE * 0.01
+
+/datum/scripture/abscond/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return
+
+ if(!SSthe_ark.marked_areas[get_area(invoker)])
+ to_chat(user, span_warning("We can only abscond from marked areas!"))
+ return FALSE
+
+/datum/scripture/abscond/invoke_success()
+ try_servant_warp(invoker, get_turf(pick(GLOB.abscond_markers)))
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/golem_conversion.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/golem_conversion.dm
new file mode 100644
index 00000000000..862175fc27c
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/golem_conversion.dm
@@ -0,0 +1,31 @@
+//replaces the anchoring crystal scripture if all 3 crystals have been summoned and protected
+/datum/scripture/transform_to_golem
+ name = "Ascend Form"
+ desc = "Ascend your form to that of a clockwork golem, giving them innate armor, environmental immunity, and faster invoking for most scriptures."
+ tip = "Can only be used by humaniod servants."
+ button_icon_state = "Spatial Warp"
+ power_cost = STANDARD_CELL_CHARGE * 0.5
+ invocation_time = 15 SECONDS
+ invocation_text = list("My form is weak...", "It must ascend...", "To that of clockwork.")
+ cogs_required = 3
+ category = SPELLTYPE_SERVITUDE
+
+/datum/scripture/transform_to_golem/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(!ishuman(invoker))
+ to_chat(invoker, span_warning("This scripture can only be used by humanoid servants."))
+ return FALSE
+
+ if(is_species(invoker, /datum/species/clockwork_golem))
+ to_chat(invoker, span_notice("You are already a clockwork golem!"))
+ return FALSE
+ return TRUE
+
+/datum/scripture/transform_to_golem/invoke_success()
+ var/mob/living/carbon/human/human_servant = invoker
+ human_servant.set_species(/datum/species/clockwork_golem)
+ human_servant.update_body(TRUE)
+ human_servant.update_mutations_overlay()
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/hateful_manacles.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/hateful_manacles.dm
new file mode 100644
index 00000000000..fedebae250f
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/hateful_manacles.dm
@@ -0,0 +1,41 @@
+/datum/scripture/slab/hateful_manacles
+ name = "Hateful Manacles"
+ desc = "Forms replicant manacles around a target's wrists that function like handcuffs, restraining the target."
+ tip = "Handcuff a target at close range to subdue them for conversion or vitality extraction."
+ button_icon_state = "Hateful Manacles"
+ power_cost = STANDARD_CELL_CHARGE * 0.05
+ invocation_time = 1.5 SECONDS // 1.5 to invoke, 3 to cuff
+ invocation_text = list("Shackle the heretic...", "Break them in body and spirit!")
+ slab_overlay = "hateful_manacles"
+ use_time = 20 SECONDS
+ cogs_required = 1
+ category = SPELLTYPE_SERVITUDE
+
+
+/datum/scripture/slab/hateful_manacles/apply_effects(mob/living/carbon/target_carbon)
+ if(!iscarbon(target_carbon) || IS_CLOCK(target_carbon))
+ return FALSE
+
+ if(target_carbon.handcuffed)
+ target_carbon.balloon_alert(invoker, "already restrained!")
+ return FALSE
+
+ playsound(target_carbon, 'sound/items/weapons/handcuffs.ogg', 30, TRUE, -2)
+ target_carbon.visible_message(span_danger("[invoker] forms a well of energy around [target_carbon], brass appearing at their wrists!"),\
+ span_userdanger("[invoker] is trying to restrain you!"))
+
+ if(!do_after(invoker, 3 SECONDS, target = target_carbon, hidden = TRUE) || target_carbon.handcuffed)
+ return FALSE
+
+ target_carbon.set_handcuffed(new /obj/item/restraints/handcuffs/clockwork(target_carbon))
+ target_carbon.update_handcuffed()
+ log_combat(invoker, target_carbon, "handcuffed")
+
+ return TRUE
+
+
+/obj/item/restraints/handcuffs/clockwork
+ name = "replicant manacles"
+ desc = "Heavy manacles made out of freezing-cold metal. It looks like brass, but feels much more solid."
+ icon_state = "brass_manacles"
+ item_flags = DROPDEL
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/integration_cog.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/integration_cog.dm
new file mode 100644
index 00000000000..abbd4737c65
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/integration_cog.dm
@@ -0,0 +1,19 @@
+/datum/scripture/integration_cog
+ name = "Integration Cog"
+ desc = "Fabricates an integration cog, which can be inserted into APCs to draw power and unlock scriptures."
+ tip = "Install integration cogs into APCs to increase your energy stores and unlock new scriptures."
+ button_icon_state = "Integration Cog"
+ invocation_time = 1 SECONDS
+ invocation_text = list("Tick tock Engine...")
+ category = SPELLTYPE_SERVITUDE
+
+/datum/scripture/integration_cog/invoke_success()
+ if(invoker.put_in_hands(new /obj/item/clockwork/integration_cog))
+ to_chat(invoker, span_brass("You summon an integration cog into your hands."))
+ playsound(src, 'sound/machines/click.ogg', 50)
+ return TRUE
+
+ else
+ to_chat(invoker, span_brass("You summon an integration cog on the floor."))
+ playsound(src, 'sound/machines/click.ogg', 50)
+ return FALSE
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/kindle.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/kindle.dm
new file mode 100644
index 00000000000..4ddc7873e0a
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/kindle.dm
@@ -0,0 +1,102 @@
+#define EFFECT_TIME (7 SECONDS)
+
+// Clock cult's version of the "bullshit stun hand"
+
+/datum/scripture/slab/kindle
+ name = "Kindle"
+ desc = "Stuns and mutes a target from a short range."
+ tip = "Best paired with hateful manacels for conversion, they are stunned for 7 seconds and muted for 14."
+ button_icon_state = "Kindle"
+ power_cost = STANDARD_CELL_CHARGE * 0.125
+ invocation_time = 2 SECONDS
+ invocation_text = list("Divinity, show them your light!")
+ after_use_text = "Let the power flow through you!"
+ slab_overlay = "volt"
+ use_time = 15 SECONDS
+ cogs_required = 1
+ category = SPELLTYPE_SERVITUDE
+
+/datum/scripture/slab/kindle/apply_effects(mob/living/hit_mob)
+ if(!isliving(hit_mob))
+ return FALSE
+
+ if(!IS_CLOCK(invoker))
+ hit_mob = invoker
+
+ if(IS_CLOCK(hit_mob))
+ return FALSE
+
+ // Chaplains are understandably 100% immune
+ if(hit_mob.can_block_magic(MAGIC_RESISTANCE_HOLY))
+ hit_mob.mob_light(color = LIGHT_COLOR_HOLY_MAGIC, range = 2, duration = 10 SECONDS)
+
+ var/mutable_appearance/forbearance = mutable_appearance('icons/mob/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER)
+ hit_mob.add_overlay(forbearance)
+ addtimer(CALLBACK(hit_mob, TYPE_PROC_REF(/atom, cut_overlay), forbearance), 10 SECONDS)
+
+ hit_mob.visible_message(span_warning("[hit_mob] stares blankly, as a field of energy flows around them."), \
+ span_userdanger("You feel a slight shock as a wave of energy flows past you."))
+
+ playsound(invoker, 'sound/effects/magic/mm_hit.ogg', 50, TRUE)
+ return TRUE
+
+ //To make battles more fun, both sides can't bullshit stun hand the other
+ if(IS_CULTIST(hit_mob))
+ hit_mob.mob_light(color = LIGHT_COLOR_BLOOD_MAGIC, range = 2, duration = 30 SECONDS)
+
+ hit_mob.adjust_stutter(15 SECONDS)
+ hit_mob.adjust_jitter(15 SECONDS)
+
+ var/mob_color = hit_mob.color
+ hit_mob.color = LIGHT_COLOR_BLOOD_MAGIC
+ animate(hit_mob, color = mob_color, time = 30 SECONDS)
+
+ hit_mob.say("Fwebar uloft'gib mirlig yro'fara!")
+
+ to_chat(invoker, span_warning("Some force greater than you intervenes! [hit_mob] is protected by Nar'sie!"))
+ to_chat(hit_mob, span_warning("You are protected by your faith to Nar'sie!"))
+
+ playsound(invoker, 'sound/effects/magic/mm_hit.ogg', 50, TRUE)
+ return TRUE
+
+ if(IS_HERETIC(hit_mob))
+ to_chat(invoker, span_warning("Some force greater than you intervenes! [hit_mob] is protected by the Forgotten Gods!"))
+ to_chat(hit_mob, span_warning("You are protected by your faith to the Forgotten Gods."))
+ var/old_color = hit_mob.color
+ hit_mob.color = rgb(0, 128, 0)
+ animate(hit_mob, color = old_color, time = 1 SECONDS, easing = EASE_IN)
+ hit_mob.adjust_stutter(15 SECONDS)
+ hit_mob.adjust_jitter(15 SECONDS)
+ playsound(invoker, 'sound/effects/magic/mm_hit.ogg', 50, TRUE)
+ return TRUE
+
+ //Successful Invokation
+ invoker.mob_light(color = LIGHT_COLOR_CLOCKWORK, range = 2, duration = 1 SECONDS)
+
+ if(issilicon(hit_mob))
+ var/mob/living/silicon/borgo = hit_mob
+ borgo.emp_act(EMP_HEAVY)
+
+ else if(iscarbon(hit_mob))
+ var/mob/living/carbon/carbon_hit = hit_mob
+ var/has_mindshield = HAS_TRAIT(hit_mob, TRAIT_MINDSHIELD)
+
+ carbon_hit.adjust_stutter(15 SECONDS)
+ carbon_hit.adjust_jitter(15 SECONDS)
+
+ carbon_hit.adjust_timed_status_effect(26 SECONDS, /datum/status_effect/speech/slurring/clock)
+
+ carbon_hit.adjust_silence(EFFECT_TIME * (has_mindshield ? 1 : 2)) //enough time to cuff and remove their radio
+ carbon_hit.AdjustKnockdown(EFFECT_TIME * (has_mindshield ? 0.5 : 1.5))
+ //pretty much 0 stun if your on reebe, still good for knockdown though, also only a 1 second stun on mindshielded people
+ carbon_hit.Stun((has_mindshield ? 0.5 SECONDS : EFFECT_TIME) * ((on_reebe(carbon_hit) && GLOB.clock_ark?.current_state) ? 0.1 : 1))
+
+ if(hit_mob.client)
+ var/client_color = hit_mob.client.color
+ hit_mob.client.color = "#BE8700"
+ animate(hit_mob.client, color = client_color, time = 2.5 SECONDS)
+
+ playsound(invoker, 'sound/effects/magic/staff_animation.ogg', 50, TRUE)
+ return TRUE
+
+#undef EFFECT_TIME
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/sentinels_compromise.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/sentinels_compromise.dm
new file mode 100644
index 00000000000..11aad309126
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/sentinels_compromise.dm
@@ -0,0 +1,59 @@
+///how much do we heal per do_after() loop
+#define HEALED_PER_LOOP 20
+
+/datum/scripture/slab/sentinels_compromise
+ name = "Sentinel's Compromise"
+ desc = "Heals of non-toxin damage on a target then converts 50% of it back as toxin damage to you."
+ tip = "Works well with Properity Prisms. Cannot be used by cogscarabs."
+ power_cost = STANDARD_CELL_CHARGE * 0.15
+ cogs_required = 1
+ invocation_time = 1 SECONDS //short invocation but using it also takes some time afterwards
+ invocation_text = list("By the light of Engine...") //the second line is said when used on someone
+ button_icon_state = "Sentinel's Compromise"
+ category = SPELLTYPE_SERVITUDE //you have a healing spell please please PLEASE use it
+ slab_overlay = "compromise"
+ use_time = 15 SECONDS
+ recital_sound = 'sound/effects/magic/magic_missile.ogg'
+ fast_invoke_mult = 0.8
+
+/datum/scripture/slab/sentinels_compromise/check_special_requirements(mob/user)
+ if(issilicon(user))
+ invocation_time = 10 * initial(invocation_time)
+ else
+ invocation_time = initial(invocation_time) //might be worth making a silicon_invoke() proc or something
+ return ..()
+
+/datum/scripture/slab/sentinels_compromise/apply_effects(mob/living/healed_mob)
+ if(!isliving(healed_mob) || !IS_CLOCK(invoker) || !IS_CLOCK(healed_mob))
+ return FALSE
+
+ if(iscogscarab(invoker))
+ to_chat(invoker, span_warning("Your form is too frail to take the burden of another."))
+ return FALSE
+
+ if(!do_after(invoker, invocation_time, healed_mob))
+ return FALSE
+
+ healed_mob.cure_husk()
+ if(healed_mob.stat == DEAD) //technically the husk healing is free but it should be fine
+ return FALSE
+
+ healed_mob.blood_volume = BLOOD_VOLUME_NORMAL
+ healed_mob.set_nutrition(NUTRITION_LEVEL_FULL)
+ healed_mob.bodytemperature = BODYTEMP_NORMAL
+ apply_heal(healed_mob)
+ clockwork_say(invoker, text2ratvar("Wounds will close."), TRUE)
+ new /obj/effect/temp_visual/heal(get_turf(healed_mob), "#1E8CE1")
+ return TRUE
+
+/datum/scripture/slab/sentinels_compromise/proc/apply_heal(mob/living/healed_mob)
+ var/healed_amount = -healed_mob.heal_ordered_damage(HEALED_PER_LOOP, list(BRUTE, BURN, OXY, BRAIN))
+ healed_mob.adjust_stamina_loss(-HEALED_PER_LOOP)
+ healed_mob.reagents.remove_reagent(/datum/reagent/water/holywater, HEALED_PER_LOOP)
+ if(isclockgolem(invoker))
+ invoker.adjust_fire_loss(healed_amount * 0.5)
+ else
+ invoker.adjust_tox_loss(healed_amount * 0.5)
+ return TRUE
+
+#undef HEALED_PER_LOOP
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/submission_sigil.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/submission_sigil.dm
new file mode 100644
index 00000000000..d67359564ba
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/submission_sigil.dm
@@ -0,0 +1,20 @@
+/datum/scripture/create_structure/sigil_submission
+ name = "Sigil of Submission"
+ desc = "Summons a sigil of submission, which will convert anyone placed on top of it to the faith of Ratvar after 8 seconds."
+ tip = "Simply wait after placing a convertee on top, do not interact with the sigil."
+ button_icon_state = "Sigil of Submission"
+ power_cost = STANDARD_CELL_CHARGE * 0.2
+ invocation_time = 5 SECONDS
+ invocation_text = list("Relax, animal...", "for I shall show you the truth.")
+ summoned_structure = /obj/structure/destructible/clockwork/sigil/submission
+ cogs_required = 1
+ category = SPELLTYPE_SERVITUDE
+
+/datum/scripture/create_structure/sigil_submission/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(user.mind.has_antag_datum(/datum/antagonist/clock_cultist/solo))
+ to_chat(user, span_clockyellow("You don't have Justiciar permission to summon this structure..."))
+ return FALSE
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/vitality_sigil.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/vitality_sigil.dm
new file mode 100644
index 00000000000..35abde745d6
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/servitude/vitality_sigil.dm
@@ -0,0 +1,11 @@
+/datum/scripture/create_structure/sigil_vitality
+ name = "Vitality Matrix"
+ desc = "Summons a vitality matrix, which drains the life force of non servants. Much less vitality is gained from simpler entities."
+ tip = "If a fellow servant who is dead or mindless is placed on a rune, they will be restored. Bringing back the dead will cost Vitality."
+ button_icon_state = "Sigil of Vitality"
+ power_cost = STANDARD_CELL_CHARGE * 0.25
+ invocation_time = 5 SECONDS
+ invocation_text = list("My life in your hands.")
+ summoned_structure = /obj/structure/destructible/clockwork/sigil/vitality
+ cogs_required = 2
+ category = SPELLTYPE_SERVITUDE
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/structures/anchoring_crystal.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/anchoring_crystal.dm
new file mode 100644
index 00000000000..bab20169097
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/anchoring_crystal.dm
@@ -0,0 +1,90 @@
+/datum/scripture/create_structure/anchoring_crystal
+ name = "Anchoring Crystal"
+ desc = "Summon an anchoring crystal to the station."
+ tip = "Oops!" //this is set on New()
+ button_icon_state = "Clockwork Obelisk"
+ power_cost = STANDARD_CELL_CHARGE * 0.5
+ invocation_time = 20 SECONDS
+ invocation_text = list("Space shall fold...", "Time shall mold...", "Anchor us here...", "Engine is near!")
+ summoned_structure = /obj/structure/destructible/clockwork/anchoring_crystal
+ cogs_required = 5
+ invokers_required = 3
+ category = SPELLTYPE_STRUCTURES
+ ///how long in seconds until the scripture can be invoked again, pretty much a cooldown
+ var/static/time_until_invokable = 0
+ ///the list of
+ var/static/list/valid_areas
+
+/datum/scripture/create_structure/anchoring_crystal/New()
+ update_info()
+ . = ..()
+ RegisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CHARGED, PROC_REF(on_crystal_charged))
+ RegisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CREATED, PROC_REF(update_info))
+
+/datum/scripture/create_structure/anchoring_crystal/Destroy(force)
+ UnregisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CHARGED)
+ UnregisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CREATED)
+ return ..()
+
+/datum/scripture/create_structure/anchoring_crystal/process(seconds_per_tick)
+ time_until_invokable = time_until_invokable - (seconds_per_tick SECONDS)
+ if(time_until_invokable <= 0)
+ var/datum/scripture/create_structure/anchoring_crystal/global_datum = GLOB.clock_scriptures_by_type[/datum/scripture/create_structure/anchoring_crystal]
+ STOP_PROCESSING(SSprocessing, global_datum)
+ time_until_invokable = 0
+
+/datum/scripture/create_structure/anchoring_crystal/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(time_until_invokable)
+ to_chat(invoker, span_warning("The ark will be stable enough to summon another crystal in [time_until_invokable] seconds."))
+ return FALSE
+
+ if(SSthe_ark.charged_anchoring_crystals && !SSthe_ark.valid_crystal_areas[get_area(invoker)])
+ var/list/area_list = list()
+ for(var/area/added_area in SSthe_ark.valid_crystal_areas)
+ area_list += SSthe_ark.valid_crystal_areas[added_area]
+ to_chat(invoker, span_warning("This cystal can only be summoned in [english_list(area_list)]."))
+ return FALSE
+
+ var/area/checked_area = get_area(invoker)
+ if(!(checked_area?.area_flags & VALID_TERRITORY))
+ to_chat(invoker, span_warning("You cannot summon an anchoring crystal here!"))
+ return FALSE
+ return TRUE
+
+/datum/scripture/create_structure/anchoring_crystal/invoke()
+ if(time_until_invokable) //check again in case they try and make two at once
+ var/datum/scripture/create_structure/anchoring_crystal/scripture = GLOB.clock_scriptures_by_type[/datum/scripture/create_structure/anchoring_crystal]
+ START_PROCESSING(SSprocessing, scripture) //make sure we dont brick somehow
+ to_chat(invoker, span_warning("Another Anchoring Crystal is already charging!"))
+ return FALSE
+ . = ..()
+
+/datum/scripture/create_structure/anchoring_crystal/invoke_success()
+ . = ..()
+ time_until_invokable = ANCHORING_CRYSTAL_COOLDOWN
+ var/datum/scripture/create_structure/anchoring_crystal/scripture = GLOB.clock_scriptures_by_type[/datum/scripture/create_structure/anchoring_crystal]
+ START_PROCESSING(SSprocessing, scripture)
+
+/datum/scripture/create_structure/anchoring_crystal/proc/on_crystal_charged()
+ SIGNAL_HANDLER
+ if(SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON + 2)
+ unique_lock()
+ return
+
+/datum/scripture/create_structure/anchoring_crystal/proc/update_info()
+ SIGNAL_HANDLER
+ tip = "With this crystal [anchoring_crystal_charge_message()]"
+ if(!SSthe_ark.charged_anchoring_crystals)
+ return
+
+ if(!length(SSthe_ark.valid_crystal_areas))
+ desc = "We cannot summon any more anchoring crystals to the station."
+ else
+ var/list/area_list = list()
+ for(var/area/added_area in SSthe_ark.valid_crystal_areas)
+ area_list += SSthe_ark.valid_crystal_areas[added_area]
+ desc = "Summon an anchoring crystal to the station, it can be summoned in [english_list(area_list)]."
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/structures/empower_wall.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/empower_wall.dm
new file mode 100644
index 00000000000..278bcb07afa
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/empower_wall.dm
@@ -0,0 +1,33 @@
+/datum/scripture/slab/empower_wall
+ name = "Empower Wall"
+ desc = "Empowers a clockwork wall's stabilization lattice, improving its resilience."
+ tip = "Empowers a clockwork wall's stabilization lattice, improving its resilience."
+ button_icon_state = "empower_wall"
+ power_cost = STANDARD_CELL_CHARGE * 0.1
+ invocation_time = 3 SECONDS
+ invocation_text = list("Strengthen our resolve...", "So we may never fall!")
+ slab_overlay = "hateful_manacles"
+ use_time = 30 SECONDS
+ cogs_required = 3
+ category = SPELLTYPE_STRUCTURES
+ uses = 3
+
+/datum/scripture/slab/empower_wall/apply_effects(obj/structure/destructible/clockwork/wall_lattice/applied_to)
+ if(!istype(applied_to))
+ return FALSE
+
+ if(applied_to.is_empowered)
+ applied_to.balloon_alert(invoker, "\The [applied_to] is already empowered.")
+ return FALSE
+
+ applied_to.balloon_alert(invoker, "you start to empower \the [applied_to].")
+ if(!do_after(invoker, 3 SECONDS, applied_to) || applied_to?.is_empowered)
+ applied_to.balloon_alert(invoker, "you fail to empower \the [applied_to].")
+ return FALSE
+
+ if(QDELETED(applied_to))
+ return FALSE
+
+ applied_to.balloon_alert(invoker, "you empower \the [applied_to].")
+ applied_to.empower()
+ return TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/structures/interdiction_lens.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/interdiction_lens.dm
new file mode 100644
index 00000000000..0b0ec0cce21
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/interdiction_lens.dm
@@ -0,0 +1,11 @@
+/datum/scripture/create_structure/interdiction
+ name = "Interdiction Lens"
+ desc = "Creates a device that will slow non servants in the area and damage mechanised exosuits. Requires power from a sigil of transmission."
+ tip = "Construct interdiction lens to slow down a hostile assault."
+ button_icon_state = "Interdiction Lens"
+ power_cost = STANDARD_CELL_CHARGE * 0.3
+ invocation_time = 8 SECONDS
+ invocation_text = list("Oh great lord...", "may your divinity block the outsiders.")
+ summoned_structure = /obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens
+ cogs_required = 4
+ category = SPELLTYPE_STRUCTURES
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/structures/ocular_warden.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/ocular_warden.dm
new file mode 100644
index 00000000000..e157603536b
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/ocular_warden.dm
@@ -0,0 +1,26 @@
+#define OCULAR_WARDEN_PLACE_RANGE 4
+
+/datum/scripture/create_structure/ocular_warden
+ name = "Ocular Warden"
+ desc = "An eye turret that will fire upon nearby targets."
+ tip = "Place these around to prevent crew from rushing past your defenses."
+ button_icon_state = "Ocular Warden"
+ power_cost = STANDARD_CELL_CHARGE * 0.3
+ invocation_time = 5 SECONDS
+ invocation_text = list("We summon thee to defend our temple!")
+ summoned_structure = /obj/structure/destructible/clockwork/gear_base/powered/ocular_warden
+ cogs_required = 3
+ category = SPELLTYPE_STRUCTURES
+
+/datum/scripture/create_structure/ocular_warden/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(locate(/obj/structure/destructible/clockwork/gear_base/powered/ocular_warden) in range(OCULAR_WARDEN_PLACE_RANGE))
+ user.balloon_alert(user, "too close to another warden!")
+ return FALSE
+
+ return TRUE
+
+#undef OCULAR_WARDEN_PLACE_RANGE
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/structures/prosperity_prism.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/prosperity_prism.dm
new file mode 100644
index 00000000000..1edb47dd272
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/prosperity_prism.dm
@@ -0,0 +1,26 @@
+//==================================//
+// ! Prosperity Prism ! //
+//==================================//
+/datum/scripture/create_structure/prosperity_prism
+ name = "Prosperity Prism"
+ desc = "Creates a prism that will remove all forms of damage from nearby servants over time, along with purging poisons. Requires power from a sigil of transmission."
+ tip = "Create a prosperity prism to heal servants while defending your base."
+ button_icon_state = "Prolonging Prism"
+ power_cost = STANDARD_CELL_CHARGE * 0.3
+ invocation_time = 8 SECONDS
+ invocation_text = list("Your light shall heal the wounds beneath my skin.")
+ summoned_structure = /obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism
+ cogs_required = 2
+ category = SPELLTYPE_STRUCTURES
+
+
+/datum/scripture/create_structure/prosperity_prism/check_special_requirements(mob/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(locate(/obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism) in range(3)) // No stacking heals for you
+ user.balloon_alert(user, "too close to another prism!")
+ return FALSE
+
+ return TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/structures/stargazer.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/stargazer.dm
new file mode 100644
index 00000000000..43af30a7bec
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/stargazer.dm
@@ -0,0 +1,11 @@
+/datum/scripture/create_structure/stargazer
+ name = "Stargazer"
+ desc = "Allows you to enchant your weapons giving them unique and improved properties."
+ tip = "Make your weapons more powerful by enchanting them with stargazers."
+ button_icon_state = "Stargazer"
+ power_cost = STANDARD_CELL_CHARGE * 0.25
+ invocation_time = 45 SECONDS
+ invocation_text = list("The light of Engine shall empower my armaments!")
+ summoned_structure = /obj/structure/destructible/clockwork/gear_base/stargazer
+ cogs_required = 2
+ category = SPELLTYPE_STRUCTURES
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/structures/tinkerers_cache.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/tinkerers_cache.dm
new file mode 100644
index 00000000000..5c840c3a7b4
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/tinkerers_cache.dm
@@ -0,0 +1,11 @@
+/datum/scripture/create_structure/tinkerers_cache
+ name = "Tinkerer's Cache"
+ desc = "Creates a tinkerer's cache, a powerful forge capable of crafting elite equipment."
+ tip = "Use the cache to create more powerful equipment at the cost of power and time."
+ button_icon_state = "Tinkerer's Cache"
+ power_cost = STANDARD_CELL_CHARGE * 0.35
+ invocation_time = 45 SECONDS
+ invocation_text = list("Guide my hand and we shall create greatness.")
+ summoned_structure = /obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache
+ cogs_required = 4
+ category = SPELLTYPE_STRUCTURES
diff --git a/tff_modular/modules/antagonists/clock_cult/scriptures/structures/transmission_sigil.dm b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/transmission_sigil.dm
new file mode 100644
index 00000000000..7c8139a69d2
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/scriptures/structures/transmission_sigil.dm
@@ -0,0 +1,11 @@
+/datum/scripture/create_structure/sigil_transmission
+ name = "Sigil of Transmission"
+ desc = "Summons a sigil of transmission, required to power clockwork structures. Will also drain power from charged objects."
+ tip = "Power structures using this."
+ button_icon_state = "Sigil of Transmission"
+ power_cost = STANDARD_CELL_CHARGE * 0.05
+ invocation_time = 5 SECONDS
+ invocation_text = list("Oh great holy one...", "your energy...", "the power of the holy light!")
+ summoned_structure = /obj/structure/destructible/clockwork/sigil/transmission
+ category = SPELLTYPE_STRUCTURES
+ assault_invoke_time_mult = 1
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/ark_damage.ogg b/tff_modular/modules/antagonists/clock_cult/sound/ark_damage.ogg
new file mode 100644
index 00000000000..59092957111
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/ark_damage.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/ark_deathrattle.ogg b/tff_modular/modules/antagonists/clock_cult/sound/ark_deathrattle.ogg
new file mode 100644
index 00000000000..fe7de9f5fa2
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/ark_deathrattle.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/ark_recall.ogg b/tff_modular/modules/antagonists/clock_cult/sound/ark_recall.ogg
new file mode 100644
index 00000000000..cc409d17825
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/ark_recall.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/ark_scream.ogg b/tff_modular/modules/antagonists/clock_cult/sound/ark_scream.ogg
new file mode 100644
index 00000000000..e0d3e2aabf2
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/ark_scream.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/brass_skewer.ogg b/tff_modular/modules/antagonists/clock_cult/sound/brass_skewer.ogg
new file mode 100644
index 00000000000..18463054205
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/brass_skewer.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/clockcult_gateway_charging.ogg b/tff_modular/modules/antagonists/clock_cult/sound/clockcult_gateway_charging.ogg
new file mode 100644
index 00000000000..5108a3645ca
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/clockcult_gateway_charging.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/clockcult_gateway_closing.ogg b/tff_modular/modules/antagonists/clock_cult/sound/clockcult_gateway_closing.ogg
new file mode 100644
index 00000000000..83c8592096e
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/clockcult_gateway_closing.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/eminence_command.ogg b/tff_modular/modules/antagonists/clock_cult/sound/eminence_command.ogg
new file mode 100644
index 00000000000..410ac9b7f08
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/eminence_command.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/eminence_selected.ogg b/tff_modular/modules/antagonists/clock_cult/sound/eminence_selected.ogg
new file mode 100644
index 00000000000..8185a52e625
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/eminence_selected.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/integration_cog_install.ogg b/tff_modular/modules/antagonists/clock_cult/sound/integration_cog_install.ogg
new file mode 100644
index 00000000000..35c13b33abc
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/integration_cog_install.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/lambda.ogg b/tff_modular/modules/antagonists/clock_cult/sound/lambda.ogg
new file mode 100644
index 00000000000..dad08b5dc31
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/lambda.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/miss.ogg b/tff_modular/modules/antagonists/clock_cult/sound/miss.ogg
new file mode 100644
index 00000000000..e7c3f5ddf12
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/miss.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/ocularwarden_dot1.ogg b/tff_modular/modules/antagonists/clock_cult/sound/ocularwarden_dot1.ogg
new file mode 100644
index 00000000000..8976ad8104b
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/ocularwarden_dot1.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/ocularwarden_target.ogg b/tff_modular/modules/antagonists/clock_cult/sound/ocularwarden_target.ogg
new file mode 100644
index 00000000000..0cd8b2000cb
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/ocularwarden_target.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/ratvar_reveal.ogg b/tff_modular/modules/antagonists/clock_cult/sound/ratvar_reveal.ogg
new file mode 100644
index 00000000000..3809ed7ea3f
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/ratvar_reveal.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/ratvar_rises.ogg b/tff_modular/modules/antagonists/clock_cult/sound/ratvar_rises.ogg
new file mode 100644
index 00000000000..8841b358866
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/ratvar_rises.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/sound/steam_whoosh.ogg b/tff_modular/modules/antagonists/clock_cult/sound/steam_whoosh.ogg
new file mode 100644
index 00000000000..b915dbb9ede
Binary files /dev/null and b/tff_modular/modules/antagonists/clock_cult/sound/steam_whoosh.ogg differ
diff --git a/tff_modular/modules/antagonists/clock_cult/status_effects.dm b/tff_modular/modules/antagonists/clock_cult/status_effects.dm
new file mode 100644
index 00000000000..dc9914b29dc
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/status_effects.dm
@@ -0,0 +1,84 @@
+#define CLIENT_COLOR_SOURCE_RATVAR "client_color_source_ratvar"
+
+/datum/status_effect/interdiction
+ id = "interdicted"
+ duration = 2.6 SECONDS
+ status_type = STATUS_EFFECT_REFRESH
+ tick_interval = 0.2 SECONDS
+ alert_type = /atom/movable/screen/alert/status_effect/interdiction
+ /// If we kicked the owner out of running mode
+ var/running_toggled = FALSE
+
+/datum/status_effect/interdiction/tick()
+ if(owner.move_intent != MOVE_INTENT_WALK)
+ owner.toggle_move_intent()
+ owner.adjust_confusion_up_to(1 SECONDS, 1 SECONDS)
+ running_toggled = TRUE
+ to_chat(owner, span_warning("You know you shouldn't be running here."))
+
+ owner.add_movespeed_modifier(/datum/movespeed_modifier/clock_interdiction)
+
+/datum/status_effect/interdiction/on_remove()
+ owner.remove_movespeed_modifier(/datum/movespeed_modifier/clock_interdiction)
+
+ if(running_toggled && owner.move_intent == MOVE_INTENT_WALK)
+ owner.toggle_move_intent()
+
+/atom/movable/screen/alert/status_effect/interdiction
+ name = "Interdicted"
+ desc = "I don't think I am meant to go this way."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/hud/screen_alert.dmi'
+ icon_state = "belligerent"
+
+/datum/movespeed_modifier/clock_interdiction
+ multiplicative_slowdown = 1.5
+
+/datum/status_effect/clock_warp_sickness
+ id = "clock_warp_sickness"
+ alert_type = /atom/movable/screen/alert/status_effect/clock_warp_sickness
+
+/datum/status_effect/clock_warp_sickness/on_creation(mob/living/new_owner, _duration = 1 SECONDS)
+ duration = _duration
+ return ..()
+
+/datum/status_effect/clock_warp_sickness/on_apply()
+ . = ..()
+ owner.add_actionspeed_modifier(/datum/actionspeed_modifier/clock_warp_sickness)
+ owner.add_movespeed_modifier(/datum/movespeed_modifier/clock_warp_sickness)
+ owner.adjust_confusion(duration)
+ owner.adjust_dizzy(duration)
+ owner.add_client_colour(/datum/client_colour/clock_warp, CLIENT_COLOR_SOURCE_RATVAR)
+
+/datum/status_effect/clock_warp_sickness/on_remove()
+ . = ..()
+ owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/clock_warp_sickness)
+ owner.remove_movespeed_modifier(/datum/movespeed_modifier/clock_warp_sickness)
+ owner.remove_client_colour(CLIENT_COLOR_SOURCE_RATVAR)
+
+/atom/movable/screen/alert/status_effect/clock_warp_sickness
+ name = "Warp Sickness"
+ desc = "You are disoriented from recently teleporting."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/mob/actions_clock.dmi'
+ icon_state = "warp_down"
+ alerttooltipstyle = "clockwork"
+
+/datum/movespeed_modifier/clock_warp_sickness
+ multiplicative_slowdown = 1
+
+/datum/actionspeed_modifier/clock_warp_sickness
+ multiplicative_slowdown = 0.6
+
+/datum/client_colour/clock_warp
+ color = LIGHT_COLOR_CLOCKWORK
+ priority = 2
+ fade_out = 5
+
+/datum/status_effect/speech/slurring/clock
+ id = "clock_slurring"
+ common_prob = 50
+ uncommon_prob = 25
+ replacement_prob = 33
+ doubletext_prob = 0
+ text_modification_file = "slurring_clock_text.json"
+
+#undef CLIENT_COLOR_SOURCE_RATVAR
diff --git a/tff_modular/modules/antagonists/clock_cult/structure_info_element.dm b/tff_modular/modules/antagonists/clock_cult/structure_info_element.dm
new file mode 100644
index 00000000000..4752619c625
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structure_info_element.dm
@@ -0,0 +1,64 @@
+/datum/element/clockwork_structure_info
+ element_flags = ELEMENT_DETACH_ON_HOST_DESTROY
+
+
+/datum/element/clockwork_structure_info/Attach(datum/target, list/slots_to_count)
+ . = ..()
+
+ if(!istype(target, /obj/structure/destructible/clockwork/gear_base))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, COMSIG_ATOM_AFTER_ATTACKEDBY, PROC_REF(print_info))
+ RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
+
+
+/datum/element/clockwork_structure_info/Detach(datum/target)
+ . = ..()
+ UnregisterSignal(target, COMSIG_ATOM_AFTER_ATTACKEDBY)
+
+/**
+ *
+ * This proc is called when the user hits the target with an item, which checks for it being a clockwork slab.
+ *
+ * Arguments:
+ * * source - The structure that was attacked
+ * * weapon - The item that attacked the structure
+ * * user - The one who attacked the structure
+ */
+/datum/element/clockwork_structure_info/proc/print_info(obj/structure/destructible/clockwork/gear_base/source, obj/item/weapon, mob/user, proximity_flag, click_parameters)
+ SIGNAL_HANDLER
+
+ if(!IS_CLOCK(user) || !istype(weapon, /obj/item/clockwork/clockwork_slab))
+ return
+
+ var/assembled_string = ""
+
+ assembled_string += "[source]
"
+ assembled_string += "This structure is currently [source.anchored ? "anchored" : "unanchored"].
"
+
+ if(istype(source, /obj/structure/destructible/clockwork/gear_base/powered))
+ var/obj/structure/destructible/clockwork/gear_base/powered/powered_source = source
+ assembled_string += "This structure is currently toggled [powered_source.enabled ? "on" : "off"],\
+ and is [powered_source.is_powered ? "running" : "not running"].
"
+ assembled_string += "This structure consumes [powered_source.passive_consumption] W of passive capacity while enabled.
"
+ assembled_string += "This structure is connected to [LAZYLEN(powered_source.transmission_sigils)]\
+ transmission sigil[LAZYLEN(powered_source.transmission_sigils) == 1 ? "" : "s"]."
+
+ to_chat(user, span_brass(assembled_string))
+
+/**
+ *
+ * This proc is called when a mob examines the structure
+ *
+ * Arguments:
+ * * source - The structure that was examined
+ * * user - The one who attacked the structure
+ * * examine_text - The list of text to send the examiner
+ */
+/datum/element/clockwork_structure_info/proc/on_examine(obj/structure/destructible/clockwork/gear_base/source, mob/examiner, list/examine_text)
+ SIGNAL_HANDLER
+
+ if(!IS_CLOCK(examiner))
+ return
+
+ examine_text += span_brass("You can gain more information by using a Clockwork Slab.")
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/_powered.dm b/tff_modular/modules/antagonists/clock_cult/structures/_powered.dm
new file mode 100644
index 00000000000..cb61e8f2922
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/_powered.dm
@@ -0,0 +1,170 @@
+/obj/structure/destructible/clockwork/gear_base/powered
+ /// If the structure has its "on" switch flipped. Does not mean it's on, necessarily (needs power and anchoring, too)
+ var/enabled = FALSE
+ /// How much power this structure uses passively
+ var/passive_consumption = 0
+ /// Do we actually have power when turned on
+ var/is_powered = FALSE
+ /// Lazylist of nearby transmission signals
+ var/list/transmission_sigils
+ /// Has an "_inactive" icon state
+ var/has_off_icon = TRUE
+ /// Has an "_active" icon state
+ var/has_on_icon = TRUE
+ /// Has the ability to toggle power by using an empty hand on it
+ var/has_power_toggle = TRUE
+
+/obj/structure/destructible/clockwork/gear_base/powered/Initialize(mapload)
+ . = ..()
+ update_icon_state()
+ LAZYINITLIST(transmission_sigils)
+ for(var/obj/structure/destructible/clockwork/sigil/transmission/trans_sigil in range(src, SIGIL_TRANSMISSION_RANGE))
+ link_to_sigil(trans_sigil)
+ AddComponent(/datum/component/clockwork_trap/powered_structure)
+
+/obj/structure/destructible/clockwork/gear_base/powered/Destroy()
+ for(var/obj/structure/destructible/clockwork/sigil/transmission/trans_sigil as anything in transmission_sigils)
+ trans_sigil.linked_structures -= src
+ return ..()
+
+/obj/structure/destructible/clockwork/gear_base/powered/attack_hand(mob/user)
+ if(!IS_CLOCK(user))
+ return ..()
+
+ try_toggle_power(user)
+
+/obj/structure/destructible/clockwork/gear_base/powered/wrench_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(!.)
+ return
+
+ if(anchored)
+ return
+
+ enabled = FALSE
+ turn_off()
+ update_icon_state()
+ visible_message("[src] powers down as it becomes unanchored from the ground.")
+
+/obj/structure/destructible/clockwork/gear_base/powered/update_icon_state()
+ . = ..()
+ icon_state = base_icon_state || initial(icon_state)
+
+ if(!anchored)
+ icon_state = base_icon_state + unwrenched_suffix
+ return
+
+ if(has_off_icon && (!is_powered || !enabled))
+ icon_state = base_icon_state + "_inactive"
+ return
+
+ if(has_on_icon && is_powered)
+ icon_state = base_icon_state + "_active"
+
+/obj/structure/destructible/clockwork/gear_base/powered/process(seconds_per_tick)
+ var/last_powered_state = is_powered
+ is_powered = length(transmission_sigils) > 0
+ if(last_powered_state != is_powered)
+ if(is_powered)
+ repowered()
+ else
+ depowered()
+ return FALSE
+ return TRUE
+
+/obj/structure/destructible/clockwork/gear_base/powered/proc/try_toggle_power(mob/user)
+ if(!has_power_toggle)
+ return
+
+ if(!anchored)
+ if(user)
+ balloon_alert(user, "not fastened!")
+ return
+
+ if(!enabled)
+ if(!length(transmission_sigils) || !SSthe_ark.adjust_passive_power(passive_consumption, TRUE)) //the actual adjustment is done in repowered()
+ if(user)
+ balloon_alert(user, "not enough power!")
+ return
+ enabled = TRUE //cant just do an inversion due to icon updates
+ turn_on()
+ else
+ enabled = FALSE
+ turn_off()
+
+ if(user)
+ balloon_alert(user, "turned [enabled ? "on" : "off"]")
+
+/// Turn on the structure, letting it consume power and process again
+/obj/structure/destructible/clockwork/gear_base/powered/proc/turn_on()
+ repowered()
+ START_PROCESSING(SSthe_ark, src)
+
+/// Turn off the structure, ceasing its processing
+/obj/structure/destructible/clockwork/gear_base/powered/proc/turn_off()
+ depowered()
+ STOP_PROCESSING(SSthe_ark, src)
+
+/// Checks if there's a sigil to power it, calls repower() if changed from depowered to powered, vice versa
+/obj/structure/destructible/clockwork/gear_base/powered/proc/check_transmission_sigils()
+ if(!enabled)
+ return FALSE
+
+ if(!is_powered)
+ if(length(transmission_sigils))
+ repowered()
+ return TRUE
+ return FALSE
+ else if(!length(transmission_sigils))
+ depowered()
+ return FALSE
+ return TRUE
+
+/obj/structure/destructible/clockwork/gear_base/powered/proc/check_powered()
+ is_powered = length(transmission_sigils) > 0
+ return is_powered
+
+/// Uses power if there's enough to do so
+/obj/structure/destructible/clockwork/gear_base/powered/proc/use_energy(amount)
+ return (has_power_toggle ? check_transmission_sigils() : check_powered()) && SSthe_ark.adjust_clock_power(-amount)
+
+/// Triggers when the structure runs out of power to use
+/obj/structure/destructible/clockwork/gear_base/powered/proc/depowered()
+ SHOULD_CALL_PARENT(TRUE)
+ is_powered = FALSE
+ SSthe_ark.adjust_passive_power(-passive_consumption)
+ update_icon_state()
+
+/// Triggers when the structure regains power to use
+/obj/structure/destructible/clockwork/gear_base/powered/proc/repowered()
+ SHOULD_CALL_PARENT(TRUE)
+ is_powered = length(transmission_sigils) > 0
+ SSthe_ark.adjust_passive_power(passive_consumption)
+ update_icon_state()
+
+/// Adds a sigil to the linked structure list
+/obj/structure/destructible/clockwork/gear_base/powered/proc/link_to_sigil(obj/structure/destructible/clockwork/sigil/transmission/sigil)
+ LAZYOR(transmission_sigils, sigil)
+ sigil.linked_structures |= src
+
+/// Removes a sigil from the linked structure list
+/obj/structure/destructible/clockwork/gear_base/powered/proc/unlink_to_sigil(obj/structure/destructible/clockwork/sigil/transmission/sigil)
+ if(!LAZYFIND(transmission_sigils, sigil))
+ return
+
+ LAZYREMOVE(transmission_sigils, sigil)
+ sigil.linked_structures -= src
+ check_transmission_sigils()
+
+/datum/component/clockwork_trap/powered_structure
+ takes_input = TRUE
+
+/datum/component/clockwork_trap/powered_structure/trigger()
+ if(!..())
+ return
+
+ var/obj/structure/destructible/clockwork/gear_base/powered/structure = parent
+ if(!istype(structure))
+ return
+
+ structure.try_toggle_power()
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/_structure.dm b/tff_modular/modules/antagonists/clock_cult/structures/_structure.dm
new file mode 100644
index 00000000000..c4fbe600a25
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/_structure.dm
@@ -0,0 +1,52 @@
+/// The base clockwork structure. Can have an alternate desc and will show up in the list of clockwork objects.
+/obj/structure/destructible/clockwork
+ name = "meme structure"
+ desc = "Some frog or something, the fuck?"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ icon_state = "rare_pepe"
+ anchored = TRUE
+ density = TRUE
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ break_message = span_warning("Sparks fly as the brass structure shatters across the ground.") //The message shown when a structure breaks
+ break_sound = 'sound/effects/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks
+ debris = list(
+ /obj/structure/fluff/clockwork/alloy_shards/large = 1,
+ /obj/structure/fluff/clockwork/alloy_shards/medium = 2,
+ /obj/structure/fluff/clockwork/alloy_shards/small = 3,
+ )
+ ///if we ignore attacks from servants of ratvar instead of taking damage
+ var/immune_to_servant_attacks = FALSE
+ ///Shown to servants when they examine
+ var/clockwork_desc = ""
+ ///Shown to servants when they examine and are on reebe
+ var/reebe_desc = ""
+ ///can this structure be rotated with a crowbar
+ var/can_rotate = TRUE
+ ///if set, then the maximum amount of damage this structure can take from take_damage()
+ var/damage_cap
+ ///a basic cooldown declare for anything that will use it
+ COOLDOWN_DECLARE(use_cooldown)
+
+/obj/structure/destructible/clockwork/Initialize(mapload)
+ . = ..()
+ if(clockwork_desc || reebe_desc)
+ AddElement(/datum/element/clockwork_description, clockwork_desc, reebe_desc)
+
+/obj/structure/destructible/clockwork/Destroy()
+ return ..()
+
+/obj/structure/destructible/clockwork/attacked_by(obj/item/I, mob/living/user)
+ if(immune_to_servant_attacks && (IS_CLOCK(user)))
+ return
+ return ..()
+
+/obj/structure/destructible/clockwork/crowbar_act(mob/living/user, obj/item/tool)
+ if(IS_CLOCK(user) && can_rotate)
+ setDir(turn(dir, 90))
+ balloon_alert(user, "rotated [dir2text(dir)]")
+ return TRUE
+
+/obj/structure/destructible/clockwork/run_atom_armor(damage_amount, damage_type, damage_flag, attack_dir, armour_penetration, armour_ignorance)
+ if(damage_cap)
+ return min(damage_cap, ..())
+ return ..()
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/anchor_crystal.dm b/tff_modular/modules/antagonists/clock_cult/structures/anchor_crystal.dm
new file mode 100644
index 00000000000..975d6f6a9d5
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/anchor_crystal.dm
@@ -0,0 +1,192 @@
+#define CRYSTAL_SHIELD_DELAY 50 SECONDS //how long until shields start to recharge
+#define CRYSTAL_CHARGING 0 //crystal is currently charging
+#define CRYSTAL_LOCATION_ANNOUNCED 1 //the location of the crystal has been anouced to the crew
+#define FULLY_CHARGED 2 //the crystal is fully charged
+#define SHIELD_ACTIVE "active" //the shield is currently active
+#define SHIELD_DEFLECT "deflect" //the shield is currently in its deflecting animation
+#define SHIELD_BREAK "break" //the shield is currently in its breaking animation
+#define SHIELD_BROKEN "broken" //the shield is currently broken
+#define EXTRA_MARKED_AREAS 4 //how many extra adjacent areas do we mark
+/obj/structure/destructible/clockwork/anchoring_crystal
+ name = "Anchoring Crystal"
+ desc = "A strange crystal that you cant quite seem to focus on."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ icon_state = "obelisk"
+ break_message = span_warning("As the Anchoring Crystal shatters you swear you hear a faint scream.")
+ break_sound = 'tff_modular/modules/antagonists/clock_cult/sound/ark_damage.ogg'
+ immune_to_servant_attacks = TRUE
+ clockwork_desc = "This will help anchor reebe to this realm, allowing for greater power."
+ can_rotate = FALSE
+ resistance_flags = FIRE_PROOF | ACID_PROOF | LAVA_PROOF
+ armor_type = /datum/armor/anchoring_crystal
+ max_integrity = 250 //pretty hard to break
+ ///how many hits this can take before taking structure damage, not using the component as its only for items/mobs
+ var/shields = 3
+ ///what charge state is this crystal
+ var/charge_state = CRYSTAL_CHARGING
+ ///what area is this in
+ var/area/crystal_area
+ ///timer var for charging
+ var/charging_for = 0
+ ///due to the way overlays are handled we have to handle everything for them within a single SIGNAL_HANDLER proc, this var is used for keeping track of what to set our overlay state to next
+ var/overlay_state = SHIELD_ACTIVE
+ ///the list of our charge effect datums
+ var/static/list/charge_datums
+ ///the charge effect datum we are currently using
+ var/datum/anchoring_crystal_charge_effect/charge_effect_datum
+ ///cooldown for when we were last hit
+ COOLDOWN_DECLARE(recently_hit_cd)
+
+/datum/armor/anchoring_crystal
+ bio = 100
+ bomb = 100 //we dont want bombing to be good
+ energy = 100
+ fire = 100
+ acid = 100
+ melee = -15 //weak to melee, subject to change
+ laser = 60 //resistant to lasers
+ bullet = 30
+
+/obj/structure/destructible/clockwork/anchoring_crystal/Initialize(mapload)
+ . = ..()
+ if(!SSthe_ark.initialized)
+ SSthe_ark.Initialize()
+
+ crystal_area = get_area(src)
+ SSthe_ark.anchoring_crystals[src] = 0
+
+ SEND_SIGNAL(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CREATED, src)
+ var/conversion_timer = SSthe_ark.convert_area_turfs(crystal_area)
+ var/list/adjacent_areas = get_area_edge_turfs(crystal_area, TRUE)[src.z]
+ var/extra_marks = 0
+ while(length(adjacent_areas) && extra_marks < EXTRA_MARKED_AREAS)
+ var/area/marked_area = pick_n_take(adjacent_areas)
+ if(marked_area.outdoors || SSthe_ark.marked_areas[marked_area])
+ continue
+
+ extra_marks++
+ SSthe_ark.marked_areas[marked_area] = TRUE
+ SSthe_ark.convert_area_turfs(marked_area, 50, conversion_timer)
+
+ priority_announce("Reality warping object aboard the station, emergency shuttle uplink connection lost.", "Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE)
+ send_clock_message(null, span_bigbrass(span_bold("An Anchoring Crystal has been created at [crystal_area], defend it!")))
+ START_PROCESSING(SSthe_ark, src)
+ RegisterSignal(src, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays))
+ update_icon()
+
+ SSthe_ark.marked_areas[crystal_area] = TRUE
+ SSthe_ark.block_shuttle(src)
+ if(SSthe_ark.valid_crystal_areas)
+ SSthe_ark.valid_crystal_areas -= crystal_area
+
+/obj/structure/destructible/clockwork/anchoring_crystal/Destroy()
+ SSthe_ark.clear_shuttle_interference(src)
+ return ..()
+
+/obj/structure/destructible/clockwork/anchoring_crystal/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration)
+ COOLDOWN_START(src, recently_hit_cd, CRYSTAL_SHIELD_DELAY)
+ if(shields >= 1)
+ shields--
+ src.visible_message("The attack is deflected by the shield of [src].")
+ if(shields > 0)
+ overlay_state = SHIELD_DEFLECT
+ else
+ overlay_state = SHIELD_BREAK
+ do_sparks(2, TRUE, src)
+ update_icon()
+ damage_amount = 0 //dont take damage if we have shields
+ return ..()
+
+/obj/structure/destructible/clockwork/anchoring_crystal/process(seconds_per_tick)
+ for(var/mob/living/affected_mob in crystal_area)
+ if(IS_CLOCK(affected_mob))
+ affected_mob.adjust_tox_loss(-2.5 * seconds_per_tick, TRUE, TRUE) //slightly better tox healing as well as better stam healing around it for servants
+ affected_mob.adjust_stamina_loss(-3.75 * seconds_per_tick, TRUE)
+ continue
+ affected_mob.adjust_silence_up_to(5 SECONDS * seconds_per_tick, 30 SECONDS)
+
+ if(charge_state == FULLY_CHARGED) //if fully charged then add the power and return
+ SSthe_ark.adjust_clock_power(5 * seconds_per_tick, TRUE)
+ return
+
+ charging_for = min(charging_for + (seconds_per_tick * 10), ANCHORING_CRYSTAL_CHARGE_DURATION)
+
+ if(shields < initial(shields) && COOLDOWN_FINISHED(src, recently_hit_cd))
+ playsound(src, 'sound/effects/magic/charge.ogg', 50, TRUE)
+ shields++
+ overlay_state = SHIELD_ACTIVE
+ update_icon()
+
+ if(charging_for >= ANCHORING_CRYSTAL_CHARGE_DURATION)
+ finish_charging()
+ return
+
+ if(charge_state < CRYSTAL_LOCATION_ANNOUNCED && charging_for >= 30 SECONDS) //announce after thirty seconds
+ charge_state = CRYSTAL_LOCATION_ANNOUNCED
+ priority_announce("Reality warping object located in [crystal_area].", "Central Command Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE)
+
+/obj/structure/destructible/clockwork/anchoring_crystal/Destroy()
+ send_clock_message(null, span_bigbrass(span_bold("The Anchoring Crystal at [crystal_area] has been destroyed!")))
+ SSthe_ark.anchoring_crystals -= src
+ STOP_PROCESSING(SSthe_ark, src)
+ UnregisterSignal(src, COMSIG_ATOM_UPDATE_OVERLAYS)
+ return ..()
+
+/obj/structure/destructible/clockwork/anchoring_crystal/examine(mob/user) //needs to be here as it has updating information
+ . = ..()
+ if(IS_CLOCK(user) || isobserver(user))
+ . += span_brass(\
+ "[charge_state == FULLY_CHARGED ? "It is fully charged and is indestructable." : "It will be fully charged in [DisplayTimeText(ANCHORING_CRYSTAL_CHARGE_DURATION-charging_for)]."]")
+
+//do all the stuff for finishing charging
+/obj/structure/destructible/clockwork/anchoring_crystal/proc/finish_charging()
+ send_clock_message(null, span_bigbrass(span_bold("The Anchoring Crystal at [crystal_area] has fully charged! [anchoring_crystal_charge_message(TRUE)]")))
+ charge_state = FULLY_CHARGED
+ resistance_flags |= INDESTRUCTIBLE
+ atom_integrity = INFINITY
+ set_armor(/datum/armor/immune)
+ desc += "Reality around it shimmers, making it effectively impervious to damage."
+ priority_announce("Reality in [crystal_area] has been destabilized, all personnel are advised to avoid the area.", \
+ "Central Command Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE)
+ SSthe_ark.on_crystal_charged(src)
+
+//set the shield overlay
+/obj/structure/destructible/clockwork/anchoring_crystal/proc/on_update_overlays(atom/crystal, list/overlays)
+ SIGNAL_HANDLER
+
+ var/mutable_appearance/shield_appearance = mutable_appearance('tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi', \
+ overlay_state == SHIELD_BROKEN ? "broken" : "clock_shield", ABOVE_OBJ_LAYER)
+ if(overlay_state == SHIELD_DEFLECT)
+ shield_appearance.icon_state = "clock_shield_deflect"
+ overlay_state = SHIELD_ACTIVE
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 3)
+ else if(overlay_state == SHIELD_BREAK)
+ shield_appearance.icon_state = "clock_shield_break"
+ overlay_state = SHIELD_BROKEN
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 2)
+ overlays += shield_appearance
+
+///return a message based off of what this anchoring crystal did/will do for the cult
+/proc/anchoring_crystal_charge_message(completed = FALSE)
+ var/message = ""
+ switch(SSthe_ark.charged_anchoring_crystals)
+ if(0)
+ message = "[completed ? "We can now" : "We will be able to"] support 2 more servants and gain faster build speed with replica fabricators on reebe."
+ if(ANCHORING_CRYSTALS_TO_SUMMON - 1)
+ message = "[completed ? "We can now" : "We will be able to"] open the ark."
+ if(ANCHORING_CRYSTALS_TO_SUMMON)
+ message = "The Steam Helios, a strong 2 pilot mech, [completed ? "has been" : "will be"] summoned to reebe."
+ if(ANCHORING_CRYSTALS_TO_SUMMON + 1)
+ message = "Humaniod servants [completed ? "may now" : "will be able to"] ascend their form to that of a clockwork golem, giving them innate armor, environmental immunity, \
+ and faster invoking for most scriptures."
+ return message
+
+#undef CRYSTAL_SHIELD_DELAY
+#undef CRYSTAL_CHARGING
+#undef CRYSTAL_LOCATION_ANNOUNCED
+#undef FULLY_CHARGED
+#undef SHIELD_ACTIVE
+#undef SHIELD_DEFLECT
+#undef SHIELD_BREAK
+#undef SHIELD_BROKEN
+#undef EXTRA_MARKED_AREAS
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/brass_window.dm b/tff_modular/modules/antagonists/clock_cult/structures/brass_window.dm
new file mode 100644
index 00000000000..3db6cff3dd9
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/brass_window.dm
@@ -0,0 +1,75 @@
+/obj/structure/window/reinforced/clockwork
+ name = "brass window"
+ desc = "A paper-thin pane of translucent yet reinforced brass."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/window.dmi'
+ icon_state = "clockwork_window_single"
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ max_integrity = 80
+ explosion_block = 2
+ decon_speed = 4 SECONDS
+ glass_type = /obj/item/stack/sheet/bronze
+ glass_amount = 1
+
+/obj/structure/window/reinforced/clockwork/Initialize(mapload, direct)
+ if(on_reebe(src))
+ decon_speed = 1 SECONDS
+ max_integrity = round(max_integrity * 0.5) //I would like to make it take double damage instead but this about works for now
+ . = ..()
+
+/obj/structure/window/reinforced/clockwork/attackby_secondary(obj/item/tool, mob/user, params)
+ if(state == RWINDOW_SECURE)
+ if(tool.tool_behaviour == TOOL_WIRECUTTER && IS_CLOCK(user))
+ user.visible_message(
+ span_notice("[user] starts cutting the pane of \the [src] away..."),
+ span_notice("You start cutting away the pane of \the [src]."))
+ if(tool.use_tool(src, user, 2 SECONDS, volume = 50))
+ state = RWINDOW_BARS_CUT
+ to_chat(user, span_notice("The window pane falls out of the way exposing the frame bolts."))
+ return ..()
+
+/obj/structure/window/reinforced/clockwork/examine(mob/user)
+ . = ..()
+ if(IS_CLOCK(user))
+ if(state == RWINDOW_SECURE)
+ . += span_brass("You see a way to cut the window pane away.")
+
+/obj/structure/window/reinforced/clockwork/narsie_act()
+ take_damage(rand(25, 75), BRUTE)
+ if(!QDELETED(src))
+ var/previouscolor = color
+ color = "#960000"
+ animate(src, color = previouscolor, time = 8)
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8)
+
+/obj/structure/window/reinforced/clockwork/ratvar_act()
+ return FALSE
+
+/obj/structure/window/reinforced/clockwork/rcd_act(mob/user, obj/item/construction/rcd/the_rcd)
+ return
+
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/clockwork/spawner, 0)
+
+/obj/structure/window/reinforced/clockwork/unanchored
+ anchored = FALSE
+
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/clockwork/unanchored/spawner, 0)
+
+/obj/structure/window/reinforced/clockwork/fulltile
+ icon_state = "clockwork_window-0"
+ base_icon_state = "clockwork_window"
+ icon = 'icons/obj/smooth_structures/clockwork_window.dmi'
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = SMOOTH_GROUP_WINDOW_FULLTILE_BRONZE + SMOOTH_GROUP_WINDOW_FULLTILE
+ canSmoothWith = SMOOTH_GROUP_WINDOW_FULLTILE_BRONZE
+ fulltile = TRUE
+ flags_1 = PREVENT_CLICK_UNDER_1
+ obj_flags = CAN_BE_HIT
+ max_integrity = 100
+ glass_amount = 2
+
+/obj/structure/window/reinforced/clockwork/Initialize(mapload, direct)
+ new /obj/effect/temp_visual/ratvar/window(get_turf(src))
+ return ..()
+
+/obj/structure/window/reinforced/clockwork/fulltile/unanchored
+ anchored = FALSE
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/eminence_beacon.dm b/tff_modular/modules/antagonists/clock_cult/structures/eminence_beacon.dm
new file mode 100644
index 00000000000..a608f3aaa6b
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/eminence_beacon.dm
@@ -0,0 +1,81 @@
+/obj/structure/destructible/clockwork/eminence_beacon
+ name = "Eminence Spire"
+ desc = "An ancient, brass spire which holds the spirit of a powerful entity conceived by Ratvar to oversee his faithful servants."
+ icon_state = "tinkerers_daemon"
+ resistance_flags = INDESTRUCTIBLE
+ ///are we currently holding a vote for an eminence
+ var/vote_active = FALSE
+ ///weakref to our vote timer
+ var/datum/weakref/vote_timer
+ ///are we currently polling for an eminence
+ var/polling = FALSE
+
+/obj/structure/destructible/clockwork/eminence_beacon/attack_hand(mob/user)
+ . = ..()
+ if(!IS_CLOCK(user))
+ return
+ if(vote_active)
+ if(vote_timer)
+ deltimer(vote_timer?.resolve())
+ vote_timer = null
+ vote_active = FALSE
+ send_clock_message(null, "[user] has cancelled the Eminence vote.")
+ return
+ if(GLOB.current_eminence)
+ to_chat(user, span_brass("The Eminence has already been released."))
+ return
+
+ var/option = tgui_alert(user, "Becoming the Eminence is not an easy task, be sure you will be able to lead the servants. \
+ If you choose to do so, your old form with be destroyed.", "Who shall control the Eminence?", list("Yourself", "A ghost", "Cancel"))
+ if(vote_active)
+ balloon_alert(user, "a vote has already been called, if you would like to object you can interact with the spire again.")
+ return
+
+ if(option == "Yourself")
+ send_clock_message(null, span_bigbrass("[user] has elected themselves to become the Eminence. Interact with \the [src] to object."))
+ vote_timer = WEAKREF(addtimer(CALLBACK(src, PROC_REF(vote_succeed), user), 60 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE))
+ else if(option == "A ghost")
+ send_clock_message(null, span_bigbrass("[user] has elected for a ghost to become the Eminence. Interact with \the [src] to object."))
+ vote_timer = WEAKREF(addtimer(CALLBACK(src, PROC_REF(vote_succeed)), 60 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE))
+ else
+ return
+ vote_active = TRUE
+
+/obj/structure/destructible/clockwork/eminence_beacon/proc/vote_succeed(mob/living/eminence) //if we select a ghost then we dont call any living procs so this is fine
+ vote_active = FALSE
+ if(polling)
+ return
+
+ if(GLOB.current_eminence)
+ message_admins("[type] calling vote_succeed() with a set GLOB.current_eminence, this should not be happening.")
+ return
+ polling = TRUE
+ if(!eminence)
+ var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates(
+ "Do you want to play as the eminence",
+ check_jobban = ROLE_MIDROUND_CLOCK_CULTIST,
+ role = ROLE_SENTIENCE,
+ poll_time = 10 SECONDS,
+ alert_pic = /mob/living/eminence,
+ role_name_text = "eminence"
+ )
+ if(length(candidates))
+ eminence = pick(candidates)
+
+ polling = FALSE
+ if(!(eminence?.client))
+ send_clock_message(null, "The Eminence remains in slumber, for now, try waking it again soon.")
+ return
+
+ var/mob/living/eminence/new_mob = new /mob/living/eminence(get_turf(src))
+ if(isobserver(eminence))
+ new_mob.PossessByPlayer(eminence.key)
+ else
+ var/datum/antagonist/clock_cultist/servant_datum = eminence.mind.has_antag_datum(/datum/antagonist/clock_cultist)
+ if(servant_datum)
+ servant_datum.silent = TRUE
+ servant_datum.on_removal()
+ eminence.mind.transfer_to(new_mob, TRUE)
+ eminence.dust(TRUE, TRUE)
+ new_mob.mind.add_antag_datum(/datum/antagonist/clock_cultist/eminence)
+ send_clock_message(null, span_bigbrass("The Eminence has risen!"))
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/gear_base.dm b/tff_modular/modules/antagonists/clock_cult/structures/gear_base.dm
new file mode 100644
index 00000000000..6ab82016744
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/gear_base.dm
@@ -0,0 +1,45 @@
+/obj/structure/destructible/clockwork/gear_base
+ name = "gear base"
+ desc = "A large cog lying on the floor at feet level."
+ icon_state = "gear_base"
+ clockwork_desc = "A large cog lying on the floor at feet level."
+ anchored = FALSE
+ break_message = span_warning("Oh, that broke.")
+ /// What's appeneded to the structure when unanchored
+ var/unwrenched_suffix = "_unwrenched"
+ /// If this can be moved at all by unwrenching it
+ var/can_unwrench = TRUE
+
+
+/obj/structure/destructible/clockwork/gear_base/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_structure_info)
+
+
+/obj/structure/destructible/clockwork/gear_base/wrench_act(mob/living/user, obj/item/tool)
+ if(!IS_CLOCK(user))
+ return
+
+ if(!can_unwrench)
+ balloon_alert(user, "cannot be unwrenched!")
+ return
+
+ balloon_alert(user, "[anchored ? "unwrenching" : "wrenching"]...")
+
+ if(!tool.use_tool(src, user, 2 SECONDS, volume = 50))
+ return
+
+ visible_message(span_notice("[user] [anchored ? "unwrenches" : "wrenches down"] [src]."), span_notice("You [anchored ? "unwrench" : "wrench"] [src]."))
+
+ anchored = !anchored
+ update_icon_state()
+
+ return TRUE
+
+
+/obj/structure/destructible/clockwork/gear_base/update_icon_state()
+ . = ..()
+ icon_state = initial(icon_state)
+
+ if(!anchored)
+ icon_state += unwrenched_suffix
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/interdiction_lens.dm b/tff_modular/modules/antagonists/clock_cult/structures/interdiction_lens.dm
new file mode 100644
index 00000000000..ec142e237fc
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/interdiction_lens.dm
@@ -0,0 +1,93 @@
+#define INTERDICTION_LENS_RANGE 4
+#define POWER_PER_PERSON 3
+
+/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens
+ name = "interdiction lens"
+ desc = "A mesmerizing light that flashes to a rhythm that you just can't stop tapping to."
+ clockwork_desc = "A small device which will slow down nearby attackers and projectiles at a large power cost, both active and passive."
+ icon_state = "interdiction_lens"
+ base_icon_state = "interdiction_lens"
+ anchored = TRUE
+ break_message = span_warning("The interdiction lens breaks into multiple fragments, which gently float to the ground.")
+ max_integrity = 150
+ passive_consumption = 5
+ /// Dampening field around the interdiction
+ var/datum/proximity_monitor/advanced/bubble/projectile_dampener/clockcult/dampening_field
+
+/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens/Initialize(mapload)
+ . = ..()
+ dampening_field = new(src, INTERDICTION_LENS_RANGE, TRUE, src)
+
+/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens/Destroy()
+ if(enabled)
+ STOP_PROCESSING(SSobj, src)
+ QDEL_NULL(dampening_field)
+ return ..()
+
+/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens/process(delta_time)
+ . = ..()
+ if(!.)
+ return
+
+ for(var/mob/living/living_mob in viewers(INTERDICTION_LENS_RANGE, src))
+ if(!IS_CLOCK(living_mob) && use_energy(POWER_PER_PERSON))
+ living_mob.apply_status_effect(/datum/status_effect/interdiction)
+
+ for(var/obj/vehicle/sealed/mecha/mech in range(INTERDICTION_LENS_RANGE, src))
+ var/clock_pilot = FALSE
+ for(var/mob/living/pilot in mech.occupants)
+ if(!IS_CLOCK(pilot))
+ continue
+
+ clock_pilot = TRUE
+ break
+
+ if(clock_pilot || !use_energy(POWER_PER_PERSON))
+ continue
+
+ mech.emp_act(EMP_LIGHT)
+ do_sparks(mech, TRUE, mech)
+
+/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens/repowered()
+ . = ..()
+ flick("interdiction_lens_recharged", src)
+
+ if(istype(dampening_field))
+ QDEL_NULL(dampening_field)
+
+ dampening_field = new(src, INTERDICTION_LENS_RANGE, TRUE, src)
+
+/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens/depowered()
+ . = ..()
+ flick("interdiction_lens_discharged", src)
+ QDEL_NULL(dampening_field)
+
+/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens/free
+
+/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens/free/use_energy(amount)
+ return TRUE
+
+//Dampening field
+
+/datum/proximity_monitor/advanced/bubble/projectile_dampener/clockcult/setup_effect_directions()
+ return NONE // Should be invisible
+
+/datum/proximity_monitor/advanced/bubble/projectile_dampener/clockcult/draw_effect()
+ return NONE // Should be invisible
+
+/datum/proximity_monitor/advanced/bubble/projectile_dampener/clockcult/catch_bullet_effect(obj/projectile/bullet)
+ if(isliving(bullet.firer))
+ var/mob/living/living_firer = bullet.firer
+ if(IS_CLOCK(living_firer))
+ return
+ return ..()
+
+/datum/proximity_monitor/advanced/bubble/projectile_dampener/clockcult/release_bullet_effect(obj/projectile/bullet)
+ if(isliving(bullet.firer))
+ var/mob/living/living_firer = bullet.firer
+ if(IS_CLOCK(living_firer))
+ return
+ return ..()
+
+#undef INTERDICTION_LENS_RANGE
+#undef POWER_PER_PERSON
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/lattice.dm b/tff_modular/modules/antagonists/clock_cult/structures/lattice.dm
new file mode 100644
index 00000000000..b91b92ee324
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/lattice.dm
@@ -0,0 +1,58 @@
+/obj/structure/lattice/clockwork
+ name = "cog lattice"
+ desc = "A lightweight support lattice. These hold the Justicar's station together."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork.dmi'
+ icon_state = "lattice_clockwork-0"
+ base_icon_state = "lattice_clockwork"
+ smoothing_groups = SMOOTH_GROUP_LATTICE
+ canSmoothWith = SMOOTH_GROUP_LATTICE
+
+/obj/structure/lattice/clockwork/Initialize(mapload)
+ . = ..()
+ ratvar_act()
+ if(on_reebe(src))
+ resistance_flags |= INDESTRUCTIBLE
+
+/obj/structure/lattice/clockwork/ratvar_act()
+ if(ISODD(x+y)) //this check looks to be broken
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork_large.dmi'
+ pixel_x = -9
+ pixel_y = -9
+ else
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/lattice_clockwork.dmi'
+ pixel_x = 0
+ pixel_y = 0
+ return TRUE
+
+/obj/structure/lattice/catwalk/clockwork
+ name = "clockwork catwalk"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork.dmi'
+ icon_state = "catwalk_clockwork-0"
+ base_icon_state = "catwalk_clockwork"
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = SMOOTH_GROUP_CATWALK + SMOOTH_GROUP_LATTICE + SMOOTH_GROUP_OPEN_FLOOR
+ canSmoothWith = SMOOTH_GROUP_CATWALK
+
+/obj/structure/lattice/catwalk/clockwork/Initialize(mapload)
+ . = ..()
+ if(!mapload)
+ new /obj/effect/temp_visual/ratvar/floor/catwalk(loc)
+ new /obj/effect/temp_visual/ratvar/beam/catwalk(loc)
+ if(on_reebe(src))
+ resistance_flags |= INDESTRUCTIBLE
+
+/obj/structure/lattice/catwalk/clockwork/Destroy(force)
+ if(resistance_flags & INDESTRUCTIBLE)
+ return
+ return ..()
+
+/obj/structure/lattice/catwalk/clockwork/ratvar_act()
+ if(ISODD(x+y))
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork_large.dmi'
+ pixel_x = -9
+ pixel_y = -9
+ else
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/catwalk_clockwork.dmi'
+ pixel_x = 0
+ pixel_y = 0
+ return TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/ocular_warden.dm b/tff_modular/modules/antagonists/clock_cult/structures/ocular_warden.dm
new file mode 100644
index 00000000000..22b087aa3cb
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/ocular_warden.dm
@@ -0,0 +1,78 @@
+#define FIRE_DELAY (2 SECONDS)
+#define FIRE_RANGE 6
+#define BASE_DAMAGE 10
+#define MINIMUM_DAMAGE 10
+#define DAMAGE_FALLOFF 1
+#define SHOOT_POWER_USE 5
+
+/obj/structure/destructible/clockwork/gear_base/powered/ocular_warden
+ name = "ocular warden"
+ desc = "A wide, open eye that stares intently into your soul. It seems resistant to energy based weapons."
+ clockwork_desc = "A defensive device that will fight any nearby intruders."
+ break_message = span_warning("A black ooze leaks from the ocular warden as it slowly sinks to the ground.")
+ icon_state = "ocular_warden"
+ base_icon_state = "ocular_warden"
+ max_integrity = 75
+ armor_type = /datum/armor/clockwork_ocular_warden
+ passive_consumption = 3
+ can_unwrench = FALSE
+ anchored = TRUE
+ /// Cooldown between firing
+ COOLDOWN_DECLARE(fire_cooldown)
+
+/datum/armor/clockwork_ocular_warden
+ melee = -50
+ bullet = -10
+ laser = 60
+ energy = 60
+ bomb = 20
+ bio = 0
+
+/obj/structure/destructible/clockwork/gear_base/powered/ocular_warden/process(delta_time)
+ . = ..()
+ if(!.)
+ return
+
+ if(!COOLDOWN_FINISHED(src, fire_cooldown))
+ return
+
+ //Check hostiles in range
+ var/list/valid_targets = list()
+ for(var/mob/living/potential_target in hearers(FIRE_RANGE, src))
+
+ if(IS_CLOCK(potential_target) || potential_target.stat)
+ continue
+
+ valid_targets += potential_target
+
+ if(!length(valid_targets))
+ return
+
+ if(!use_energy(SHOOT_POWER_USE))
+ return
+
+ playsound(src, 'tff_modular/modules/antagonists/clock_cult/sound/ocularwarden_target.ogg', 60, TRUE)
+
+ var/mob/living/target = pick(valid_targets)
+ if(!target)
+ return
+
+ dir = get_dir(get_turf(src), get_turf(target))
+
+ // Apply 10 damage (- 1 for each tile away they are), or 5, whichever is larger
+ target.apply_damage(max(BASE_DAMAGE - (get_dist(src, target) * DAMAGE_FALLOFF), MINIMUM_DAMAGE) * delta_time, BURN)
+ to_chat(target, span_boldwarning("You feel as though your soul is being burned!"))
+
+ new /obj/effect/temp_visual/ratvar/ocular_warden(get_turf(target))
+ new /obj/effect/temp_visual/ratvar/ocular_warden(get_turf(src))
+
+ playsound(target, 'tff_modular/modules/antagonists/clock_cult/sound/ocularwarden_dot1.ogg', 60, TRUE)
+
+ COOLDOWN_START(src, fire_cooldown, FIRE_DELAY)
+
+#undef FIRE_DELAY
+#undef FIRE_RANGE
+#undef BASE_DAMAGE
+#undef MINIMUM_DAMAGE
+#undef DAMAGE_FALLOFF
+#undef SHOOT_POWER_USE
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/prosperity_prism.dm b/tff_modular/modules/antagonists/clock_cult/structures/prosperity_prism.dm
new file mode 100644
index 00000000000..f035a1f39b5
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/prosperity_prism.dm
@@ -0,0 +1,44 @@
+#define POWER_PER_USE 3
+#define HEAL_PER_USE 2
+
+/obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism
+ name = "prosperity prism"
+ desc = "A prism that seems to somehow always have its gaze locked to you."
+ clockwork_desc = "A prism that will heal nearby servants of various damage types, along with purging poisons."
+ icon_state = "prolonging_prism"
+ base_icon_state = "prolonging_prism"
+ anchored = TRUE
+ break_message = span_warning("The prism falls apart, smoke leaking out into the air.")
+ max_integrity = 150
+ passive_consumption = 5
+ ///typecache of chem types to purge
+ var/static/list/chems_to_purge
+
+/obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism/Initialize(mapload)
+ . = ..()
+ if(!chems_to_purge)
+ chems_to_purge = typecacheof(list(/datum/reagent/toxin, /datum/reagent/water/holywater))
+
+/obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism/process(seconds_per_tick)
+ . = ..()
+ if(!.)
+ return
+
+ for(var/mob/living/possible_cultist in range(3, src))
+ if(isnull(possible_cultist) || !IS_CLOCK(possible_cultist) || possible_cultist.health >= possible_cultist.maxHealth || !use_energy(-POWER_PER_USE))
+ continue
+
+ var/healed_amount = HEAL_PER_USE * seconds_per_tick
+ possible_cultist.adjust_stamina_loss(-4 * seconds_per_tick, TRUE)
+ possible_cultist.adjust_oxy_loss(-healed_amount)
+ possible_cultist.heal_overall_damage(healed_amount, healed_amount, updating_health = TRUE)
+ new /obj/effect/temp_visual/heal(get_turf(possible_cultist), "#1E8CE1")
+ if(!possible_cultist.reagents)
+ continue
+
+ for(var/datum/reagent/negative_chem in possible_cultist.reagents?.reagent_list)
+ if(is_type_in_typecache(negative_chem, chems_to_purge))
+ possible_cultist.reagents?.remove_reagent(negative_chem.type, 2.5 * seconds_per_tick)
+
+#undef POWER_PER_USE
+#undef HEAL_PER_USE
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/sigil/_sigil.dm b/tff_modular/modules/antagonists/clock_cult/structures/sigil/_sigil.dm
new file mode 100644
index 00000000000..ff5fb371130
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/sigil/_sigil.dm
@@ -0,0 +1,148 @@
+#define SIGIL_INVOCATION_ALPHA 120
+#define SIGIL_INVOKED_ALPHA 200
+#define SIGIL_MATRIX_SCALE 1.2
+
+//Sigil base
+/obj/structure/destructible/clockwork/sigil
+ name = "sigil"
+ desc = "It's a sigil that does something."
+ max_integrity = 10
+ break_sound = null
+ debris = null
+ break_message = "The sigil is dispelled."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi'
+ icon_state = "sigilvitality"
+ density = FALSE
+ alpha = 90
+ /// How long you stand on the sigil before affect is applied
+ var/effect_stand_time = 0
+ /// The atom/movable that this is currently affecting
+ var/currently_affecting
+ /// Color while not used
+ var/idle_color = "#FFFFFF"
+ /// Color faded to while someone stands on top
+ var/invocation_color = "#F1A03B"
+ /// Color pulsed when effect applied
+ var/pulse_color = "#EBC670"
+ /// Color pulsed when effect fails
+ var/fail_color = "#d47433"
+ /// Ref to the current timer
+ var/active_timer
+ /// TRUE if the affect repeatedly applied an affect to the thing above it
+ var/looping = FALSE
+ /// FALSE if the rune can affect non-living atoms
+ var/living_only = TRUE
+
+/obj/structure/destructible/clockwork/sigil/Initialize(mapload)
+ . = ..()
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
+ COMSIG_ATOM_EXITED = PROC_REF(on_exited),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
+ color = idle_color
+
+/obj/structure/destructible/clockwork/sigil/Destroy()
+ currently_affecting = null
+
+ if(active_timer)
+ deltimer(active_timer)
+ active_timer = null
+
+ return ..()
+
+/obj/structure/destructible/clockwork/sigil/attack_hand(mob/user)
+ . = ..()
+ if(dispel_check(user))
+ dispel()
+
+/// For trap sigils and similar; applies effects when someone/something walks over
+/obj/structure/destructible/clockwork/sigil/proc/on_entered(datum/source, atom/movable/entered_movable)
+ SIGNAL_HANDLER
+
+ if((!isliving(entered_movable) && living_only) || currently_affecting || active_timer)
+ return
+
+ currently_affecting = entered_movable
+ if(!effect_stand_time)
+ apply_effects(entered_movable)
+ return
+
+ do_sparks(5, TRUE, src)
+ animate(src, color = invocation_color, alpha = SIGIL_INVOCATION_ALPHA, effect_stand_time)
+ active_timer = addtimer(CALLBACK(src, PROC_REF(apply_effects), entered_movable), effect_stand_time, TIMER_UNIQUE | TIMER_STOPPABLE)
+
+
+/// For when someone/something leaves the sigil's turf
+/obj/structure/destructible/clockwork/sigil/proc/on_exited(datum/source, atom/movable/exited_movable)
+ SIGNAL_HANDLER
+
+ if(currently_affecting != exited_movable)
+ return
+
+ currently_affecting = null
+ animate(src, color = idle_color, alpha = initial(alpha), time = 0.5 SECONDS)
+
+ if(active_timer)
+ deltimer(active_timer)
+ active_timer = null
+
+
+/// If the sigil does not affect living, do not inherit this
+/obj/structure/destructible/clockwork/sigil/proc/can_affect(atom/movable/movable_apply)
+
+ var/mob/living/living_mob = movable_apply
+ if(!istype(living_mob))
+ return FALSE
+
+ if(living_mob.can_block_magic(MAGIC_RESISTANCE_HOLY))
+ return FALSE
+
+ return TRUE
+
+
+/// What happens when the sigil fails to invoke
+/obj/structure/destructible/clockwork/sigil/proc/fail_invocation()
+ active_timer = null
+ currently_affecting = null
+ color = fail_color
+ transform = matrix() * SIGIL_MATRIX_SCALE
+ alpha = 140
+ animate(src, transform = matrix(), color = idle_color, alpha = initial(alpha), time = 0.5 SECONDS)
+
+
+/// Apply the effects to an atom/movable
+/obj/structure/destructible/clockwork/sigil/proc/apply_effects(atom/movable/movable_apply)
+
+ if(!can_affect(movable_apply))
+ fail_invocation()
+ return FALSE
+
+ color = pulse_color
+ transform = matrix() * SIGIL_MATRIX_SCALE
+ alpha = SIGIL_INVOKED_ALPHA
+
+ if(looping)
+ animate(src, transform = matrix(), color = invocation_color, alpha = SIGIL_INVOCATION_ALPHA, effect_stand_time)
+ active_timer = addtimer(CALLBACK(src, PROC_REF(apply_effects), movable_apply), effect_stand_time, TIMER_UNIQUE | TIMER_STOPPABLE)
+
+ else
+ active_timer = null
+ currently_affecting = null
+ animate(src, transform = matrix(), color = idle_color, alpha = initial(alpha), time = 0.5 SECONDS)
+
+ return TRUE
+
+
+/// Dispel the sigil and delete itself
+/obj/structure/destructible/clockwork/sigil/proc/dispel()
+ animate(src, transform = matrix() * 1.5, alpha = 0, time = 3)
+ QDEL_IN(src, 0.3 SECONDS)
+
+/// Put any addtional checks you want to do before dispelling here
+/obj/structure/destructible/clockwork/sigil/proc/dispel_check(mob/user)
+ return IS_CLOCK(user) || do_after(user, 10 SECONDS, src)
+
+#undef SIGIL_INVOCATION_ALPHA
+#undef SIGIL_INVOKED_ALPHA
+#undef SIGIL_MATRIX_SCALE
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_submission.dm b/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_submission.dm
new file mode 100644
index 00000000000..9a418c065f0
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_submission.dm
@@ -0,0 +1,80 @@
+/obj/structure/destructible/clockwork/sigil/submission
+ name = "sigil of submission"
+ desc = "A strange sigil, with otherworldy drawings on it."
+ clockwork_desc = "A sigil pulsating with a glorious light. Anyone held on top of this for 8 seconds will become a loyal servant of Ratvar."
+ icon_state = "sigilsubmission"
+ effect_stand_time = 8 SECONDS
+ idle_color = "#FFFFFF"
+ invocation_color = "#e042d8"
+ pulse_color = "#EBC670"
+ fail_color = "#d43333"
+
+/obj/structure/destructible/clockwork/sigil/submission/can_affect(mob/living/checked_mob)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(IS_CLOCK(checked_mob))
+ return FALSE
+
+ if(HAS_TRAIT(checked_mob, TRAIT_MINDSHIELD))
+ return FALSE
+ return is_convertable_to_clock(checked_mob)
+
+/obj/structure/destructible/clockwork/sigil/submission/apply_effects(mob/living/converted_mob)
+ . = ..()
+ if(!.)
+ converted_mob.visible_message(span_warning("[converted_mob] resists conversion!"))
+ return FALSE
+
+ if(converted_mob.client)
+ var/previous_colour = converted_mob.client.color
+ converted_mob.client.color = LIGHT_COLOR_CLOCKWORK
+ animate(converted_mob.client, color = previous_colour, time = 1 SECONDS)
+
+ GLOB.main_clock_cult?.check_member_distribution()
+ if(isdrone(converted_mob) && (length(SSthe_ark.cogscarabs) < MAXIMUM_COGSCARABS))
+ var/mob/living/basic/drone/cogscarab/cogger = new /mob/living/basic/drone/cogscarab(get_turf(src))
+ cogger.PossessByPlayer(converted_mob.key)
+ cogger.mind?.add_antag_datum(/datum/antagonist/clock_cultist)
+ cogger.visible_message("A light envelops \the [converted_mob]! As the light fades you see it has become a cogscarab!",
+ span_brass("Ratvar has granted you your freedom, you must protect the ark at all costs!"))
+ converted_mob.death(TRUE)
+ return TRUE
+
+ else if(((GLOB.main_clock_cult?.human_servants.len < GLOB.main_clock_cult?.max_human_servants) && ishuman(converted_mob)) || !ishuman(converted_mob))
+ var/datum/antagonist/clock_cultist/servant_datum = new
+ servant_datum.give_slab = FALSE
+ converted_mob.mind.add_antag_datum(servant_datum)
+ converted_mob.Paralyze(5 SECONDS)
+ converted_mob.blood_volume = BLOOD_VOLUME_NORMAL
+ if(ishuman(converted_mob))
+ var/mob/living/carbon/human/human_converted = converted_mob
+ human_converted.uncuff()
+ new /obj/item/clockwork/clockwork_slab(get_turf(src))
+
+ var/brutedamage = converted_mob.get_brute_loss()
+ var/burndamage = converted_mob.get_brute_loss()
+ if(brutedamage || burndamage)
+ converted_mob.adjust_brute_loss(-(round(brutedamage * 0.75)))
+ converted_mob.adjust_fire_loss(-(round(burndamage * 0.75)))
+
+ converted_mob.visible_message(span_warning("[converted_mob] sits completely motionless as \
+ [(brutedamage || burndamage) ? "a bright light pours from [converted_mob.p_their()] wounds as they close." \
+ : "as the sigil below [converted_mob.p_them()] glows brightly"]!"),
+ span_bigbrass("You feel a flash of light and the world spin around you!"))
+ send_clock_message(null, "[converted_mob] has been converted!")
+ converted_mob.remove_status_effect(/datum/status_effect/speech/slurring/clock)
+ return TRUE
+
+ visible_message(span_warning("\The [src] falters as though it cannot support more servants."))
+ return FALSE
+
+/obj/structure/destructible/clockwork/sigil/submission/dispel_check(mob/user)
+ . = ..()
+ if(!.)
+ return
+ if(active_timer)
+ if(IS_CLOCK(user) && tgui_alert(user, "Are you sure you want to dispel [src]? It is currently converting [currently_affecting].", "Confirm dispel", list("Yes", "No")) != "Yes")
+ return FALSE
+ return TRUE
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_transmission.dm b/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_transmission.dm
new file mode 100644
index 00000000000..97496cd841d
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_transmission.dm
@@ -0,0 +1,108 @@
+//these are not actually the amount given and taken but are instead the amount SSthe_ark.clock_power is adjusted by
+#define POWER_GIVE 5
+#define POWER_SIPHON 5
+
+/obj/structure/destructible/clockwork/sigil/transmission
+ name = "sigil of transmission"
+ desc = "A strange sigil, swirling with a yellow light."
+ clockwork_desc = "A glorious sigil used to power Ratvarian structures and recharge energy-based objects."
+ icon_state = "sigiltransmission"
+ effect_stand_time = 1 SECONDS
+ idle_color = "#f1a746"
+ invocation_color = "#f5c529"
+ pulse_color = "#f8df8b"
+ fail_color = "#f1a746"
+ looping = TRUE
+ living_only = FALSE
+ /// A list of structures linked to this sigil
+ var/list/linked_structures = list()
+
+/obj/structure/destructible/clockwork/sigil/transmission/Initialize(mapload)
+ . = ..()
+
+ for(var/obj/structure/destructible/clockwork/gear_base/powered/gear_base in range(src, SIGIL_TRANSMISSION_RANGE))
+ gear_base.link_to_sigil(src)
+ //START_PROCESSING(SSthe_ark, src)
+
+/obj/structure/destructible/clockwork/sigil/transmission/Destroy()
+ //STOP_PROCESSING(SSthe_ark, src)
+ for(var/obj/structure/destructible/clockwork/gear_base/powered/gear_base as anything in linked_structures)
+ gear_base.unlink_to_sigil(src)
+
+ return ..()
+
+/*/obj/structure/destructible/clockwork/sigil/transmission/process()
+ for(var/obj/structure/destructible/clockwork/gear_base/powered/gear_base as anything in linked_structures)
+ if(gear_base.transmission_sigils[1] != src) // [1] Ensures we are the master (first) transmission signal
+ continue
+
+ gear_base.check_transmission_sigils()*/
+
+/obj/structure/destructible/clockwork/sigil/transmission/can_affect(atom/movable/atom_movable)
+ return (ismecha(atom_movable) || iscyborg(atom_movable) || ishuman(atom_movable))
+
+/obj/structure/destructible/clockwork/sigil/transmission/apply_effects(atom/movable/apply_to)
+ if(ismecha(apply_to))
+ var/obj/vehicle/sealed/mecha/target_mech = apply_to
+ var/is_clockie = FALSE
+
+ for(var/mob/living/living_mob in target_mech.occupants)
+ if(!IS_CLOCK(living_mob))
+ continue
+
+ is_clockie = TRUE // If one person is a cultist, we just say "they good" to the mech itself
+ break
+
+ var/obj/item/stock_parts/power_store/cell/power_cell = target_mech.cell
+
+ if(!power_cell)
+ return
+
+ if(is_clockie)
+ if((power_cell.charge < power_cell.maxcharge) && SSthe_ark.clock_power >= POWER_GIVE)
+ target_mech.give_power(power_cell.chargerate)
+ SSthe_ark.clock_power -= POWER_GIVE
+
+ else
+ if(power_cell.charge)
+ target_mech.use_energy(power_cell.chargerate)
+ SSthe_ark.clock_power += POWER_SIPHON
+
+ else if(iscyborg(apply_to))
+ var/mob/living/silicon/robot/borg = apply_to
+ var/obj/item/stock_parts/power_store/cell/power_cell = borg.get_cell()
+
+ if(!power_cell)
+ return
+
+ if(IS_CLOCK(borg))
+ if((power_cell.charge < power_cell.maxcharge) && SSthe_ark.clock_power >= POWER_GIVE)
+ power_cell.give(power_cell.chargerate)
+ SSthe_ark.clock_power -= POWER_GIVE
+
+ else if(power_cell.charge > power_cell.chargerate)
+ power_cell.give(-power_cell.chargerate)
+ SSthe_ark.clock_power += POWER_SIPHON
+
+ else if(ishuman(apply_to))
+ var/mob/living/carbon/human/human = apply_to
+ var/list/human_contents = human.get_contents()
+
+ for(var/obj/item/content_item as anything in human_contents)
+ var/obj/item/stock_parts/power_store/cell/power_cell = content_item.get_cell()
+
+ if(!power_cell)
+ continue
+
+ if(IS_CLOCK(human))
+ if((power_cell.charge < power_cell.maxcharge) && SSthe_ark.clock_power >= POWER_GIVE)
+ power_cell.give(power_cell.chargerate)
+ SSthe_ark.clock_power -= POWER_GIVE
+
+ else
+ if(power_cell.charge > power_cell.chargerate)
+ power_cell.give(-power_cell.chargerate)
+ SSthe_ark.clock_power += POWER_SIPHON
+
+#undef POWER_GIVE
+#undef POWER_SIPHON
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_vitality.dm b/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_vitality.dm
new file mode 100644
index 00000000000..599328088d3
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/sigil/sigil_vitality.dm
@@ -0,0 +1,118 @@
+///how much damage do we heal when reviving someone before costing vitality
+#define FREE_DAMAGE_HEALED 20
+///how much do we reduce drained mobs health by each siphon
+#define HEALTH_DRAINED 15
+/obj/structure/destructible/clockwork/sigil/vitality
+ name = "vitality matrix"
+ desc = "A twisting, confusing artifact that drains the unenlightended on contact."
+ clockwork_desc = "A beautiful artifact that will drain the life of heretics placed on top of it."
+ icon_state = "sigilvitality"
+ effect_stand_time = 2.5 SECONDS // You can't permastun someone with this, so you'll need to keep them grabbed + cuffed
+ idle_color = "#5e87c4"
+ invocation_color = "#83cbe7"
+ pulse_color = "#c761d4"
+ fail_color = "#525a80"
+ looping = TRUE
+
+/obj/structure/destructible/clockwork/sigil/vitality/can_affect(mob/living/affected_mob)
+ if((HAS_TRAIT(affected_mob, TRAIT_HUSK) && !IS_CLOCK(affected_mob)) || HAS_TRAIT(affected_mob, TRAIT_NODEATH) || HAS_TRAIT(affected_mob, TRAIT_NO_SOUL) || HAS_TRAIT(affected_mob, TRAIT_NO_SOUL_BY_VITALITY))
+ return FALSE
+
+ if(!ishuman(affected_mob))
+ return FALSE
+
+ return TRUE
+
+/obj/structure/destructible/clockwork/sigil/vitality/dispel_check(mob/user)
+ . = ..()
+ if(!.)
+ return
+
+ if(active_timer)
+ if(IS_CLOCK(user) && tgui_alert(user, "Are you sure you want to dispel [src]? It is currently siphoning [currently_affecting].", "Confirm dispel", list("Yes", "No")) != "Yes")
+ return FALSE
+ return TRUE
+
+/obj/structure/destructible/clockwork/sigil/vitality/apply_effects(mob/living/affected_mob)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(IS_CLOCK(affected_mob))
+ deltimer(active_timer)
+ active_timer = null
+ var/revived = FALSE
+ if(affected_mob.stat == DEAD)
+ var/damage_healed = FREE_DAMAGE_HEALED + ((affected_mob.getMaxHealth() - affected_mob.health) * 0.6)
+ if(GLOB.clock_vitality >= damage_healed)
+ GLOB.clock_vitality -= damage_healed
+ affected_mob.revive(ADMIN_HEAL_ALL)
+ revived = TRUE
+
+ if(affected_mob.stat != DEAD && (!affected_mob.client || affected_mob.client.is_afk()))
+ set waitfor = FALSE
+ var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
+ "Do you want to play as a [affected_mob.real_name], an inactive clock cultist?",
+ role = ROLE_MIDROUND_CLOCK_CULTIST,
+ poll_time = 5 SECONDS,
+ checked_target = affected_mob,
+ alert_pic = affected_mob,
+ role_name_text = "clock cultist"
+ )
+ if(isnull(chosen_one))
+ visible_message(span_warning("\The [src] fails to revive [affected_mob]!"))
+ fail_invocation()
+ else
+ to_chat(affected_mob.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
+ message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(affected_mob)]) to replace an AFK player.")
+ affected_mob.ghostize(FALSE)
+ affected_mob.PossessByPlayer(chosen_one.key)
+ revived = TRUE
+ if(revived)
+ var/pronoun_appropriate_demonym = "CLOCK-SIBLING"
+ if(affected_mob.gender == MALE)
+ pronoun_appropriate_demonym = "CLOCK-BROTHER"
+ if(affected_mob.gender == FEMALE)
+ pronoun_appropriate_demonym = "CLOCK-SISTER"
+ SEND_SOUND(affected_mob, 'modular_nova/modules/clock_cult/sound/magic/scripture_tier_up.ogg')
+ to_chat(affected_mob, span_bigbrass("\"[text2ratvar("YOUR SERVITUDE IS NOT FINISHED, [uppertext(affected_mob.real_name)]. RISE, [pronoun_appropriate_demonym], AND BE RENEWED.")]\""))
+ affected_mob.visible_message(span_warning("[affected_mob] draws in a huge breath, a bright light shining from [affected_mob.p_their()] eyes."), \
+ span_bigbrass("You awaken suddenly from the void. You're alive!"))
+ return
+
+ affected_mob.Paralyze(1 SECONDS)
+ if(affected_mob.can_adjust_tox_loss(15))
+ affected_mob.adjust_tox_loss(15)
+ else
+ affected_mob.adjust_fire_loss(15)
+ playsound(loc, 'sound/effects/magic/clockwork/ratvar_attack.ogg', 40)
+ if((affected_mob.stat == DEAD))
+ playsound(loc, 'sound/effects/magic/exit_blood.ogg', 60)
+ to_chat(affected_mob, span_clockred("The last of your life is drained away..."))
+ GLOB.clock_vitality = min(GLOB.clock_vitality + 40, MAX_CLOCK_VITALITY) // 100 (for clients) total in the ideal situation, since it'll take 6 pulses to go from full to crit
+ check_special_role(affected_mob)
+ ADD_TRAIT(affected_mob, TRAIT_NO_SOUL_BY_VITALITY, SIGIL_TRAIT)
+ return
+
+ affected_mob.visible_message(span_clockred("[affected_mob] looks weak as the color fades from their body."), span_clockred("You feel your soul faltering..."))
+ GLOB.clock_vitality = min(GLOB.clock_vitality + (affected_mob.client ? 10 : 1), MAX_CLOCK_VITALITY) // Monkey or whatever? You get jackshit
+
+
+/// Checks the role of whoever was killed by the vitality sigil, and does any special code if needed.
+/obj/structure/destructible/clockwork/sigil/vitality/proc/check_special_role(mob/living/affected_mob)
+ if(IS_CULTIST(affected_mob))
+ send_clock_message(null, span_clockred("The dog of Nar'sie, [affected_mob] has had their vitality drained, rejoice!"))
+ GLOB.clock_vitality = min(GLOB.clock_vitality + 20, MAX_CLOCK_VITALITY)
+ affected_mob.mind?.remove_antag_datum(/datum/antagonist/cult)
+ else if(IS_HERETIC(affected_mob))
+ send_clock_message(null, span_clockred("The heretic, [affected_mob] has had their vitality drained, rejoice!"))
+ GLOB.clock_vitality = min(GLOB.clock_vitality + 30, MAX_CLOCK_VITALITY)
+ affected_mob.dust()
+ var/obj/item/mmi/posibrain/soul_vessel/soul_vessel = new(get_turf(src))
+ soul_vessel.transfer_personality(affected_mob)
+ new /obj/item/gun/ballistic/rifle/lionhunter/clockwork(get_turf(src))
+ else
+ send_clock_message(null, span_clockred("[affected_mob] has had their vitality drained by [src], rejoice!"))
+
+#undef FREE_DAMAGE_HEALED
+#undef HEALTH_DRAINED
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/stargazer.dm b/tff_modular/modules/antagonists/clock_cult/structures/stargazer.dm
new file mode 100644
index 00000000000..e9c62cb59df
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/stargazer.dm
@@ -0,0 +1,128 @@
+//Stargazer structure
+/obj/structure/destructible/clockwork/gear_base/stargazer
+ name = "stargazer"
+ desc = "A small pedestal, glowing with a divine energy."
+ clockwork_desc = "Place a weapon upon it to provide special powers and abilities to the weapon."
+ reebe_desc = "The energies of reebe are interfering with it's abilites, making it only be able to to enchant things at the lowest level."
+ icon_state = "stargazer"
+ base_icon_state = "stargazer"
+ anchored = TRUE
+ break_message = span_warning("The stargazer collapses.")
+ ///ref to our visual effect, migtht be able to make this just be an overlay
+ var/obj/effect/stargazer_light/light_effect
+ ///how long is our use cooldown
+ var/stargazer_cooldown = 3 MINUTES
+
+/obj/structure/destructible/clockwork/gear_base/stargazer/Initialize(mapload)
+ . = ..()
+ light_effect = new /obj/effect/stargazer_light(get_turf(src))
+ START_PROCESSING(SSobj, src)
+
+/obj/structure/destructible/clockwork/gear_base/stargazer/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ if(!QDELETED(light_effect))
+ QDEL_NULL(light_effect)
+ return ..()
+
+/obj/structure/destructible/clockwork/gear_base/stargazer/process()
+ if(QDELETED(light_effect))
+ return
+ for(var/mob/living/viewing_mob in viewers(2, get_turf(src)))
+ if(IS_CLOCK(viewing_mob))
+ if(!light_effect.is_open)
+ light_effect.open()
+ return
+ if(light_effect.is_open)
+ light_effect.close()
+
+/obj/structure/destructible/clockwork/gear_base/stargazer/wrench_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(!.)
+ return
+
+ if(anchored && !light_effect)
+ light_effect = new /obj/effect/stargazer_light(get_turf(src))
+ else if(light_effect)
+ QDEL_NULL(light_effect)
+
+/obj/structure/destructible/clockwork/gear_base/stargazer/attackby(obj/item/attacking_item, mob/living/user, params)
+ if(!anchored)
+ to_chat(user, span_brass("You need to anchor \the [src] to the floor first."))
+ return
+
+ if(!enchanting_checks(attacking_item, user))
+ return
+
+ to_chat(user, span_brass("You begin placing \the [attacking_item] onto [src]."))
+ if(do_after(user, 6 SECONDS, src))
+ if(!enchanting_checks(attacking_item, user))
+ return
+
+ if(istype(attacking_item, /obj/item) && (istype(attacking_item, /obj/item/clothing) || attacking_item.force) && upgrade_weapon(attacking_item, user))
+ COOLDOWN_START(src, use_cooldown, stargazer_cooldown)
+ return
+ to_chat(user, span_brass("You cannot upgrade \the [attacking_item]."))
+
+/obj/structure/destructible/clockwork/gear_base/stargazer/proc/enchanting_checks(obj/item/checked_item, mob/living/user)
+ if(!COOLDOWN_FINISHED(src, use_cooldown))
+ to_chat(user, span_brass("\The [src] is still warming up, it will be ready in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown))]."))
+ return FALSE
+
+ if(HAS_TRAIT(checked_item, TRAIT_STARGAZED))
+ to_chat(user, span_brass("\The [checked_item] has already been enchanted!"))
+ return FALSE
+ return TRUE
+
+/obj/structure/destructible/clockwork/gear_base/stargazer/proc/upgrade_weapon(obj/item/upgraded_item, mob/living/user)
+ if(!attempt_enchantment(upgraded_item, description_span = ""))
+ return FALSE
+ //Prevent re-enchanting
+ ADD_TRAIT(upgraded_item, TRAIT_STARGAZED, STARGAZER_TRAIT)
+ //Add a glowy colour
+ upgraded_item.add_atom_colour(rgb(243, 227, 183), ADMIN_COLOUR_PRIORITY)
+ to_chat(user, span_notice("\The [upgraded_item] glows with a brilliant light!"))
+ return TRUE
+
+//The visual effect of the stargazer
+/obj/effect/stargazer_light
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ icon_state = "stargazer_closed"
+ pixel_y = 10
+ layer = ABOVE_OBJ_LAYER
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ alpha = 160
+ ///are we open or closed
+ var/is_open = FALSE
+ ///ref to our timer if we have one
+ var/active_timer
+
+/obj/effect/stargazer_light/ex_act()
+ return
+
+/obj/effect/stargazer_light/Destroy(force)
+ cancel_timer()
+ return ..()
+
+/obj/effect/stargazer_light/proc/finish_opening()
+ icon_state = "stargazer_light"
+ active_timer = null
+
+/obj/effect/stargazer_light/proc/finish_closing()
+ icon_state = "stargazer_closed"
+ active_timer = null
+
+/obj/effect/stargazer_light/proc/open()
+ icon_state = "stargazer_opening"
+ cancel_timer()
+ active_timer = addtimer(CALLBACK(src, PROC_REF(finish_opening)), 2, TIMER_STOPPABLE | TIMER_UNIQUE)
+ is_open = TRUE
+
+/obj/effect/stargazer_light/proc/close()
+ icon_state = "stargazer_closing"
+ cancel_timer()
+ active_timer = addtimer(CALLBACK(src, PROC_REF(finish_closing)), 2, TIMER_STOPPABLE | TIMER_UNIQUE)
+ is_open = FALSE
+
+/obj/effect/stargazer_light/proc/cancel_timer()
+ if(active_timer)
+ deltimer(active_timer)
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/the_ark.dm b/tff_modular/modules/antagonists/clock_cult/structures/the_ark.dm
new file mode 100644
index 00000000000..79aac6ddbbe
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/the_ark.dm
@@ -0,0 +1,251 @@
+GLOBAL_DATUM(clock_ark, /obj/structure/destructible/clockwork/the_ark) //set to be equal to the ark on creation if none
+GLOBAL_VAR_INIT(ratvar_risen, FALSE)
+
+#define ARK_READY_PERIOD 300 SECONDS //how long until the cult is annouced after they reach max members, 5 minutes
+#define ARK_GRACE_PERIOD 210 SECONDS //how long until the portals open after the cult is annouced, 3 minutes 30 seconds
+#define ARK_ASSAULT_PERIOD 600 //how long the crew has to destroy the ark after the assault begins, 10 minutes
+/obj/structure/destructible/clockwork/the_ark
+ name = "\improper Ark of the Clockwork Justiciar"
+ desc = "A massive, hulking amalgamation of parts. It seems to be maintaining a very unstable bluespace anomaly."
+ clockwork_desc = "Nezbere's magnum opus: a hulking clockwork machine capable of combining bluespace and steam power to summon Ratvar. Once activated, \
+ its instability will cause one-way bluespace rifts to open across the station to the City of Cogs, so be prepared to defend it at all costs."
+ max_integrity = 1000
+ icon = 'icons/effects/96x96.dmi'
+ icon_state = "clockwork_gateway_components"
+ pixel_x = -32
+ pixel_y = -32
+ immune_to_servant_attacks = TRUE
+ layer = BELOW_MOB_LAYER
+ can_rotate = FALSE
+ break_message = null
+ break_sound = null
+ debris = null
+ resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
+
+ ///current charge state of the ark
+ var/current_state = ARK_STATE_BASE
+ ///tracker for how long until ratvar is summoned in ARK_STATE_ACTIVE/ARK_STATE_SUMMONING
+ var/charging_for = 0
+
+/obj/structure/destructible/clockwork/the_ark/Initialize(mapload)
+ . = ..()
+ if(!GLOB.clock_ark)
+ GLOB.clock_ark = src
+ SSpoints_of_interest.make_point_of_interest(src)
+
+ if(!SSthe_ark.initialized)
+ SSthe_ark.Initialize()
+
+/obj/structure/destructible/clockwork/the_ark/examine(mob/user)
+ . = ..()
+ if(IS_CLOCK(user) || isobserver(user))
+ switch(current_state)
+ if(ARK_STATE_CHARGING)
+ . += span_brass("The ark has started charging, the crew will soon know our glory!")
+ if(ARK_STATE_ACTIVE)
+ . += span_brass("The ark is opening, [charging_for ? "defend it until ratvar arrives in [ARK_ASSAULT_PERIOD - charging_for] seconds." : "prepare to defend it!"]")
+ if(ARK_STATE_SUMMONING)
+ . += span_brass("Ratvar has nearly arrived, it will only be [ARK_ASSAULT_PERIOD - charging_for] more seconds!")
+ if(user.client?.holder)
+ . += span_warning("ADMIN ONLY WARNING: DELETING THIS WILL END THE ROUND.")
+
+/obj/structure/destructible/clockwork/the_ark/Destroy()
+ if(GLOB.clock_ark == src)
+ GLOB.clock_ark = null
+ if(GLOB.ratvar_risen)
+ return ..()
+ STOP_PROCESSING(SSthe_ark, src)
+ send_clock_message(null, span_bigbrass("The Ark has been destroyed, Reebe is becoming unstable!"))
+ for(var/mob/living/current_mob in GLOB.player_list)
+ if(!on_reebe(current_mob))
+ continue
+ if(IS_CLOCK(current_mob))
+ to_chat(current_mob, span_reallybig(span_clockyellow("Your mind is distorted by the distant sound of a thousand screams. [span_reallybig("YOU HAVE FAILED TO PROTECT MY ARK. \
+ YOU WILL BE TRAPPED HERE WITH ME TO SUFFER FOREVER...")]")))
+ continue
+ current_mob.SetSleeping(5 SECONDS)
+ to_chat(current_mob, span_clockyellow("Your mind is distorted by the distant sound of a thousand screams before suddenly everything falls silent."))
+ to_chat(current_mob, span_hypnophrase("The only thing you remember is suddenly feeling hard ground beneath you and the safety of home."))
+ current_mob.forceMove(find_safe_turf())
+
+ if(GLOB.narsie_breaching_rune)
+ if(istype(GLOB.narsie_breaching_rune, /obj/effect/rune/narsie))
+ new /obj/narsie(get_turf(GLOB.narsie_breaching_rune))
+ else
+ new /obj/narsie(get_safe_random_station_turf())
+
+ INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(explode_reebe))
+ return ..()
+
+/obj/structure/destructible/clockwork/the_ark/Destroy()
+ if(current_state >= ARK_STATE_FINAL)
+ return
+ ASYNC
+ if(!(flags_1 & HOLOGRAM_1))
+ current_state = ARK_STATE_FINAL
+ resistance_flags |= INDESTRUCTIBLE
+ visible_message(span_userdanger("[src] begins to pulse uncontrollably... you might want to run!"))
+ sound_to_playing_players('sound/effects/clockcult_gateway_disrupted.ogg', 50)
+ sleep(2.5 SECONDS)
+ sound_to_playing_players('sound/machines/clockcult/ark_deathrattle.ogg', 50)
+ sleep(2.7 SECONDS)
+ explosion(src, 1, 3, 8, 8)
+ sound_to_playing_players('sound/effects/explosion/explosion_distant.ogg', 50)
+ for(var/obj/effect/portal/clockcult/portal in GLOB.portals)
+ qdel(portal)
+ SSshuttle.clearHostileEnvironment(src)
+ SSsecurity_level.set_level(SEC_LEVEL_RED)
+ qdel(src)
+ return ..()
+
+/obj/structure/destructible/clockwork/the_ark/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration)
+ if(current_state == ARK_STATE_FINAL)
+ return
+
+ . = ..()
+ if(!.)
+ return
+ send_clock_message(null, span_bigbrass("The ark is taking damage!"), sent_sound = 'tff_modular/modules/antagonists/clock_cult/sound/ark_damage.ogg')
+ flick("clockwork_gateway_damaged", src)
+ playsound(src, 'tff_modular/modules/antagonists/clock_cult/sound/ark_damage.ogg', 75, FALSE)
+
+/obj/structure/destructible/clockwork/the_ark/process(seconds_per_tick)
+ if(current_state >= ARK_STATE_FINAL)
+ return
+
+ if(current_state >= ARK_STATE_CHARGING)
+ charging_for = min(charging_for + (seconds_per_tick * DELTA_WORLD_TIME(SSthe_ark)), ARK_ASSAULT_PERIOD)
+
+ if(charging_for >= ARK_ASSAULT_PERIOD)
+ summon_ratvar()
+ return
+
+ if(current_state < ARK_STATE_SUMMONING && charging_for >= (ARK_ASSAULT_PERIOD * 0.5))
+ current_state = ARK_STATE_SUMMONING
+ icon_state = "clockwork_gateway_closing"
+ sound_to_playing_players('tff_modular/modules/antagonists/clock_cult/sound/clockcult_gateway_closing.ogg', 30, TRUE)
+
+ if(current_state >= ARK_STATE_SUMMONING && SPT_PROB(4, seconds_per_tick))
+ send_to_playing_players(span_warning("[pick(list("You feel the fabric of reality twist and bend.", \
+ "Your mind buzzes with fear.", \
+ "You hear otherworldly screams from all around you.", \
+ "You feel reality shudder for a moment...", \
+ "You feel time and space distorting around you..."))]"))
+
+/obj/structure/destructible/clockwork/the_ark/proc/prepare_ark()
+ if(current_state > ARK_STATE_BASE)
+ return
+ current_state = ARK_STATE_CHARGING
+ SSshuttle.registerHostileEnvironment(src)
+ icon_state = "clockwork_gateway_charging"
+ send_clock_message(null, span_bigbrass("The Ark's many cogs suddenly whir to life, steam gushing out of its many crevices; it will open in 5 minutes!"), \
+ sent_sound = 'modular_nova/modules/clock_cult/sound/magic/scripture_tier_up.ogg')
+ addtimer(CALLBACK(src, PROC_REF(open_gateway)), ARK_READY_PERIOD) //MOVE THIS TO A LOOP ON THE ARK SS
+
+/obj/structure/destructible/clockwork/the_ark/proc/open_gateway()
+ if(current_state >= ARK_STATE_GRACE)
+ return
+ current_state = ARK_STATE_GRACE
+ SSshuttle.registerHostileEnvironment(src)
+ icon_state = "clockwork_gateway_active"
+ send_clock_message(null, span_bigbrass("The Ark has been activated, you will be transported soon! Dont forget to gather weapons with your \"Clockwork Armaments\" scripture."), \
+ sent_sound = 'sound/effects/magic/clockwork/ark_activation_sequence.ogg')
+ addtimer(CALLBACK(src, PROC_REF(announce_gateway)), 27 SECONDS)
+
+/obj/structure/destructible/clockwork/the_ark/proc/announce_gateway()
+ send_clock_message(null, span_clockyellow("DESTROY THE HERETICS."), sent_sound = 'tff_modular/modules/antagonists/clock_cult/sound/ark_recall.ogg')
+ sleep(3 SECONDS)
+ current_state = ARK_STATE_ACTIVE
+
+ for(var/datum/mind/servant_mind in GLOB.main_clock_cult.members)
+ var/mob/living/servant_mob = servant_mind.current
+ if(QDELETED(servant_mob))
+ continue
+
+ if(GLOB.abscond_markers)
+ try_servant_warp(servant_mob, get_turf(pick(GLOB.abscond_markers)))
+
+ var/datum/antagonist/clock_cultist/servant_antag = servant_mind.has_antag_datum(/datum/antagonist/clock_cultist)
+ servant_antag?.add_forbearance(servant_mob)
+
+ sound_to_playing_players('sound/effects/magic/clockwork/invoke_general.ogg', 50)
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
+ addtimer(CALLBACK(src, PROC_REF(begin_assault)), ARK_GRACE_PERIOD)
+
+ priority_announce("Massive [Gibberish("bluespace", 100)] anomaly detected on all frequencies. All crew are directed to \
+ @!$, [text2ratvar("PURGE ALL UNTRUTHS")] <&. the anomalies and destroy their source to prevent further damage to corporate property. This is \
+ not a drill. Estimated time of appearance: [ARK_GRACE_PERIOD/10] seconds. Use this time to prepare for an attack on [station_name()]." \
+ ,"Central Command Higher Dimensional Affairs", 'sound/effects/magic/clockwork/ark_activation.ogg')
+
+ sound_to_playing_players('tff_modular/modules/antagonists/clock_cult/sound/clockcult_gateway_charging.ogg', 10, TRUE)
+ log_game("The clock cult has begun opening the Ark of the Clockwork Justiciar.")
+
+/obj/structure/destructible/clockwork/the_ark/proc/begin_assault()
+ START_PROCESSING(SSthe_ark, src)
+ priority_announce("Space-time anomalies detected near the station. Source determined to be a temporal \
+ energy pulse emanating from J1523-215. All crew are to enter [text2ratvar("prep#re %o di%")]\
+ and destroy the [text2ratvar("I'd like to see you try")], which has been determined to be the source of the \
+ pulse to prevent mass damage to Nanotrasen property.", "Anomaly Alert", ANNOUNCER_SPANOMALIES)
+
+ log_game("The opening of the Ark of the Clockwork Justiciar has caused portals to open around the station.")
+ for(var/i in 1 to 100)
+ new /obj/effect/portal/clockcult(get_random_station_turf())
+ sleep(1)
+
+/obj/structure/destructible/clockwork/the_ark/proc/summon_ratvar()
+ if(current_state >= ARK_STATE_FINAL)
+ return
+ current_state = ARK_STATE_FINAL
+ STOP_PROCESSING(SSthe_ark, src)
+ resistance_flags |= INDESTRUCTIBLE
+ send_clock_message(null, span_bigbrass("Ratvar approaches, you shall be eternally rewarded for your servitude!"), msg_ghosts = FALSE)
+ send_to_playing_players(span_warning("You feel time slow down."))
+ GLOB.ratvar_risen = TRUE
+ sound_to_playing_players('tff_modular/modules/antagonists/clock_cult/sound/ratvar_rises.ogg', 100)
+
+ if(GLOB.main_clock_cult)
+ for(var/datum/mind/current_mind in GLOB.main_clock_cult.members)
+ var/mob/living/newgod = current_mind.current
+ if(!newgod)
+ continue
+ ADD_TRAIT(newgod, TRAIT_GODMODE, "ratvar")
+ else
+ stack_trace("Clockwork ark calling summon_ratvar() with no set main_clock_cult.")
+
+ for(var/mob/living/checked_mob as anything in GLOB.player_list)
+ if(on_reebe(checked_mob)) //doing an addtimer to insure these run on time as the ark will be getting qdeled at this time
+ addtimer(CALLBACK(null, GLOBAL_PROC_REF(try_servant_warp), checked_mob, get_safe_random_station_turf()), 12.8 SECONDS)
+
+ var/original_matrix = matrix()
+ animate(src, transform = original_matrix * 1.5, alpha = 255, time = 125)
+ sleep(3 SECONDS)
+ send_to_playing_players(span_warning("You see cracks forming in space around you."))
+ sleep(3 SECONDS)
+ send_to_playing_players(span_warning("You are deafened by the sound of a million screams."))
+ sleep(5.5 SECONDS)
+ send_to_playing_players(span_userdanger("THE JUSTICAR IS HERE."))
+ sleep(1 SECONDS)
+ transform = original_matrix
+ animate(src, transform = original_matrix * 3, alpha = 0, time = 5)
+ QDEL_IN(src, 4)
+ sleep(3)
+ new /obj/ratvar(get_random_station_turf())
+
+/proc/explode_reebe()
+ var/list/reebe_area_list = get_area_turfs(/area/ruin/powered/reebe/city)
+ if(length(reebe_area_list))
+ for(var/i in 1 to 30)
+ explosion(pick(reebe_area_list), 0, 2, 4, 4, FALSE)
+ sleep(5)
+ if(length(GLOB.abscond_markers))
+ explosion(pick(GLOB.abscond_markers), 50, 40, 30, 30, FALSE, TRUE)
+ SSticker.force_ending = TRUE
+
+#undef ARK_READY_PERIOD
+#undef ARK_GRACE_PERIOD
+#undef ARK_ASSAULT_PERIOD
+
+/obj/effect/rune/narsie/Destroy(force)
+ if(src == GLOB.narsie_breaching_rune)
+ GLOB.narsie_breaching_rune = TRUE //we still want to summon even if destroyed
+ return ..()
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/tinkerers_cache.dm b/tff_modular/modules/antagonists/clock_cult/structures/tinkerers_cache.dm
new file mode 100644
index 00000000000..bbc07132edd
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/tinkerers_cache.dm
@@ -0,0 +1,158 @@
+/obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache
+ name = "tinkerer's cache"
+ desc = "A bronze store filled with parts and components."
+ icon_state = "tinkerers_cache"
+ base_icon_state = "tinkerers_cache"
+ clockwork_desc = "Can be used to forge powerful Ratvarian items and traps at the cost of power and time."
+ reebe_desc = "It's connection to the physical realm is weakened from being on reebe, restricting its ability to make certain items."
+ anchored = TRUE
+ break_message = span_warning("The tinkerer's cache melts into a pile of brass.")
+ has_on_icon = FALSE
+ has_off_icon = FALSE
+ has_power_toggle = FALSE
+ /// Assoc list of the names of all the craftable items to their path
+ var/static/list/station_craftable
+ /// Assoc list of items craftable on reebe
+ var/static/list/reebe_craftable
+
+/obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache/Initialize(mapload)
+ . = ..()
+ if(!length(station_craftable) || !length(reebe_craftable))
+ assemble_datum_list()
+
+/obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
+
+ if(!IS_CLOCK(user))
+ to_chat(user, span_warning("You try to put your hand into [src], but almost burn yourself!"))
+ return
+
+ if(!anchored)
+ to_chat(user, span_brass("[src] needs to be anchored to the floor first."))
+ return
+
+ if(!length(transmission_sigils))
+ to_chat(user, span_brass("[src] isn't connected to power!"))
+ return
+
+ if(!COOLDOWN_FINISHED(src, use_cooldown))
+ to_chat(user, span_brass("[src] is still warming up, it will be ready in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown))]."))
+ return
+
+ var/list/valid_list = (on_reebe(src) ? reebe_craftable : reebe_craftable + station_craftable)
+ var/datum/tinker_cache_item/chosen_item = tgui_input_list(user, "Select an item to create at the forge.", "Forging", valid_list)
+ if(!chosen_item)
+ return
+
+ chosen_item = valid_list[chosen_item]
+ if(!can_interact(user) || !anchored || !check_powered() || !chosen_item || !COOLDOWN_FINISHED(src, use_cooldown))
+ return
+
+ if(!length(transmission_sigils))
+ to_chat(user, span_brass("This needs to be connected to a transmission sigil!"))
+ return
+
+ var/amount_to_create = 1
+ if(!chosen_item.time_delay_mult)
+ amount_to_create = tgui_input_number(user, "How many would you like to create?", "Tinkerers Cache", max_value = 10, min_value = 1)
+
+ if(!use_energy(chosen_item.power_use * amount_to_create))
+ to_chat(user, span_brass("You need more power to forge this item."))
+ return
+
+ if(chosen_item.time_delay_mult)
+ COOLDOWN_START(src, use_cooldown, 4 MINUTES * chosen_item.time_delay_mult)
+
+ var/crafting_item = chosen_item.item_path
+ for(var/i in 1 to amount_to_create)
+ new crafting_item(get_turf(src))
+ playsound(src, 'sound/machines/clockcult/steam_whoosh.ogg', 50)
+
+ to_chat(user, span_brass("You craft [chosen_item.name] to near perfection, \the [src] cooling down. \
+ [chosen_item.time_delay_mult ? "It will be available in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown))]." : "It is ready to use again."]"))
+
+// Assemble a list of subtype tinker cache datums
+/obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache/proc/assemble_datum_list()
+ station_craftable = list()
+ reebe_craftable = list()
+ for(var/datum/tinker_cache_item/initial_item as anything in subtypesof(/datum/tinker_cache_item))
+ initial_item = new initial_item
+ (!initial_item.allowed_on_reebe ? station_craftable : reebe_craftable)["[initial_item.name] ([initial_item.power_use] W)"] = initial_item
+
+// This used to be a hardcoded list
+/datum/tinker_cache_item
+ /// Name of the item
+ var/name = "abstract parent"
+ /// Path to the object that this will create
+ var/item_path
+ /// Amount of power this will consume to create
+ var/power_use = 0
+ /// Multiplier for time delay (default 4m) after producing this item
+ var/time_delay_mult = 1
+ /// Is this item able to be fabricated on reebe
+ var/allowed_on_reebe = TRUE
+
+/datum/tinker_cache_item/speed_robes
+ name = "Robes Of Divinity"
+ item_path = /obj/item/clothing/suit/clockwork/speed
+ power_use = 300
+ allowed_on_reebe = FALSE
+
+/datum/tinker_cache_item/invis_cloak
+ name = "Shrouding Cloak"
+ item_path = /obj/item/clothing/suit/clockwork/cloak
+ power_use = 300
+ allowed_on_reebe = FALSE
+
+/datum/tinker_cache_item/sight_goggles
+ name = "Wraith Spectacles"
+ item_path = /obj/item/clothing/glasses/clockwork/wraith_spectacles
+ power_use = 400
+ allowed_on_reebe = FALSE
+
+/datum/tinker_cache_item/hud_visor
+ name = "Judicial Visor"
+ item_path = /obj/item/clothing/glasses/clockwork/judicial_visor
+ power_use = 400
+ allowed_on_reebe = FALSE
+
+/datum/tinker_cache_item/replica_fabricator
+ name = "Replica Fabricator"
+ item_path = /obj/item/clockwork/replica_fabricator
+ power_use = 400
+
+/datum/tinker_cache_item/clockwork_slab
+ name = "Clockwork Slab"
+ item_path = /obj/item/clockwork/clockwork_slab
+ power_use = 100
+ time_delay_mult = 0.5
+
+/datum/tinker_cache_item/tools
+ name = "Equipped Toolbelt"
+ item_path = /obj/item/storage/belt/utility/clock
+ power_use = 150
+ time_delay_mult = 0.75
+
+/datum/tinker_cache_item/trap
+ name = "Flipper (Trap)"
+ item_path = /obj/item/clockwork/trap_placer/flipper
+ power_use = 50
+ time_delay_mult = 0
+
+/datum/tinker_cache_item/trap/skewer
+ name = "Skewer (Trap)"
+ item_path = /obj/item/clockwork/trap_placer/skewer
+
+/datum/tinker_cache_item/trap/delay
+ name = "Delayer (Trigger)"
+ item_path = /obj/item/wallframe/clocktrap/delay
+
+/datum/tinker_cache_item/trap/lever
+ name = "Lever (Trigger)"
+ item_path = /obj/item/wallframe/clocktrap/lever
+
+/datum/tinker_cache_item/trap/pressure
+ name = "Pressure Sensor (Trigger)"
+ item_path = /obj/item/clockwork/trap_placer/pressure_sensor
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/traps/recievers/flipper.dm b/tff_modular/modules/antagonists/clock_cult/structures/traps/recievers/flipper.dm
new file mode 100644
index 00000000000..1d943aa34a4
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/traps/recievers/flipper.dm
@@ -0,0 +1,60 @@
+#define FLIP_DISTANCE 6
+#define FLIP_SPEED 3
+
+/obj/item/clockwork/trap_placer/flipper
+ name = "flipper"
+ desc = "A steam powered rotating floor panel. When input is received it will fling anyone on top of it."
+ icon_state = "pressure_sensor"
+ result_path = /obj/structure/destructible/clockwork/trap/flipper
+ clockwork_desc = "A floor panel capable of flinging anyone back when triggered."
+
+/obj/structure/destructible/clockwork/trap/flipper
+ name = "flipper"
+ desc = "A steam powered rotating floor panel. When input is received it will fling anyone on top of it."
+ icon_state = "flipper"
+ component_datum = /datum/component/clockwork_trap/flipper
+ unwrench_path = /obj/item/clockwork/trap_placer/flipper
+ clockwork_desc = "A floor panel capable of flinging anyone back when triggered. However, it does have a cooldown between uses."
+ COOLDOWN_DECLARE(flip_cooldown)
+ /// Time between possible flips
+ var/cooldown_flip = 10 SECONDS
+
+/obj/structure/destructible/clockwork/trap/flipper/examine(mob/user)
+ . = ..()
+
+ if(!COOLDOWN_FINISHED(src, flip_cooldown) && IS_CLOCK(user))
+ . += span_brass("It's not ready to activate again yet!")
+
+/// Send all `atom/movable`s flying in the set direction for a decent distance
+/obj/structure/destructible/clockwork/trap/flipper/proc/flip()
+ if(!COOLDOWN_FINISHED(src, flip_cooldown))
+ return
+
+ COOLDOWN_START(src, flip_cooldown, cooldown_flip)
+ addtimer(CALLBACK(src, PROC_REF(cooldown_done)), cooldown_flip)
+
+ flick("flipping", src)
+
+ for(var/atom/movable/movable_atom in get_turf(src))
+
+ if(movable_atom.anchored)
+ continue
+
+ movable_atom.throw_at(get_edge_target_turf(src, dir), FLIP_DISTANCE, FLIP_SPEED)
+
+/// Visual update when the cooldown's finished
+/obj/structure/destructible/clockwork/trap/flipper/proc/cooldown_done()
+ visible_message(span_brass("[src] whirrs with a loud *CLANK* as it resets."))
+
+/datum/component/clockwork_trap/flipper
+ takes_input = TRUE
+
+/datum/component/clockwork_trap/flipper/trigger()
+ if(!..())
+ return
+
+ var/obj/structure/destructible/clockwork/trap/flipper/flipper_parent = parent
+ flipper_parent.flip()
+
+#undef FLIP_DISTANCE
+#undef FLIP_SPEED
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/traps/recievers/skewer.dm b/tff_modular/modules/antagonists/clock_cult/structures/traps/recievers/skewer.dm
new file mode 100644
index 00000000000..3aaa3850e3b
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/traps/recievers/skewer.dm
@@ -0,0 +1,123 @@
+#define SKEWER_DAMAGE 15
+#define SKEWER_BLEED 30
+
+
+/obj/item/clockwork/trap_placer/skewer
+ name = "brass skewer"
+ desc = "A spiked, brass skewer attached to a steam powered extension mechanism."
+ icon_state = "brass_skewer_extended"
+ result_path = /obj/structure/destructible/clockwork/trap/skewer
+ clockwork_desc = "A skewer that can pierce through a target, activated by a linked trigger."
+
+/obj/structure/destructible/clockwork/trap/skewer
+ name = "brass skewer"
+ desc = "A spiked, brass skewer attached to a steam powered extension mechanism."
+ icon_state = "brass_skewer"
+ component_datum = /datum/component/clockwork_trap/skewer
+ unwrench_path = /obj/item/clockwork/trap_placer/skewer
+ buckle_lying = FALSE
+ max_integrity = 20
+ clockwork_desc = "A skewer that can pierce through a target, activated by a linked trigger."
+ COOLDOWN_DECLARE(stab_cooldown)
+ /// If the spear is currently extended
+ var/extended = FALSE
+ /// Mutable appearance stab overlay
+ var/mutable_appearance/stab_overlay
+
+/datum/armor/raised_clock_skewer
+ laser = 30
+ melee = 50
+ bullet = 40
+ energy = 30
+
+/// Stab any non-clock mobs who stood on the tile
+/obj/structure/destructible/clockwork/trap/skewer/proc/stab()
+ if(extended)
+ retract()
+ return
+
+ if(!COOLDOWN_FINISHED(src, stab_cooldown))
+ return
+
+ COOLDOWN_START(src, stab_cooldown, 10 SECONDS)
+ extended = TRUE
+ icon_state = "[initial(icon_state)]_extended"
+ var/target_stabbed = FALSE
+ density = TRUE
+ set_armor(/datum/armor/raised_clock_skewer)
+
+ for(var/mob/living/stabbed_mob in get_turf(src))
+ if(stabbed_mob.incorporeal_move || (stabbed_mob.movement_type & (FLOATING|FLYING)))
+ continue
+
+ if(IS_CLOCK(stabbed_mob))
+ to_chat(stabbed_mob, span_warning("You dodge out of the way of [src]!"))
+ continue
+
+ if(!buckle_mob(stabbed_mob, TRUE))
+ continue
+
+ target_stabbed = TRUE
+ to_chat(stabbed_mob, span_userdanger("You are impaled by [src]!"))
+ stabbed_mob.emote("scream")
+ stabbed_mob.apply_damage(SKEWER_DAMAGE, BRUTE, BODY_ZONE_CHEST)
+
+ if(ishuman(stabbed_mob))
+ var/mob/living/carbon/human/stabbed_human = stabbed_mob
+ stabbed_human.bleed(SKEWER_BLEED)
+
+ if(target_stabbed)
+ if(!stab_overlay)
+ stab_overlay = mutable_appearance('tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi', "brass_skewer_pokeybit", layer = ABOVE_MOB_LAYER)
+
+ add_overlay(stab_overlay)
+
+
+/obj/structure/destructible/clockwork/trap/skewer/unbuckle_mob(mob/living/buckled_mob, force, can_fall)
+ if(force)
+ return ..()
+
+ if(!buckled_mob.break_do_after_checks())
+ return
+
+ balloon_alert(buckled_mob, "climbing off of [src]...")
+
+ if(!do_after(buckled_mob, 5 SECONDS, target = src))
+ balloon_alert(buckled_mob, "failed to climb off [src]")
+ return
+
+ return ..()
+
+
+/obj/structure/destructible/clockwork/trap/skewer/post_unbuckle_mob(mob/living/stabbed_mob)
+ if(!has_buckled_mobs())
+ cut_overlay(stab_overlay)
+
+
+/// Unbuckling mobs and reverting the trap for when the pokey bit goes back in
+/obj/structure/destructible/clockwork/trap/skewer/proc/retract()
+ extended = FALSE
+ icon_state = initial(icon_state)
+ density = FALSE
+ cut_overlay(stab_overlay)
+ set_armor(null)
+ for(var/mob/living/stabbed_mob as anything in buckled_mobs)
+ unbuckle_mob(stabbed_mob, TRUE)
+
+
+/datum/component/clockwork_trap/skewer
+ takes_input = TRUE
+
+
+/datum/component/clockwork_trap/skewer/trigger()
+ if(!..())
+ return
+
+ var/obj/structure/destructible/clockwork/trap/skewer/trap = parent
+ if(!istype(trap))
+ return
+
+ INVOKE_ASYNC(trap, TYPE_PROC_REF(/obj/structure/destructible/clockwork/trap/skewer, stab))
+
+#undef SKEWER_DAMAGE
+#undef SKEWER_BLEED
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/delay.dm b/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/delay.dm
new file mode 100644
index 00000000000..462759d0957
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/delay.dm
@@ -0,0 +1,48 @@
+/obj/item/wallframe/clocktrap/delay
+ name = "clockwork timer"
+ desc = "A small, detached timer."
+ icon_state = "delayer"
+ result_path = /obj/structure/destructible/clockwork/trap/delay
+ clockwork_desc = "A device that can be attached to walls. When input is received, it will send an output signal a configurable (with multitool) time later."
+
+
+/obj/structure/destructible/clockwork/trap/delay
+ name = "clockwork timer"
+ desc = "A small timer attatched to the wall."
+ icon_state = "delayer"
+ component_datum = /datum/component/clockwork_trap/delay
+ unwrench_path = /obj/item/wallframe/clocktrap/delay
+ max_integrity = 15
+ clockwork_desc = "When input is received, it will send an output signal a configurable (with multitool) amount of time later."
+ /// How much time the signal is delayed
+ var/delay_time = 1 SECONDS
+
+
+
+/obj/structure/destructible/clockwork/trap/delay/multitool_act(mob/living/user, obj/item/tool)
+ delay_time = tgui_input_number(user, "Input delay time", "Clockwork Timer", 1 SECONDS, 120 SECONDS, 1 SECONDS)
+ return TRUE
+
+
+/datum/component/clockwork_trap/delay
+ takes_input = TRUE
+ sends_input = TRUE
+ /// If the trap is active or not
+ var/active = FALSE
+
+
+/datum/component/clockwork_trap/delay/trigger()
+ if(!..() || active)
+ return
+
+ active = TRUE
+ flick("delayer_active", parent)
+
+ var/obj/structure/destructible/clockwork/trap/delay/parent_delayer = parent
+ addtimer(CALLBACK(src, PROC_REF(finish)), parent_delayer.delay_time)
+
+
+/// Finish the delay, trigger any traps
+/datum/component/clockwork_trap/delay/proc/finish()
+ active = FALSE
+ trigger_connected()
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/lever.dm b/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/lever.dm
new file mode 100644
index 00000000000..7dd5926bb85
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/lever.dm
@@ -0,0 +1,26 @@
+/obj/item/wallframe/clocktrap/lever
+ name = "switch"
+ desc = "A small switch attatched to the wall."
+ icon_state = "lever"
+ result_path = /obj/structure/destructible/clockwork/trap/lever
+ clockwork_desc = "A device that can be attached to walls to allow you to send a signal to linked traps."
+
+
+/obj/structure/destructible/clockwork/trap/lever
+ name = "switch"
+ desc = "A small switch attatched to the wall."
+ icon_state = "lever"
+ unwrench_path = /obj/item/wallframe/clocktrap/lever
+ component_datum = /datum/component/clockwork_trap/lever
+ max_integrity = 75
+ clockwork_desc = "A device allows you to send a signal to linked traps."
+
+
+/datum/component/clockwork_trap/lever
+ sends_input = TRUE
+
+
+/datum/component/clockwork_trap/lever/attack_hand(mob/user)
+ trigger_connected()
+ to_chat(user, span_notice("You activate the switch."))
+ playsound(user, 'sound/machines/click.ogg', 50)
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/pressure_sensor.dm b/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/pressure_sensor.dm
new file mode 100644
index 00000000000..b4dc211ced0
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/traps/senders/pressure_sensor.dm
@@ -0,0 +1,45 @@
+/obj/item/clockwork/trap_placer/pressure_sensor
+ name = "pressure plate"
+ desc = "I wonder what happens if you step on it."
+ icon_state = "pressure_sensor"
+ result_path = /obj/structure/destructible/clockwork/trap/pressure_sensor
+ clockwork_desc = "Allows you to send a signal to linked traps when a non-servant steps on the plate."
+
+
+/obj/structure/destructible/clockwork/trap/pressure_sensor
+ name = "pressure plate"
+ desc = "I wonder what happens if you step on it."
+ icon_state = "pressure_sensor"
+ unwrench_path = /obj/item/clockwork/trap_placer/pressure_sensor
+ component_datum = /datum/component/clockwork_trap/pressure_sensor
+ alpha = 60
+ layer = 2.53
+ max_integrity = 5
+ clockwork_desc = "Allows you to send a signal to linked traps when a non-servant steps on the plate."
+
+
+/datum/component/clockwork_trap/pressure_sensor
+ sends_input = TRUE
+
+
+/datum/component/clockwork_trap/pressure_sensor/Initialize()
+ . = ..()
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
+ )
+ AddComponent(/datum/component/connect_loc_behalf, parent, loc_connections)
+
+/// Trigger all connected traps now that someone's stepped on the tile
+/datum/component/clockwork_trap/pressure_sensor/proc/on_entered(datum/source, atom/movable/entered_movable)
+ SIGNAL_HANDLER
+
+ //Items in hands or boxes shouldn't trigger it
+ if(!isturf(entered_movable.loc) || !isliving(entered_movable))
+ return
+
+ var/mob/living/entered_living = entered_movable
+ if(IS_CLOCK(entered_living) || entered_living.incorporeal_move || (entered_living.movement_type & (FLOATING|FLYING)))
+ return
+
+ trigger_connected()
+ playsound(parent, 'sound/machines/click.ogg', 50)
diff --git a/tff_modular/modules/antagonists/clock_cult/structures/traps/trap.dm b/tff_modular/modules/antagonists/clock_cult/structures/traps/trap.dm
new file mode 100644
index 00000000000..3e4799c854b
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/structures/traps/trap.dm
@@ -0,0 +1,182 @@
+//might be able to refactor these into mech comp stuff
+//Thing that you stick on the floor
+/obj/item/clockwork/trap_placer
+ name = "trap"
+ desc = "don't trust it"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+ /// The path of the trap to make when this is set down
+ var/result_path = /obj/structure/destructible/clockwork/trap
+
+
+/obj/item/clockwork/trap_placer/attack_self(mob/user)
+ . = ..()
+ if(!IS_CLOCK(user))
+ return
+
+ if(user.loc != get_turf(src))
+ return
+
+ place_trap(get_turf(src), user)
+
+/obj/item/clockwork/trap_placer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(!IS_CLOCK(user) || !isturf(interacting_with))
+ return NONE
+
+ place_trap(interacting_with, user)
+ return ITEM_INTERACT_SUCCESS
+
+
+/obj/item/clockwork/trap_placer/proc/place_trap(atom/target, mob/user)
+ for(var/obj/structure/destructible/clockwork/trap/trap in target) // No 50-spear instakills please
+
+ if(!istype(trap, result_path))
+ continue
+
+ user.balloon_alert(user, "space occupied!")
+ return
+
+ to_chat(user, span_brass("You place [src], use a clockwork slab to link it to other traps."))
+ var/obj/new_obj = new result_path(target)
+ new_obj.setDir(user.dir)
+
+ qdel(src)
+
+//Thing you stick on the wall
+/obj/item/wallframe/clocktrap
+ name = "clockwork trap item"
+ desc = "It's a... Wait what?"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ pixel_shift = 24
+ w_class = WEIGHT_CLASS_SMALL
+ result_path = /obj/structure/destructible/clockwork/trap
+ /// What to show the user if they are a clock cultist
+ var/clockwork_desc = "It seems to be able to be placed on walls."
+
+/obj/item/wallframe/clocktrap/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/clockwork_description, clockwork_desc)
+
+/obj/item/wallframe/clocktrap/try_build(turf/on_wall, mob/user)
+ if(get_dist(on_wall, user) > 1)
+ balloon_alert(user, "you are too far!")
+ return
+
+ var/floor_to_wall = get_dir(user, on_wall)
+ if(!(floor_to_wall in GLOB.cardinals))
+ balloon_alert(user, "stand in line with wall!")
+ return
+
+ var/turf/user_turf = get_turf(user)
+ if(!isopenturf(user_turf))
+ balloon_alert(user, "cannot place here!")
+ return
+
+ if(check_wall_item(user_turf, floor_to_wall, wall_external))
+ balloon_alert(user, "already something here!")
+ return
+
+ return TRUE
+
+//Wall item (either spawned by a wallframe or directly)
+/obj/structure/destructible/clockwork/trap
+ name = "clockwork trap item"
+ desc = "Probably doesn't do much."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ density = FALSE
+ layer = LOW_OBJ_LAYER
+ break_message = span_warning("The intricate looking device falls apart.")
+ /// What item's produced when this structure is unwrenched
+ var/unwrench_path = /obj/item/wallframe/clocktrap
+ /// The component used for the trap's back-end
+ var/component_datum = /datum/component/clockwork_trap
+
+/obj/structure/destructible/clockwork/trap/Initialize(mapload)
+ . = ..()
+ AddComponent(component_datum)
+
+/obj/structure/destructible/clockwork/trap/wrench_act(mob/living/user, obj/item/I)
+ . = ..()
+ balloon_alert(user, "unwrenching...")
+
+ if(!do_after(user, 5 SECONDS, target = src))
+ return
+
+ balloon_alert(user, "detached [src]")
+ new unwrench_path(get_turf(src))
+
+ qdel(src)
+
+//Component
+/datum/component/clockwork_trap
+ /// A list of traps this sends a signal to when this is triggered
+ var/list/outputs = list()
+ /// If this sends input (e.g. pressure plate)
+ var/sends_input = FALSE
+ /// If this takes input (e.g. skewer)
+ var/takes_input = FALSE
+
+/datum/component/clockwork_trap/Initialize()
+ . = ..()
+
+ if(!istype(parent, /obj/structure/destructible/clockwork))
+ return COMPONENT_INCOMPATIBLE
+
+ RegisterSignal(parent, COMSIG_CLOCKWORK_SIGNAL_RECEIVED, PROC_REF(trigger))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(attack_hand))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
+
+/// Adds an input device to our own `outputs` list, to be sent when it triggers
+/datum/component/clockwork_trap/proc/add_input(datum/component/clockwork_trap/input)
+ outputs |= input.parent
+
+/// Adds this as an output to the targeted component's `outputs` list
+/datum/component/clockwork_trap/proc/add_output(datum/component/clockwork_trap/output)
+ output.outputs |= parent
+
+/// Signal proc for when the trap calls CLOCKWORK_SIGNAL_RECEIVED
+/datum/component/clockwork_trap/proc/trigger()
+ SIGNAL_HANDLER
+
+ return TRUE
+
+/// Signal proc for when the trap has ATOM_ATTACK_HAND called on it
+/datum/component/clockwork_trap/proc/attack_hand(mob/user)
+ SIGNAL_HANDLER
+
+ return
+
+/// Signal proc when the trap has PARENT_ATTACKBY called on it
+/datum/component/clockwork_trap/proc/on_attackby(datum/source, obj/item/attack_item, mob/user)
+ SIGNAL_HANDLER
+
+ if(!IS_CLOCK(user) || !istype(attack_item, /obj/item/clockwork/clockwork_slab))
+ return
+
+ var/obj/item/clockwork/clockwork_slab/slab = attack_item
+
+ if(slab.buffer)
+
+ if(takes_input)
+ to_chat(user, span_brass("You connect [slab.buffer.parent] to [parent]."))
+ add_output(slab.buffer)
+ slab.buffer = null
+
+ else
+ to_chat(user, span_brass("That device does not accept input."))
+
+ else
+
+ if(sends_input)
+ to_chat(user, span_brass("You prepare to connect [parent] with other devices."))
+ slab.buffer = src
+
+ else
+
+ to_chat(user, span_brass("That device does not output anything."))
+
+/// Sends a signal to activate to every outputting component in `outputs`
+/datum/component/clockwork_trap/proc/trigger_connected()
+ for(var/datum/output as anything in outputs) //must be typecasted because of how SEND_SIGNAL works
+
+ SEND_SIGNAL(output, COMSIG_CLOCKWORK_SIGNAL_RECEIVED)
diff --git a/tff_modular/modules/antagonists/clock_cult/temp_visual.dm b/tff_modular/modules/antagonists/clock_cult/temp_visual.dm
new file mode 100644
index 00000000000..30bcdefc2b5
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/temp_visual.dm
@@ -0,0 +1,221 @@
+#define MENDING_MANTRA_SCALE 2
+
+//temporary visual effects(/obj/effect/temp_visual) used by clock stuff
+/obj/effect/temp_visual/ratvar
+ name = "ratvar's light"
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi'
+ duration = 8
+ randomdir = FALSE
+ layer = ABOVE_NORMAL_TURF_LAYER
+
+
+/obj/effect/temp_visual/ratvar/door
+ icon_state = "ratvardoorglow"
+ layer = CLOSED_DOOR_LAYER //above closed doors
+
+
+/obj/effect/temp_visual/ratvar/door/window
+ icon_state = "ratvarwindoorglow"
+ layer = ABOVE_WINDOW_LAYER
+
+
+/obj/effect/temp_visual/ratvar/beam
+ icon_state = "ratvarbeamglow"
+
+
+/obj/effect/temp_visual/ratvar/beam/door
+ layer = CLOSED_DOOR_LAYER
+
+
+/obj/effect/temp_visual/ratvar/beam/grille
+ layer = BELOW_OBJ_LAYER
+
+
+/obj/effect/temp_visual/ratvar/beam/itemconsume
+ layer = HIGH_OBJ_LAYER
+
+
+/obj/effect/temp_visual/ratvar/beam/falsewall
+ layer = OBJ_LAYER
+
+
+/obj/effect/temp_visual/ratvar/beam/catwalk
+ layer = LATTICE_LAYER
+
+
+/obj/effect/temp_visual/ratvar/wall
+ icon_state = "ratvarwallglow"
+
+
+/obj/effect/temp_visual/ratvar/wall/false
+ layer = OBJ_LAYER
+
+
+/obj/effect/temp_visual/ratvar/floor
+ icon_state = "ratvarfloorglow"
+
+
+/obj/effect/temp_visual/ratvar/floor/catwalk
+ layer = LATTICE_LAYER
+
+
+/obj/effect/temp_visual/ratvar/window
+ icon_state = "ratvarwindowglow"
+ layer = ABOVE_OBJ_LAYER
+
+
+/obj/effect/temp_visual/ratvar/window/single
+ icon_state = "ratvarwindowglow_s"
+
+
+/obj/effect/temp_visual/ratvar/gear
+ icon_state = "ratvargearglow"
+ layer = BELOW_OBJ_LAYER
+
+
+/obj/effect/temp_visual/ratvar/grille
+ icon_state = "ratvargrilleglow"
+ layer = BELOW_OBJ_LAYER
+
+
+/obj/effect/temp_visual/ratvar/grille/broken
+ icon_state = "ratvarbrokengrilleglow"
+
+
+/obj/effect/temp_visual/ratvar/belligerent
+ layer = ABOVE_MOB_LAYER
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ icon_state = "belligerent_eye"
+ pixel_y = 20
+ duration = 2 SECONDS
+
+
+/obj/effect/temp_visual/ratvar/belligerent/Initialize(mapload)
+ . = ..()
+ animate(src, alpha = 0, time = duration, easing = EASE_OUT)
+
+
+/obj/effect/temp_visual/ratvar/mending_mantra
+ layer = ABOVE_MOB_LAYER
+ duration = 2 SECONDS
+ alpha = 200
+ icon_state = "mending_mantra"
+ light_range = 1.5
+ light_color = "#1E8CE1"
+
+
+/obj/effect/temp_visual/ratvar/mending_mantra/Initialize(mapload)
+ . = ..()
+ transform = matrix() * MENDING_MANTRA_SCALE
+ var/matrix/mantra_matrix = transform
+ mantra_matrix.Turn(90)
+ animate(src, alpha = 20, time = duration, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
+ animate(src, transform = mantra_matrix, time = duration, flags = ANIMATION_PARALLEL)
+
+
+/obj/effect/temp_visual/ratvar/ocular_warden
+ name = "warden's gaze"
+ layer = ABOVE_MOB_LAYER
+ icon_state = "warden_gaze"
+ duration = 3
+
+
+/obj/effect/temp_visual/ratvar/ocular_warden/Initialize(mapload)
+ . = ..()
+ pixel_x = rand(-8, 8)
+ pixel_y = rand(-10, 10)
+ animate(src, alpha = 0, time = duration, easing = EASE_OUT)
+
+/obj/effect/temp_visual/ratvar/component
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_objects.dmi'
+ icon_state = "belligerent_eye"
+ layer = ABOVE_MOB_LAYER
+ duration = 1 SECONDS
+
+
+/obj/effect/temp_visual/ratvar/component/Initialize(mapload)
+ . = ..()
+ transform = matrix() * 0.75
+ pixel_x = rand(-10, 10)
+ pixel_y = rand(-10, -2)
+ animate(src, pixel_y = pixel_y + 10, alpha = 50, time = 1 SECONDS, easing = EASE_OUT)
+
+
+/obj/effect/temp_visual/ratvar/component/cogwheel
+ icon_state = "vanguard_cogwheel"
+
+
+/obj/effect/temp_visual/ratvar/component/capacitor
+ icon_state = "geis_capacitor"
+
+
+/obj/effect/temp_visual/ratvar/component/alloy
+ icon_state = "replicant_alloy"
+
+
+/obj/effect/temp_visual/ratvar/component/ansible
+ icon_state = "hierophant_ansible"
+
+
+/obj/effect/temp_visual/ratvar/warp
+ name = "spatial distortion"
+ icon_state = "teleport"
+ layer = ABOVE_MOB_LAYER
+
+
+/obj/effect/temp_visual/steam
+ name = "steam"
+ desc = "Steam! It's hot. It also serves as a game distribution platform."
+ icon_state = "smoke"
+ duration = 1.5 SECONDS
+
+
+/obj/effect/temp_visual/steam/Initialize(mapload, steam_direction)
+ . = ..()
+ setDir(steam_direction)
+ var/x_offset = 0
+ var/y_offset = 0
+ switch(dir)
+ if(NORTH)
+ y_offset = 8
+
+ if(EAST)
+ x_offset = 4
+ y_offset = 4
+
+ if(SOUTH)
+ y_offset = 2
+
+ if(WEST)
+ x_offset = -4
+ y_offset = 4
+
+ animate(src, pixel_x = x_offset, pixel_y = y_offset, alpha = 50, time = 1.5 SECONDS)
+
+
+/obj/effect/temp_visual/steam_release
+ name = "all the steam"
+
+/obj/effect/temp_visual/steam_release/Initialize(mapload)
+ . = ..()
+ for(var/cardinal in GLOB.cardinals)
+ var/turf/cardinal_step = get_step(src, cardinal)
+ new/obj/effect/temp_visual/steam(cardinal_step, cardinal)
+
+ playsound(src, 'sound/machines/clockcult/steam_whoosh.ogg', 30)
+ return INITIALIZE_HINT_QDEL
+
+/obj/effect/temp_visual/ratvar/constructing_effect
+ icon_state = "replica_fabricator_create"
+ layer = ABOVE_ALL_MOB_LAYER
+ plane = ABOVE_GAME_PLANE
+ anchored = TRUE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ duration = 1 SECONDS
+
+/obj/effect/temp_visual/ratvar/constructing_effect/Initialize(mapload, create_delay)
+ duration = create_delay
+ return ..()
+
+
+#undef MENDING_MANTRA_SCALE
diff --git a/tff_modular/modules/antagonists/clock_cult/turf_checker.dm b/tff_modular/modules/antagonists/clock_cult/turf_checker.dm
new file mode 100644
index 00000000000..4e04884fdd6
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/turf_checker.dm
@@ -0,0 +1,202 @@
+/*
+//a simple element that listens for passed signals and then returns based on if get_turf's type is within valid_turfs, if you need more then use the /complex subtype
+/datum/component/turf_checker
+ dupe_mode = COMPONENT_DUPE_ALLOWED
+ ///list of turf types that are valid for us
+ var/list/valid_turfs
+ ///the signal we listen for
+ var/registered_signal
+ ///do we listen for COMSIG_MOVABLE_MOVED
+ var/check_on_move
+ ///our last validity state, used to save on checks
+ var/last_validity_state = FALSE
+ ///a ref to the loc that we listen to the movement of to send our signals
+ var/atom/watched_holder
+ ///our parent's recursive locs minus it and watched_holder
+ var/list/trimmed_recursive_locs
+
+/**
+ * valid_turfs - the list of turf types that are valid for when we check
+ * registered_signal - the signal from parent we listen for to call on_signal_recieved()
+ * check_on_move - should we check turf every time our parent calls Moved()
+ * update_state_proc - proc for parent to call when we send COMSIG_TURF_CHECKER_UPDATE_STATE
+ * register_loc - should we listen to Moved() on locs of our parent as well
+ */
+/datum/component/turf_checker/Initialize(list/valid_turfs, registered_signal, check_on_move = FALSE, update_state_proc, register_loc = TRUE)
+ if(!ismovable(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ src.valid_turfs = valid_turfs
+ src.registered_signal = registered_signal
+ src.check_on_move = check_on_move
+ if(update_state_proc && check_on_move)
+ parent.RegisterSignal(src, COMSIG_TURF_CHECKER_UPDATE_STATE, update_state_proc)
+
+/datum/component/turf_checker/RegisterWithParent()
+ if(registered_signal)
+ RegisterSignal(parent, registered_signal, PROC_REF(on_signal_recieved))
+
+ if(check_on_move)
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_attached_moved))
+ trimmed_recursive_locs = list()
+ get_new_locs(parent)
+ check_turf(parent)
+
+/datum/component/turf_checker/UnregisterFromParent()
+ if(registered_signal)
+ UnregisterSignal(parent, registered_signal)
+
+ if(check_on_move)
+ parent.UnregisterSignal(src, COMSIG_TURF_CHECKER_UPDATE_STATE)
+ UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)
+
+ if(watched_holder != parent)
+ UnregisterSignal(watched_holder, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING, COMSIG_ATOM_ABSTRACT_EXITED))
+
+ for(var/atom/recursive_loc in trimmed_recursive_locs)
+ UnregisterSignal(recursive_loc, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING))
+
+/datum/component/turf_checker/proc/on_signal_recieved(atom/movable/checked_atom, atom/movable/check_override, do_check_turf = TRUE, register_to, unregister_from)
+ SIGNAL_HANDLER
+ if(register_to) //keeping these here in case your use case can handle this on the attached atom in a cheaper way than the /complex subtype
+ RegisterSignal(register_to, COMSIG_MOVABLE_MOVED, PROC_REF(check_turf_parent_only))
+
+ if(unregister_from)
+ UnregisterSignal(unregister_from, COMSIG_MOVABLE_MOVED)
+
+ if(do_check_turf)
+ return check_turf(checked_atom, check_override)
+
+//so we dont override checked_atom with old_loc
+/datum/component/turf_checker/proc/check_turf_parent_only(atom/movable/checked_atom)
+ SIGNAL_HANDLER
+ check_turf(checked_atom)
+
+/datum/component/turf_checker/proc/check_turf(atom/movable/checked_atom, atom/movable/check_override)
+ SIGNAL_HANDLER
+ if(check_override)
+ checked_atom = check_override
+
+ var/turf/checked_turf_type = get_turf(checked_atom)
+ if(!checked_turf_type)
+ return COMPONENT_CHECKER_INVALID_TURF
+
+ checked_turf_type = checked_turf_type.type
+ if(!(checked_turf_type in valid_turfs))
+ if(check_on_move && last_validity_state)
+ last_validity_state = FALSE
+ SEND_SIGNAL(src, COMSIG_TURF_CHECKER_UPDATE_STATE, FALSE, checked_atom)
+ return COMPONENT_CHECKER_INVALID_TURF
+
+ if(check_on_move && !last_validity_state)
+ last_validity_state = TRUE
+ SEND_SIGNAL(src, COMSIG_TURF_CHECKER_UPDATE_STATE, TRUE, checked_atom)
+ return COMPONENT_CHECKER_VALID_TURF
+
+/datum/component/turf_checker/proc/get_new_locs()
+ if(QDELETED(parent))
+ return
+
+ var/atom/movable/movable_parent = parent
+ var/list/attached_locs = movable_parent.get_locs_recursive()
+ var/atom/highest_holder = attached_locs[length(attached_locs)]
+ if(highest_holder == parent && watched_holder == parent)
+ return
+
+ var/list/old_recursive_locs = trimmed_recursive_locs
+ trimmed_recursive_locs = list()
+ if(watched_holder != highest_holder)
+ if(watched_holder != parent)
+ UnregisterSignal(watched_holder, list(COMSIG_MOVABLE_MOVED, COMSIG_ATOM_ABSTRACT_EXITED, COMSIG_QDELETING))
+
+ if(highest_holder != parent)
+ watched_holder = highest_holder
+ RegisterSignal(highest_holder, COMSIG_MOVABLE_MOVED, PROC_REF(check_turf_parent_only))
+ RegisterSignal(highest_holder, COMSIG_ATOM_ABSTRACT_EXITED, PROC_REF(on_holder_exited))
+ RegisterSignal(highest_holder, COMSIG_QDELETING, PROC_REF(on_loc_qdeleted))
+ if(length(attached_locs) > 2)
+ trimmed_recursive_locs = attached_locs - list(attached_locs[1], highest_holder)
+ for(var/atom/recursive_loc in trimmed_recursive_locs)
+ if(!QDELETED(recursive_loc))
+ if(recursive_loc in old_recursive_locs)
+ old_recursive_locs -= recursive_loc
+ else
+ RegisterSignal(recursive_loc, COMSIG_MOVABLE_MOVED, PROC_REF(check_holder))
+ RegisterSignal(recursive_loc, COMSIG_QDELETING, PROC_REF(on_loc_qdeleted))
+ else
+ watched_holder = parent
+
+ for(var/atom/old_recursive_loc in old_recursive_locs)
+ UnregisterSignal(old_recursive_loc, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING))
+
+/datum/component/turf_checker/proc/check_holder(atom/movable/moved)
+ SIGNAL_HANDLER
+ var/atom/movable/movable_parent = parent
+ if(movable_parent.get_highest_non_turf_loc() != watched_holder)
+ get_new_locs()
+
+/datum/component/turf_checker/proc/on_attached_moved(atom/movable/moved, atom/old_loc)
+ SIGNAL_HANDLER
+ if(watched_holder == parent)
+ var/atom/movable/movable_parent = parent
+ if(movable_parent.get_highest_non_turf_loc() == parent)
+ check_turf(moved)
+ return
+
+ get_new_locs()
+ check_turf(moved)
+
+/datum/component/turf_checker/proc/on_holder_exited(atom/exited, atom/movable/gone)
+ SIGNAL_HANDLER
+ var/atom/movable/movable_parent = parent
+ if(gone == parent || movable_parent.get_highest_non_turf_loc() != watched_holder)
+ get_new_locs()
+ check_turf(parent)
+
+/datum/component/turf_checker/proc/on_loc_qdeleted(atom/destroyed, forced)
+ SIGNAL_HANDLER
+ UnregisterSignal(destroyed, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING))
+ if(destroyed == watched_holder)
+ UnregisterSignal(destroyed, COMSIG_ATOM_ABSTRACT_EXITED)
+ watched_holder = null
+ else
+ trimmed_recursive_locs -= destroyed
+ get_new_locs()
+*/
+
+//A mob with this compoent will heal on its life() if standing on the given turfs
+/datum/component/turf_healing
+ ///what damage types to heal with a key of how much to heal for
+ var/list/healing_types = list()
+ ///typecache of what turfs to heal on
+ var/list/healing_turfs
+
+/datum/component/turf_healing/Initialize(list/healing_types, list/healing_turfs)
+ if(!isliving(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ if(healing_types)
+ src.healing_types = healing_types
+ if(healing_turfs)
+ src.healing_turfs = typecacheof(healing_turfs)
+ return ..()
+
+/datum/component/turf_healing/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_LIVING_LIFE, PROC_REF(handle_healing))
+
+/datum/component/turf_healing/UnregisterFromParent()
+ UnregisterSignal(parent, COMSIG_LIVING_LIFE)
+
+/datum/component/turf_healing/proc/handle_healing(mob/living/owner, seconds_per_tick)
+ SIGNAL_HANDLER
+
+ var/mob/living/healed_mob = parent
+ var/turf/on_turf = get_turf(healed_mob)
+ if(!is_type_in_typecache(on_turf, healing_turfs) || (healed_mob.health >= healed_mob.maxHealth))
+ return
+
+ for(var/entry in healing_types)
+ if(entry == STAMINA)
+ healed_mob.adjust_stamina_loss(-healing_types[entry] * seconds_per_tick)
+ continue
+ healed_mob.heal_damage_type((healing_types[entry] * seconds_per_tick), entry)
diff --git a/tff_modular/modules/antagonists/clock_cult/turfs/floor.dm b/tff_modular/modules/antagonists/clock_cult/turfs/floor.dm
new file mode 100644
index 00000000000..98ca06df537
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/turfs/floor.dm
@@ -0,0 +1,94 @@
+/turf/open/indestructible/reebe_void
+ name = "void"
+ desc = "A white, empty void, quite unlike anything you've seen before."
+ icon_state = "reebemap"
+ layer = SPACE_LAYER
+ baseturfs = /turf/open/indestructible/reebe_void
+ planetary_atmos = TRUE
+ bullet_bounce_sound = null //forever falling
+ init_air = FALSE
+ ///is this turf walkable
+ var/walkable = FALSE
+
+/turf/open/indestructible/reebe_void/Initialize(mapload)
+ . = ..()
+ icon_state = "reebegame"
+ ADD_TRAIT(src, TRAIT_BRONZE_TURF, TURF_TRAIT)
+
+/turf/open/indestructible/reebe_void/Enter(atom/movable/movable)
+ if(walkable)
+ return ..()
+
+ if(!..())
+ return FALSE
+ else
+ if(istype(movable, /obj/structure/window))
+ return FALSE
+ if(istype(movable, /obj/projectile))
+ return TRUE
+ return FALSE
+
+/turf/open/indestructible/reebe_void/RemoveLattice()
+ return
+
+/turf/open/indestructible/reebe_void/walkable
+ icon_state = "reebespawn"
+ baseturfs = /turf/open/indestructible/reebe_void/walkable
+ walkable = TRUE
+
+/turf/open/indestructible/reebe_void/spawning
+ icon_state = "reebespawn"
+
+/turf/open/indestructible/reebe_void/spawning/Initialize(mapload)
+ . = ..()
+ if(mapload)
+ if(prob(2))
+ new /obj/structure/fluff/clockwork/alloy_shards/large(src)
+
+ if(prob(4))
+ new /obj/structure/fluff/clockwork/alloy_shards/medium(src)
+
+ if(prob(6))
+ new /obj/structure/fluff/clockwork/alloy_shards/small(src)
+
+/turf/open/indestructible/reebe_void/spawning/lattices
+ icon_state = "reebelattice"
+
+/turf/open/indestructible/reebe_void/spawning/lattices/Initialize(mapload)
+ . = ..()
+ if(mapload && prob(40))
+ new /obj/structure/lattice/clockwork(src)
+
+//edge of the reebe map
+/turf/open/indestructible/reebe_void/void_edge
+ icon_state = "reebespawn"
+
+/turf/open/indestructible/reebe_flooring //used on reebe
+ name = "clockwork floor"
+ desc = "You feel a faint warmth from below it."
+ icon_state = "clockwork_floor"
+ planetary_atmos = TRUE
+ baseturfs = /turf/open/indestructible/reebe_flooring
+ turf_flags = NOJAUNT
+
+/turf/open/indestructible/reebe_flooring/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_BRONZE_TURF, TURF_TRAIT)
+
+/turf/open/indestructible/reebe_flooring/ratvar_act()
+ return FALSE
+
+/turf/open/indestructible/reebe_flooring/flat
+ icon_state = "reebe"
+
+/turf/open/indestructible/reebe_flooring/filled
+ icon_state = "clockwork_floor_filled"
+
+/turf/open/floor/engine/clockwork
+ name = "clockwork floor"
+ desc = "You feel a faint warmth from below it."
+ icon_state = "clockwork_floor"
+
+/turf/open/floor/engine/clockwork/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_BRONZE_TURF, TURF_TRAIT)
diff --git a/tff_modular/modules/antagonists/clock_cult/turfs/wall_lattice.dm b/tff_modular/modules/antagonists/clock_cult/turfs/wall_lattice.dm
new file mode 100644
index 00000000000..16cfcfed5ca
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/turfs/wall_lattice.dm
@@ -0,0 +1,116 @@
+#define BASE_REGEN_PER_SECOND 5
+#define EMPOWERED_REGEN_PER_SECOND 10
+#define BASE_REGEN_DELAY 30 SECONDS
+#define EMPOWERED_REGEN_DELAY 10 SECONDS
+#define EMPOWER_PASSIVE_DRAIN 0.5
+
+/obj/structure/destructible/clockwork/wall_lattice
+ name = "clockwork stabilization lattice"
+ desc = "A field of energy around a clockwork wall. If destroyed the wall would quickly implode."
+ icon = 'tff_modular/modules/antagonists/clock_cult/icons/obj/clockwork_effects.dmi'
+ icon_state = "wall_energy_lattice"
+ alpha = 130
+ layer = ABOVE_NORMAL_TURF_LAYER
+ max_integrity = 400
+ resistance_flags = ACID_PROOF | FIRE_PROOF | LAVA_PROOF
+ anchored = TRUE
+ break_sound = null
+ armor_type = /datum/armor/clockwork_wall_lattice
+ break_message = span_warning("The stabilization lattice rapidly collapses, bringing the wall its supporting with it!")
+ debris = null
+ damage_cap = 80
+ immune_to_servant_attacks = TRUE
+ can_rotate = FALSE
+ ///The wall we are linked to
+ var/turf/closed/wall/clockwork/linked_wall
+ ///Are we empowered
+ var/is_empowered = FALSE
+ ///The game tick we start regenerating at
+ var/regenerate_at = 0
+ ///How much do we regenerate per second
+ var/regen_per_second = BASE_REGEN_PER_SECOND
+ ///How long does it take us to start regenerating
+ var/regen_delay = BASE_REGEN_DELAY
+
+/obj/structure/destructible/clockwork/wall_lattice/Initialize(mapload, atom/link_to)
+ . = ..()
+ linked_wall = link_to
+ if(linked_wall)
+ if(!istype(linked_wall))
+ stack_trace("clockwork wall lattice at x[src.x], y[src.y], z[src.z] linked to something that was not a clockwork wall([link_to.type])")
+ return
+
+ var/turf/our_turf = get_turf(src)
+ if(istype(our_turf, /turf/closed/wall/clockwork))
+ linked_wall = our_turf
+
+/obj/structure/destructible/clockwork/wall_lattice/Destroy()
+ STOP_PROCESSING(SSthe_ark, src)
+ var/turf/closed/wall/clockwork/temp = linked_wall //this is to super ensure we dont loop
+ linked_wall = null
+ if(!QDELETED(temp))
+ temp.dismantle_wall()
+ return ..()
+
+/obj/structure/destructible/clockwork/wall_lattice/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration)
+ if(!regenerate_at)
+ START_PROCESSING(SSthe_ark, src)
+ regenerate_at = world.time + regen_delay
+ return ..()
+
+/obj/structure/destructible/clockwork/wall_lattice/process(seconds_per_tick)
+ if(world.time > regenerate_at)
+ repair_damage(regen_per_second * seconds_per_tick)
+
+ if(atom_integrity >= max_integrity)
+ regenerate_at = 0
+ return PROCESS_KILL
+
+/obj/structure/destructible/clockwork/wall_lattice/play_attack_sound(damage_amount, damage_type, damage_flag)
+ playsound(get_turf(src), 'sound/effects/empulse.ogg', 75, TRUE)
+
+/obj/structure/destructible/clockwork/wall_lattice/proc/empower()
+ if(is_empowered)
+ return FALSE
+
+ //SSthe_ark.passive_power -= EMPOWER_PASSIVE_DRAIN
+ regen_per_second = EMPOWERED_REGEN_PER_SECOND
+ regen_delay = EMPOWERED_REGEN_DELAY
+ set_armor(/datum/armor/empowered_clockwork_wall_lattice)
+ if(regenerate_at)
+ regenerate_at = regenerate_at - (BASE_REGEN_DELAY - EMPOWERED_REGEN_DELAY)
+ return TRUE
+
+/obj/structure/destructible/clockwork/wall_lattice/proc/unempower()
+ if(!is_empowered)
+ return FALSE
+
+ //SSthe_ark.passive_power += EMPOWER_PASSIVE_DRAIN
+ regen_per_second = BASE_REGEN_PER_SECOND
+ regen_delay = BASE_REGEN_DELAY
+ set_armor(/datum/armor/clockwork_wall_lattice)
+ if(regenerate_at)
+ regenerate_at = regenerate_at + (BASE_REGEN_DELAY - EMPOWERED_REGEN_DELAY)
+ return TRUE
+
+/datum/armor/clockwork_wall_lattice
+ melee = 10
+ bullet = 40
+ laser = 30
+ energy = 30
+ bomb = 100
+ bio = 100
+
+/datum/armor/empowered_clockwork_wall_lattice
+ melee = 30
+ bullet = 60
+ laser = 50
+ energy = 50
+ bomb = 100
+ bio = 100
+
+#undef BASE_REGEN_PER_SECOND
+#undef EMPOWERED_REGEN_PER_SECOND
+#undef BASE_REGEN_DELAY
+#undef EMPOWERED_REGEN_DELAY
+#undef EMPOWER_PASSIVE_DRAIN
diff --git a/tff_modular/modules/antagonists/clock_cult/turfs/walls.dm b/tff_modular/modules/antagonists/clock_cult/turfs/walls.dm
new file mode 100644
index 00000000000..7b04dc087d6
--- /dev/null
+++ b/tff_modular/modules/antagonists/clock_cult/turfs/walls.dm
@@ -0,0 +1,153 @@
+/turf/closed/wall/clockwork //version created by clock cultists
+ name = "clockwork wall"
+ desc = "A forboding clump of gears that turn on their own. A faint glow emanates from within."
+ icon = 'icons/turf/walls/clockwork_wall.dmi'
+ icon_state = "clockwork_wall-0"
+ base_icon_state = "clockwork_wall"
+ turf_flags = IS_SOLID
+ smoothing_flags = SMOOTH_BITMASK
+ canSmoothWith = null
+ uses_integrity = FALSE
+ sheet_type = /obj/item/stack/sheet/bronze
+ sheet_amount = 2
+ girder_type = /obj/structure/girder/bronze
+ turf_flags = NOJAUNT
+ hardness = 3 //very hard for hulks to break
+ //for deconstruction
+ var/d_state = INTACT
+ ///Should we spawn with a stabilization lattice
+ var/should_spawn_lattice = TRUE
+ ///Our linked lattice
+ var/obj/structure/destructible/clockwork/wall_lattice/linked_lattice
+
+/turf/closed/wall/clockwork/Initialize(mapload)
+ . = ..()
+ if(should_spawn_lattice)
+ linked_lattice = new(src, src)
+
+/turf/closed/wall/clockwork/Destroy()
+ if(!QDELETED(linked_lattice))
+ qdel(linked_lattice)
+ linked_lattice = null
+ return ..()
+
+/turf/closed/wall/clockwork/hulk_recoil(obj/item/bodypart/arm, mob/living/carbon/human/hulkman, damage = 41)
+ if(IS_CLOCK(hulkman)) //dont recoil for clock cultists
+ damage = 0
+ return ..()
+
+/turf/closed/wall/clockwork/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ return
+
+/turf/closed/wall/clockwork/deconstruction_hints(mob/user)
+ switch(d_state)
+ if(INTACT)
+ if(IS_CLOCK(user))
+ return span_notice("You see a way to unwind the gears with a wrench.")
+ else
+ return span_notice("You have no idea how this works! You think you see a small cog that could be cut loose.")
+ if(COVER_COG_REMOVED)
+ return span_notice("The outer cog has been cut loose, and some inner transmission cogs secured by screws are visable.")
+ if(TRANSMISSION_COGS_REMOVED)
+ return span_notice("The transmission cogs have been screwed loose. It looks like you could unbolt the gears now.")
+ if(GEARS_UNBOLTED)
+ return span_notice("The main gears have been unbolted and have stopped turning. You see a support beam that looks like it might fall off if heated.")
+ if(INNER_PANEL_REMOVED)
+ return span_notice("The support beam has been heated off. It looks like you could pry the rest apart.")
+ if(GEARS_UNWOUND)
+ return span_notice("The gears have been unwound with a wrench. You could take the rest apart with a crowbar.")
+
+/turf/closed/wall/clockwork/try_decon(obj/item/item_tool, mob/user)
+ switch(d_state)
+ if(INTACT)
+ if(IS_CLOCK(user) && item_tool.tool_behaviour == TOOL_WRENCH)
+ to_chat(user, span_notice("You start to unwind the gears"))
+ if(next_decon_state(item_tool, user, d_state, GEARS_UNWOUND, "You unwind the gears."))
+ return TRUE
+ if(item_tool.tool_behaviour == TOOL_WIRECUTTER)
+ item_tool.play_tool_sound(src, 100)
+ d_state = COVER_COG_REMOVED
+ to_chat(user, span_notice("You cut the outer cog."))
+ return TRUE
+
+ if(COVER_COG_REMOVED)
+ if(item_tool.tool_behaviour == TOOL_SCREWDRIVER)
+ to_chat(user, span_notice("You start to unscrew the transmission cogs."))
+ if(next_decon_state(item_tool, user, d_state, TRANSMISSION_COGS_REMOVED, "You unscrew the transmission cogs."))
+ return TRUE
+ else if(item_tool.tool_behaviour == TOOL_WIRECUTTER)
+ item_tool.play_tool_sound(src, 100)
+ d_state = INTACT
+ to_chat(user, span_notice("You put the cover cog back in place."))
+ return TRUE
+
+ if(TRANSMISSION_COGS_REMOVED)
+ if(item_tool.tool_behaviour == TOOL_WRENCH)
+ to_chat(user, span_notice("You start to unbolt the main gears."))
+ if(next_decon_state(item_tool, user, d_state, GEARS_UNBOLTED, "You unbolt the main gears."))
+ return TRUE
+ if(item_tool.tool_behaviour == TOOL_SCREWDRIVER)
+ to_chat(user, span_notice("You start to tighten thetransmission cogs."))
+ if(next_decon_state(item_tool, user, d_state, COVER_COG_REMOVED, "You tighten the transmission cogs."))
+ return TRUE
+
+ if(GEARS_UNBOLTED)
+ if(item_tool.tool_behaviour == TOOL_WELDER)
+ if(!item_tool.tool_start_check(user, amount=0))
+ return
+ to_chat(user, span_notice("You start to weld the support beam loose."))
+ if(next_decon_state(item_tool, user, d_state, INNER_PANEL_REMOVED, "You weld the support beam loose.", 3 SECONDS))
+ return TRUE
+ if(item_tool.tool_behaviour == TOOL_WRENCH)
+ to_chat(user, span_notice("You start to re-attach the main gears."))
+ if(next_decon_state(item_tool, user, d_state, TRANSMISSION_COGS_REMOVED, "You re-attach the main gears."))
+ return TRUE
+
+ if(INNER_PANEL_REMOVED)
+ if(item_tool.tool_behaviour == TOOL_CROWBAR)
+ to_chat(user, span_notice("You start to pry apart the [src]."))
+ if(next_decon_state(item_tool, user, d_state, sent_message = "You pry apart the [src]."))
+ dismantle_wall()
+ return TRUE
+ if(item_tool.tool_behaviour == TOOL_WELDER)
+ if(!item_tool.tool_start_check(user, amount=0))
+ return
+ to_chat(user, span_notice("You start to weld the support beam back into place."))
+ if(next_decon_state(item_tool, user, d_state, GEARS_UNBOLTED, "You weld the support beam back into place.", 3 SECONDS))
+ return TRUE
+
+ if(GEARS_UNWOUND)
+ if(item_tool.tool_behaviour == TOOL_CROWBAR)
+ to_chat(user, span_notice("You tart to pry apart the [src]."))
+ if(next_decon_state(item_tool, user, d_state, sent_message = "You pry apart the [src]."))
+ dismantle_wall()
+ return TRUE
+ if(item_tool.tool_behaviour == TOOL_WRENCH)
+ to_chat(user, span_notice("You start to re-wind the gears."))
+ if(next_decon_state(item_tool, user, d_state, INTACT, "You re-wind the gears."))
+ return TRUE
+ return FALSE
+
+//do the deconstruction stuff, this really should be a proc on Rwalls as well
+/turf/closed/wall/clockwork/proc/next_decon_state(obj/item/used_tool, mob/user, current_state, set_state, sent_message, use_time = 2 SECONDS)
+ if(on_reebe(src))
+ use_time = round(use_time * 0.2, 0.1) //it takes much less time to deconstruct walls on reebe
+
+ if(used_tool.use_tool(src, user, use_time, volume=100))
+ if(!istype(src, /turf/closed/wall/clockwork) || d_state != current_state)
+ return TRUE
+ if(set_state)
+ d_state = set_state
+ to_chat(user, span_notice("[sent_message]"))
+ return TRUE
+
+/turf/closed/wall/clockwork/ratvar_act()
+ return FALSE
+
+/turf/closed/wall/clockwork/rust_heretic_act()
+ visible_message(span_warning("\The [src] glows for a second, but is uneffected by the magic!"))
+ return
+
+/turf/closed/wall/clockwork/reebe //for mapping on reebe
+ baseturfs = /turf/open/indestructible/reebe_flooring
+ should_spawn_lattice = FALSE
diff --git a/tgstation.dme b/tgstation.dme
index 2b91e359fb5..381861c8000 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -424,6 +424,7 @@
#include "code\__DEFINES\traits\macros.dm"
#include "code\__DEFINES\traits\sources.dm"
#include "code\__DEFINES\~ff_defines\barsigns.dm"
+#include "code\__DEFINES\~ff_defines\clockwork.dm"
#include "code\__DEFINES\~ff_defines\DNA.dm"
#include "code\__DEFINES\~ff_defines\dynamic.dm"
#include "code\__DEFINES\~ff_defines\flavor_misc.dm"
@@ -9767,6 +9768,116 @@
#include "tff_modular\modules\antagonism_updates\uplink_item\code\categories\device_tools.dm"
#include "tff_modular\modules\antagonism_updates\uplink_item\code\categories\explosive.dm"
#include "tff_modular\modules\antagonism_updates\uplink_item\code\categories\stealthy_weapons.dm"
+#include "tff_modular\modules\antagonists\clock_cult\area.dm"
+#include "tff_modular\modules\antagonists\clock_cult\dimension_theme.dm"
+#include "tff_modular\modules\antagonists\clock_cult\dynamic_ruleset.dm"
+#include "tff_modular\modules\antagonists\clock_cult\enchantment.dm"
+#include "tff_modular\modules\antagonists\clock_cult\globals.dm"
+#include "tff_modular\modules\antagonists\clock_cult\hallucinations.dm"
+#include "tff_modular\modules\antagonists\clock_cult\helpers.dm"
+#include "tff_modular\modules\antagonists\clock_cult\hint_element.dm"
+#include "tff_modular\modules\antagonists\clock_cult\holy_water.dm"
+#include "tff_modular\modules\antagonists\clock_cult\language.dm"
+#include "tff_modular\modules\antagonists\clock_cult\multi_area_bound.dm"
+#include "tff_modular\modules\antagonists\clock_cult\outfit.dm"
+#include "tff_modular\modules\antagonists\clock_cult\pickup_element.dm"
+#include "tff_modular\modules\antagonists\clock_cult\portal.dm"
+#include "tff_modular\modules\antagonists\clock_cult\procs.dm"
+#include "tff_modular\modules\antagonists\clock_cult\ratvar.dm"
+#include "tff_modular\modules\antagonists\clock_cult\reebe_modules.dm"
+#include "tff_modular\modules\antagonists\clock_cult\status_effects.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structure_info_element.dm"
+#include "tff_modular\modules\antagonists\clock_cult\temp_visual.dm"
+#include "tff_modular\modules\antagonists\clock_cult\turf_checker.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\_action.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\add_warp_area.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\clockmob_warp.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\purge_reagents.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\recall_slab.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\space_fold.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\whirring_convergence.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\emience_teleports\basic_teleports.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\emience_teleports\linked_abscond.dm"
+#include "tff_modular\modules\antagonists\clock_cult\actions\emience_teleports\teleport_to_servant.dm"
+#include "tff_modular\modules\antagonists\clock_cult\antag_datums\clock_cult_team.dm"
+#include "tff_modular\modules\antagonists\clock_cult\antag_datums\clock_cultist.dm"
+#include "tff_modular\modules\antagonists\clock_cult\antag_datums\clockmob_antag_datum.dm"
+#include "tff_modular\modules\antagonists\clock_cult\antag_datums\clocksense_alert.dm"
+#include "tff_modular\modules\antagonists\clock_cult\antag_datums\eminence_antag_datum.dm"
+#include "tff_modular\modules\antagonists\clock_cult\ark_subsystem\_ark_subsystem.dm"
+#include "tff_modular\modules\antagonists\clock_cult\ark_subsystem\warp_effects.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\clock_stock_parts.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\clockwork_slab.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\clothing.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\integration_cog.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\reebe.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\replica_fabricator.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\soul_vessel.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\tools.dm"
+#include "tff_modular\modules\antagonists\clock_cult\items\weaponry.dm"
+#include "tff_modular\modules\antagonists\clock_cult\machines\airlock.dm"
+#include "tff_modular\modules\antagonists\clock_cult\machines\clock_sleeper.dm"
+#include "tff_modular\modules\antagonists\clock_cult\machines\clockwork_operating_computer.dm"
+#include "tff_modular\modules\antagonists\clock_cult\machines\comms_relay.dm"
+#include "tff_modular\modules\antagonists\clock_cult\machines\observation_console.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mechas\mecha_effects.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mechas\mecha_equipment.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mechas\steam_helios.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mobs\clockwork_golem.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mobs\clockwork_marauder.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mobs\cogscarab.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mobs\eminence.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mobs\clock_borgs\clock_borg.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mobs\clock_borgs\clock_borg_models.dm"
+#include "tff_modular\modules\antagonists\clock_cult\mobs\clock_borgs\clock_borg_modules.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\_scripture.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\preservation\clockwork_armaments.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\preservation\dimensional_breach.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\preservation\summon_cogscarab.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\preservation\summon_marauder.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\preservation\vanguard.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\servitude\abscond.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\servitude\golem_conversion.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\servitude\hateful_manacles.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\servitude\integration_cog.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\servitude\kindle.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\servitude\sentinels_compromise.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\servitude\submission_sigil.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\servitude\vitality_sigil.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\structures\anchoring_crystal.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\structures\empower_wall.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\structures\interdiction_lens.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\structures\ocular_warden.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\structures\prosperity_prism.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\structures\stargazer.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\structures\tinkerers_cache.dm"
+#include "tff_modular\modules\antagonists\clock_cult\scriptures\structures\transmission_sigil.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\_powered.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\_structure.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\anchor_crystal.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\brass_window.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\eminence_beacon.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\gear_base.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\interdiction_lens.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\lattice.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\ocular_warden.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\prosperity_prism.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\stargazer.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\the_ark.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\tinkerers_cache.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\sigil\_sigil.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\sigil\sigil_submission.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\sigil\sigil_transmission.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\sigil\sigil_vitality.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\traps\trap.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\traps\recievers\flipper.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\traps\recievers\skewer.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\traps\senders\delay.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\traps\senders\lever.dm"
+#include "tff_modular\modules\antagonists\clock_cult\structures\traps\senders\pressure_sensor.dm"
+#include "tff_modular\modules\antagonists\clock_cult\turfs\floor.dm"
+#include "tff_modular\modules\antagonists\clock_cult\turfs\wall_lattice.dm"
+#include "tff_modular\modules\antagonists\clock_cult\turfs\walls.dm"
#include "tff_modular\modules\auguments\implants.dm"
#include "tff_modular\modules\autoaccent\code\autoaccent.dm"
#include "tff_modular\modules\bar_jukebox\code\jukebox.dm"
diff --git a/tgui/packages/tgui/interfaces/AntagInfoClockAlt.tsx b/tgui/packages/tgui/interfaces/AntagInfoClockAlt.tsx
new file mode 100644
index 00000000000..60a8697b778
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/AntagInfoClockAlt.tsx
@@ -0,0 +1,37 @@
+import { Icon, Section, Stack } from 'tgui-core/components';
+import { useBackend } from '../backend';
+import { Window } from '../layouts';
+import { type Objective, ObjectivePrintout } from './common/Objectives';
+
+type Info = {
+ antag_name: string;
+ objectives: Objective[];
+ marked_areas: string[];
+};
+
+export const AntagInfoClockAlt = (props) => {
+ const { data } = useBackend();
+ const { antag_name, objectives, marked_areas } = data;
+ return (
+
+
+
+
+
+
+ {' You are the ' + antag_name + '! '}
+
+
+
+
+
+ {'Our marked areas are: ' + marked_areas}
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clockcultmidround.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clockcultmidround.ts
new file mode 100644
index 00000000000..485076a32e4
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clockcultmidround.ts
@@ -0,0 +1,18 @@
+import { type Antagonist, Category } from '../base';
+
+export const MIDROUND_CLOCKWORK_MECHANICAL_DESCRIPTION = `
+You have discovered the secret knowledge and enlightenment at the station.
+Perhaps Ratvar himself chose you as his follower, but it doesn't matter.
+Now you must restore him to the world of the living...
+`;
+
+const MidroundClockworkCultist: Antagonist = {
+ key: 'midroundclockworkcultist',
+ name: 'Midround Clockwork Cultist',
+ description: [
+ MIDROUND_CLOCKWORK_MECHANICAL_DESCRIPTION,
+ ],
+ category: Category.Midround,
+};
+
+export default MidroundClockworkCultist;
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clockcultroundstart.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clockcultroundstart.ts
new file mode 100644
index 00000000000..50a1e90cb38
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/clockcultroundstart.ts
@@ -0,0 +1,15 @@
+import { type Antagonist, Category } from '../base';
+
+export const CLOCKWORK_MECHANICAL_DESCRIPTION = `
+You were sent to the station to change the minds of the lost and revive
+the Rat'Var. Will you be able to do it, or will you fall like your god?
+`;
+
+const RoundstartClockworkCultist: Antagonist = {
+ key: 'roundstartclockworkcultist',
+ name: 'Clockwork Cultist',
+ description: [CLOCKWORK_MECHANICAL_DESCRIPTION],
+ category: Category.Roundstart,
+};
+
+export default RoundstartClockworkCultist;