, a living extension of Sevtug's will. As a guardian, you are somewhat slow, but may block attacks, \
+ and have a chance to also counter blocked melee attacks for extra damage, in addition to being immune to extreme temperatures and pressures. \
+ Your primary goal is to serve the creature that you are now a part of. You can use :b to communicate silently with your master, \
+ but can only exit if your master calls your true name or if they are exceptionally damaged. \
+ \n\n\
+ Stay near your host to protect and heal them; being too far from your host will rapidly cause you massive damage. Recall to your host if you are too weak and believe you cannot continue \
+ fighting safely. As a final note, you should probably avoid harming any fellow servants of Ratvar."
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/Initialize()
+ . = ..()
+ true_name = pick(possible_true_names)
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardianLife()
+ ..()
+ if(is_in_host())
+ if(!is_servant_of_ratvar(host))
+ emerge_from_host(FALSE, TRUE)
+ unbind_from_host()
+ return
+ if(!GLOB.ratvar_awakens && host.stat == DEAD)
+ death()
+ return
+ if(GLOB.ratvar_awakens)
+ adjustHealth(-50)
+ else
+ adjustHealth(-10)
+ if(!recovering)
+ heal_host() //also heal our host if inside of them and we aren't recovering
+ else if(health == maxHealth)
+ to_chat(src, "Your strength has returned. You can once again come forward!")
+ to_chat(host, "Your guardian is now strong enough to come forward again!")
+ recovering = FALSE
+ else
+ if(GLOB.ratvar_awakens) //If Ratvar is alive, guardians don't need a host and are downright impossible to kill
+ adjustHealth(-5)
+ heal_host()
+ else if(host)
+ if(!is_servant_of_ratvar(host))
+ unbind_from_host()
+ return
+ if(host.stat == DEAD)
+ adjustHealth(50)
+ to_chat(src, "Your host is dead!")
+ return
+ if(z && host.z && z == host.z)
+ switch(get_dist(get_turf(src), get_turf(host)))
+ if(2)
+ adjustHealth(-1)
+ if(3)
+ //EQUILIBRIUM
+ if(4)
+ adjustHealth(1)
+ if(5)
+ adjustHealth(3)
+ if(6)
+ adjustHealth(6)
+ if(7)
+ adjustHealth(9)
+ if(8 to INFINITY)
+ adjustHealth(15)
+ to_chat(src, "You're too far from your host and rapidly taking damage!")
+ else //right next to or on top of host
+ adjustHealth(-2)
+ heal_host() //gradually heal host if nearby and host is very weak
+ else //well then, you're not even in the same zlevel
+ adjustHealth(15)
+ to_chat(src, "You're too far from your host and rapidly taking damage!")
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/death(gibbed)
+ emerge_from_host(FALSE, TRUE)
+ unbind_from_host()
+ visible_message("[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.", \
+ "Your equipment falls away. You feel a moment of confusion before your fragile form is annihilated.")
+ . = ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/Stat()
+ ..()
+ if(statpanel("Status"))
+ stat(null, "Current True Name: [true_name]")
+ stat(null, "Host: [host ? host : "NONE"]")
+ if(host)
+ var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
+ if(iscarbon(host))
+ resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
+ stat(null, "Host Health: [resulthealth]%")
+ if(GLOB.ratvar_awakens)
+ stat(null, "You are [recovering ? "un" : ""]able to deploy!")
+ else
+ if(resulthealth > GUARDIAN_EMERGE_THRESHOLD)
+ stat(null, "You are [recovering ? "unable to deploy" : "able to deploy on hearing your True Name"]!")
+ else
+ stat(null, "You are [recovering ? "unable to deploy" : "able to deploy to protect your host"]!")
+ stat(null, "You do [melee_damage_upper] damage on melee attacks.")
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/Process_Spacemove(movement_dir = 0)
+ return 1
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/bind_to_host(mob/living/new_host)
+ if(!new_host)
+ return FALSE
+ host = new_host
+ var/datum/action/innate/summon_marauder/guardian/SM = new()
+ SM.linked_guardian = src
+ SM.Grant(host)
+ var/datum/action/innate/linked_minds/LM = new()
+ LM.linked_guardian = src
+ LM.Grant(host)
+ return TRUE
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/unbind_from_host()
+ if(host)
+ for(var/datum/action/innate/summon_marauder/guardian/SM in host.actions)
+ qdel(SM)
+ for(var/datum/action/innate/linked_minds/LM in host.actions)
+ qdel(LM)
+ host = null
+ return TRUE
+ return FALSE
+
+//DAMAGE and FATIGUE
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/heal_host()
+ if(!host)
+ return
+ var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
+ if(iscarbon(host))
+ resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
+ if(GLOB.ratvar_awakens || resulthealth <= GUARDIAN_EMERGE_THRESHOLD)
+ new /obj/effect/temp_visual/heal(host.loc, "#AF0AAF")
+ host.heal_ordered_damage(4, damage_heal_order)
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
+ if(amount > 0)
+ for(var/mob/living/L in view(2, src))
+ if(L.is_holding_item_of_type(/obj/item/nullrod))
+ to_chat(src, "The presence of a brandished holy artifact weakens your armor!")
+ amount *= 4 //if a wielded null rod is nearby, it takes four times the health damage
+ break
+ . = ..()
+ if(src && updating_health)
+ update_health_hud()
+ update_stats()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/update_health_hud()
+ if(hud_used && hud_used.healths)
+ if(istype(hud_used, /datum/hud/guardian))
+ var/datum/hud/guardian/M = hud_used
+ var/resulthealth
+ if(host)
+ if(iscarbon(host))
+ resulthealth = "[round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)]%"
+ else
+ resulthealth = "[round((host.health / host.maxHealth) * 100, 0.5)]%"
+ else
+ resulthealth = "NONE"
+ M.hosthealth.maptext = "HOST
[resulthealth]
"
+ hud_used.healths.maptext = "[round((health / maxHealth) * 100, 0.5)]%"
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/update_stats()
+ if(GLOB.ratvar_awakens)
+ speed = 0
+ melee_damage_lower = 20
+ melee_damage_upper = 20
+ attacktext = "devastates"
+ else
+ var/healthpercent = (health/maxHealth) * 100
+ switch(healthpercent)
+ if(100 to 70) //Bonuses to speed and damage at high health
+ speed = 0
+ melee_damage_lower = 16
+ melee_damage_upper = 16
+ attacktext = "viciously slashes"
+ if(70 to 40)
+ speed = initial(speed)
+ melee_damage_lower = initial(melee_damage_lower)
+ melee_damage_upper = initial(melee_damage_upper)
+ attacktext = initial(attacktext)
+ if(40 to 30) //Damage decrease, but not speed
+ speed = initial(speed)
+ melee_damage_lower = 10
+ melee_damage_upper = 10
+ attacktext = "lightly slashes"
+ if(30 to 20) //Speed decrease
+ speed = 2
+ melee_damage_lower = 8
+ melee_damage_upper = 8
+ attacktext = "lightly slashes"
+ if(20 to 10) //Massive speed decrease and weak melee attacks
+ speed = 3
+ melee_damage_lower = 6
+ melee_damage_upper = 6
+ attacktext = "weakly slashes"
+ if(10 to 0) //We are super weak and going to die
+ speed = 4
+ melee_damage_lower = 4
+ melee_damage_upper = 4
+ attacktext = "taps"
+
+//ATTACKING, BLOCKING, and COUNTERING
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/AttackingTarget()
+ if(is_in_host())
+ return FALSE
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/bullet_act(obj/item/projectile/Proj)
+ if(blockOrCounter(null, Proj))
+ return
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
+ if(blockOrCounter(null, AM))
+ return
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_animal(mob/living/simple_animal/M)
+ if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder/guardian) || !blockOrCounter(M, M)) //we don't want infinite blockcounter loops if fighting another guardian
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_paw(mob/living/carbon/monkey/M)
+ if(!blockOrCounter(M, M))
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if(!blockOrCounter(M, M))
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_slime(mob/living/simple_animal/slime/M)
+ if(!blockOrCounter(M, M))
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_hand(mob/living/carbon/human/M)
+ if(!blockOrCounter(M, M))
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/nullrod) || !blockOrCounter(user, I))
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/blockOrCounter(mob/target, atom/textobject)
+ if(GLOB.ratvar_awakens) //if ratvar has woken, we block nearly everything at a very high chance
+ blockchance = 90
+ counterchance = 90
+ if(prob(blockchance))
+ . = TRUE
+ if(target)
+ target.do_attack_animation(src)
+ target.changeNext_move(CLICK_CD_MELEE)
+ blockchance = initial(blockchance)
+ playsound(src, 'sound/magic/clockwork/fellowship_armory.ogg', 30, 1, 0, 1) //clang
+ visible_message("[src] blocks [target && isitem(textobject) ? "[target]'s [textobject.name]":"\the [textobject]"]!", \
+ "You block [target && isitem(textobject) ? "[target]'s [textobject.name]":"\the [textobject]"]!")
+ if(target && Adjacent(target))
+ if(prob(counterchance))
+ counterchance = initial(counterchance)
+ var/previousattacktext = attacktext
+ attacktext = "counters"
+ UnarmedAttack(target)
+ attacktext = previousattacktext
+ else
+ counterchance = min(counterchance + initial(counterchance), 100)
+ else
+ blockchance = min(blockchance + initial(blockchance), 100)
+ if(GLOB.ratvar_awakens)
+ blockchance = 90
+ counterchance = 90
+
+//COMMUNICATION and EMERGENCE
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/handle_inherent_channels(message, message_mode)
+ if(host && (is_in_host() || message_mode == MODE_BINARY))
+ guardian_comms(message)
+ return TRUE
+ return ..()
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/guardian_comms(message)
+ var/name_part = "[src] ([true_name])"
+ message = "\"[message]\"" //Processed output
+ to_chat(src, "[name_part]: [message]")
+ to_chat(host, "[name_part]: [message]")
+ for(var/M in GLOB.mob_list)
+ if(isobserver(M))
+ var/link = FOLLOW_LINK(M, src)
+ to_chat(M, "[link] [name_part] (to [findtextEx(host.name, host.real_name) ? "[host.name]" : "[host.real_name] (as [host.name])"]): [message] ")
+ return TRUE
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/return_to_host()
+ if(is_in_host())
+ return FALSE
+ if(!host)
+ to_chat(src, "You don't have a host!")
+ return FALSE
+ var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
+ if(iscarbon(host))
+ resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
+ host.visible_message("[host]'s skin flashes crimson!", "You feel [true_name]'s consciousness settle in your mind.")
+ visible_message("[src] suddenly disappears!", "You return to [host].")
+ forceMove(host)
+ if(resulthealth > GUARDIAN_EMERGE_THRESHOLD && health != maxHealth)
+ recovering = TRUE
+ to_chat(src, "You have weakened and will need to recover before manifesting again!")
+ to_chat(host, "[true_name] has weakened and will need to recover before manifesting again!")
+ return TRUE
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/try_emerge()
+ if(!host)
+ to_chat(src, "You don't have a host!")
+ return FALSE
+ if(!GLOB.ratvar_awakens)
+ var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
+ if(iscarbon(host))
+ resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
+ if(host.stat != DEAD && resulthealth > GUARDIAN_EMERGE_THRESHOLD) //if above 20 health, fails
+ to_chat(src, "Your host must be at [GUARDIAN_EMERGE_THRESHOLD]% or less health to emerge like this!")
+ return FALSE
+ return emerge_from_host(FALSE)
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/emerge_from_host(hostchosen, force) //Notice that this is a proc rather than a verb - guardians can NOT exit at will, but they CAN return
+ if(!is_in_host())
+ return FALSE
+ if(!force && recovering)
+ if(hostchosen)
+ to_chat(host, "[true_name] is too weak to come forth!")
+ else
+ to_chat(host, "[true_name] tries to emerge to protect you, but it's too weak!")
+ to_chat(src, "You try to come forth, but you're too weak!")
+ return FALSE
+ if(!force)
+ if(hostchosen) //guardian approved
+ to_chat(host, "Your words echo with power as [true_name] emerges from your body!")
+ else
+ to_chat(host, "[true_name] emerges from your body to protect you!")
+ forceMove(host.loc)
+ visible_message("[host]'s skin glows red as [name] emerges from their body!", "You exit the safety of [host]'s body!")
+ return TRUE
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/get_alt_name()
+ return " ([text2ratvar(true_name)])"
+
+/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/is_in_host() //Checks if the guardian is inside of their host
+ return host && loc == host
+
+//HOST ACTIONS
+
+//Summon guardian action: Calls forth or recalls your guardian
+/datum/action/innate/summon_marauder
+ name = "Force Guardian to Emerge/Recall"
+ desc = "Allows you to force your clockwork guardian to emerge or recall as required."
+ button_icon_state = "clockwork_marauder"
+ background_icon_state = "bg_clock"
+ check_flags = AB_CHECK_CONSCIOUS
+ buttontooltipstyle = "clockcult"
+ var/mob/living/simple_animal/hostile/clockwork/marauder/guardian/linked_guardian
+ var/static/list/defend_phrases = list("Defend me", "Come forth", "Assist me", "Protect me", "Give aid", "Help me")
+ var/static/list/return_phrases = list("Return", "Return to me", "Your job is done", "You have served", "Come back", "Retreat")
+
+/datum/action/innate/summon_marauder/IsAvailable()
+ if(!linked_guardian)
+ return FALSE
+ if(isliving(owner))
+ var/mob/living/L = owner
+ if(!L.can_speak_vocal() || L.stat)
+ return FALSE
+ return ..()
+
+/datum/action/innate/summon_guardian/Activate()
+ if(linked_guardian.is_in_host())
+ clockwork_say(owner, text2ratvar("[pick(defend_phrases)], [linked_guardian.true_name]!"))
+ linked_guardian.emerge_from_host(TRUE)
+ else
+ clockwork_say(owner, text2ratvar("[pick(return_phrases)], [linked_guardian.true_name]!"))
+ linked_guardian.return_to_host()
+ return TRUE
+
+//Linked Minds action: talks to your guardian
+/datum/action/innate/linked_minds
+ name = "Linked Minds"
+ desc = "Allows you to silently communicate with your guardian."
+ button_icon_state = "linked_minds"
+ background_icon_state = "bg_clock"
+ check_flags = AB_CHECK_CONSCIOUS
+ buttontooltipstyle = "clockcult"
+ var/mob/living/simple_animal/hostile/clockwork/marauder/guardian/linked_guardian
+
+/datum/action/innate/linked_minds/IsAvailable()
+ if(!linked_guardian)
+ return FALSE
+ return ..()
+
+/datum/action/innate/linked_minds/Activate()
+ var/message = stripped_input(owner, "Enter a message to tell your guardian.", "Telepathy")
+ if(!owner || !message)
+ return FALSE
+ if(!linked_guardian)
+ to_chat(owner, "Your guardian seems to have been destroyed!")
+ return FALSE
+ var/name_part = "Servant [findtextEx(owner.name, owner.real_name) ? "[owner.name]" : "[owner.real_name] (as [owner.name])"]"
+ message = "\"[message]\"" //Processed output
+ to_chat(owner, "[name_part]: [message]")
+ to_chat(linked_guardian, "[name_part]: [message]")
+ for(var/M in GLOB.mob_list)
+ if(isobserver(M))
+ var/link = FOLLOW_LINK(M, src)
+ to_chat(M, "[link] [name_part] (to [linked_guardian] ([linked_guardian.true_name])): [message]")
+ return TRUE
+*/
\ No newline at end of file
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
index ffe9ecfa80..a284261045 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
@@ -23,6 +23,61 @@
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Transmission, which can drain and will store power for clockwork structures."
+/*//Prolonging Prism: Creates a prism that will delay the shuttle at a power cost
+/datum/clockwork_scripture/create_object/prolonging_prism
+ descname = "Powered Structure, Delay Emergency Shuttles"
+ name = "Prolonging Prism"
+ desc = "Creates a mechanized prism which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
+ invocations = list("May this prism...", "...grant us time to enact his will!")
+ channel_time = 80
+ consumed_components = list(VANGUARD_COGWHEEL = 5, GEIS_CAPACITOR = 2, REPLICANT_ALLOY = 2)
+ object_path = /obj/structure/destructible/clockwork/powered/prolonging_prism
+ creator_message = "You form a prolonging prism, which will delay the arrival of an emergency shuttle at a massive power cost."
+ observer_message = "An onyx prism forms in midair and sprouts tendrils to support itself!"
+ invokers_required = 2
+ multiple_invokers_used = TRUE
+ usage_tip = "The power cost to delay a shuttle increases based on the number of times activated."
+ tier = SCRIPTURE_APPLICATION
+ one_per_tile = TRUE
+ primary_component = VANGUARD_COGWHEEL
+ sort_priority = 7
+ quickbind = TRUE
+ quickbind_desc = "Creates a Prolonging Prism, which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
+
+/datum/clockwork_scripture/create_object/prolonging_prism/check_special_requirements()
+ if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
+ to_chat(invoker, "\"It is too late to construct one of these, champion.\"")
+ return FALSE
+ var/turf/T = get_turf(invoker)
+ if(!T || !(T.z in GLOB.station_z_levels))
+ to_chat(invoker, "\"You must be on the station to construct one of these, champion.\"")
+ return FALSE
+ return ..()
+
+
+
+//Tinkerer's Daemon: Creates an efficient machine that rapidly produces components at a power cost.
+/datum/clockwork_scripture/create_object/tinkerers_daemon
+ descname = "Powered Structure, Component Generator"
+ name = "Tinkerer's Daemon"
+ desc = "Creates a tinkerer's daemon which can rapidly collect components. It will only function if it has sufficient power, active daemons are outnumbered by Servants by a ratio of 5:1, \
+ and there is at least one existing cache."
+ invocations = list("May this generator...", "...collect Engine parts that yet hold greatness!")
+ channel_time = 80
+ consumed_components = list(BELLIGERENT_EYE = 2, GEIS_CAPACITOR = 2, REPLICANT_ALLOY = 5)
+ object_path = /obj/structure/destructible/clockwork/powered/tinkerers_daemon
+ creator_message = "You form a tinkerer's daemon which can rapidly collect components at a power cost."
+ invokers_required = 2
+ multiple_invokers_used = TRUE
+ usage_tip = "Vital to your success!"
+ tier = SCRIPTURE_APPLICATION
+ one_per_tile = TRUE
+ primary_component = REPLICANT_ALLOY
+ sort_priority = 9
+ quickbind = TRUE
+ quickbind_desc = "Creates a Tinkerer's Daemon, which can rapidly collect components for power."
+
+*/
//Mania Motor: Creates a malevolent transmitter that will broadcast the whispers of Sevtug into the minds of nearby nonservants, causing a variety of mental effects at a power cost.
/datum/clockwork_scripture/create_object/mania_motor
@@ -67,7 +122,67 @@
quickbind = TRUE
quickbind_desc = "Creates a Clockwork Obelisk, which can send messages or open Spatial Gateways with power."
+/*
+//Memory Allocation: Finds a willing ghost and makes them into a clockwork marauders for the invoker.
+/datum/clockwork_scripture/memory_allocation
+ descname = "Guardian"
+ name = "Memory Allocation"
+ desc = "Allocates part of your consciousness to a Clockwork Marauder, a vigilant fighter that lives within you, able to be \
+ called forth by Speaking its True Name or if you become exceptionally low on health.
\
+ If it remains close to you, you will gradually regain health up to a low amount, but it will die if it goes too far from you."
+ invocations = list("Fright's will...", "...call forth...")
+ channel_time = 100
+ consumed_components = list(BELLIGERENT_EYE = 2, VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 4)
+ usage_tip = "Marauders are useful as personal bodyguards and frontline warriors."
+ tier = SCRIPTURE_APPLICATION
+ primary_component = GEIS_CAPACITOR
+ sort_priority = 3
+/datum/clockwork_scripture/memory_allocation/check_special_requirements()
+ for(var/mob/living/simple_animal/hostile/clockwork/marauder/M in GLOB.all_clockwork_mobs)
+ if(M.host == invoker)
+ to_chat(invoker, "You can only house one marauder at a time!")
+ return FALSE
+ return TRUE
+
+/datum/clockwork_scripture/memory_allocation/scripture_effects()
+ return create_marauder()
+
+/datum/clockwork_scripture/memory_allocation/proc/create_marauder()
+ invoker.visible_message("A purple tendril appears from [invoker]'s [slab.name] and impales itself in [invoker.p_their()] forehead!", \
+ "A tendril flies from [slab] into your forehead. You begin waiting while it painfully rearranges your thought pattern...")
+ invoker.notransform = TRUE //Vulnerable during the process
+ slab.busy = "Thought Modification in progress"
+ if(!do_after(invoker, 50, target = invoker))
+ invoker.visible_message("The tendril, covered in blood, retracts from [invoker]'s head and back into the [slab.name]!", \
+ "Total agony overcomes you as the tendril is forced out early!")
+ invoker.notransform = FALSE
+ invoker.Knockdown(100)
+ invoker.apply_damage(10, BRUTE, "head")
+ slab.busy = null
+ return FALSE
+ clockwork_say(invoker, text2ratvar("...the mind made..."))
+ invoker.notransform = FALSE
+ slab.busy = "Marauder Selection in progress"
+ if(!check_special_requirements())
+ return FALSE
+ to_chat(invoker, "The tendril shivers slightly as it selects a marauder...")
+ var/list/marauder_candidates = pollGhostCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 50, POLL_IGNORE_CLOCKWORK_MARAUDER)
+ if(!check_special_requirements())
+ return FALSE
+ if(!marauder_candidates.len)
+ invoker.visible_message("The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!", \
+ "The tendril was unsuccessful! Perhaps you should try again another time.")
+ return FALSE
+ clockwork_say(invoker, text2ratvar("...sword and shield!"))
+ var/mob/dead/observer/theghost = pick(marauder_candidates)
+ var/mob/living/simple_animal/hostile/clockwork/marauder/M = new(invoker)
+ M.key = theghost.key
+ M.bind_to_host(invoker)
+ invoker.visible_message("The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!", \
+ "[M.true_name], a clockwork marauder, has taken up residence in your mind. Communicate with it via the \"Linked Minds\" action button.")
+ return TRUE
+*/
//Clockwork Marauder: Creates a construct shell for a clockwork marauder, a well-rounded frontline fighter.
/datum/clockwork_scripture/create_object/construct/clockwork_marauder
descname = "Well-Rounded Combat Construct"
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
index 6349ecb581..864187b903 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
@@ -113,6 +113,40 @@
quickbind = TRUE
quickbind_desc = "Stuns and mutes a target from a short range."
+/*
+//Geis: Grants a short-range binding attack that allows you to mute and drag around a target in a very obvious manner.
+/datum/clockwork_scripture/ranged_ability/geis
+ descname = "Melee Mute & Stun"
+ name = "Geis"
+ desc = "Charges your slab with divine energy, allowing you to bind and pull a struck heretic."
+ invocations = list("Divinity, grant me strength...", "...to bind the heathen!")
+ whispered = TRUE
+ channel_time = 20
+ usage_tip = "You CANNOT TAKE ANY NON-PULL ACTIONS while the target is bound, so Sigils of Submission should be placed before use."
+ tier = SCRIPTURE_DRIVER
+ primary_component = GEIS_CAPACITOR
+ sort_priority = 5
+ quickbind = TRUE
+ quickbind_desc = "Allows you to bind and mute an adjacent target non-Servant.
Click your slab to disable."
+ slab_overlay = "geis"
+ ranged_type = /obj/effect/proc_holder/slab/geis
+ ranged_message = "You charge the clockwork slab with divine energy.\n\
+ Left-click a target within melee range to bind!\n\
+ Click your slab to cancel."
+ timeout_time = 100
+
+/datum/clockwork_scripture/ranged_ability/geis/run_scripture()
+ var/servants = 0
+ if(!GLOB.ratvar_awakens)
+ for(var/mob/living/M in GLOB.living_mob_list)
+ if(can_recite_scripture(M, TRUE))
+ servants++
+ if(servants > SCRIPT_SERVANT_REQ)
+ whispered = FALSE
+ servants -= SCRIPT_SERVANT_REQ
+ channel_time = min(channel_time + servants*3, 50)
+ return ..()
+*/
//Hateful Manacles: Applies restraints from melee over several seconds. The restraints function like handcuffs and break on removal.
/datum/clockwork_scripture/ranged_ability/hateful_manacles
@@ -293,3 +327,25 @@
sort_priority = 11
quickbind = TRUE
quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss."
+/*
+//Tinkerer's Cache: Creates a tinkerer's cache, allowing global component storage.
+/datum/clockwork_scripture/create_object/tinkerers_cache
+ descname = "Necessary Structure, Shares Components"
+ name = "Tinkerer's Cache"
+ desc = "Forms a cache that can store an infinite amount of components. All caches are linked and will provide components to slabs. \
+ Striking a cache with a slab will transfer that slab's components to the global cache."
+ invocations = list("Constructing...", "...a cache!")
+ channel_time = 50
+ consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 0)
+ object_path = /obj/structure/destructible/clockwork/cache
+ creator_message = "You form a tinkerer's cache, which is capable of storing components, which will automatically be used by slabs."
+ observer_message = "A hollow brass spire rises and begins to blaze!"
+ usage_tip = "Slabs will draw components from the global cache after the slab's own repositories, making caches extremely useful."
+ tier = SCRIPTURE_DRIVER
+ one_per_tile = TRUE
+ primary_component = REPLICANT_ALLOY
+ sort_priority = 8
+ quickbind = TRUE
+ quickbind_desc = "Creates a Tinkerer's Cache, which stores components globally for slab access."
+ var/static/prev_cost = 0
+ */
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_judgement.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_judgement.dm
new file mode 100644
index 0000000000..0a8e717b5d
--- /dev/null
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_judgement.dm
@@ -0,0 +1,43 @@
+///////////////
+// JUDGEMENT //
+///////////////
+
+//Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict, summoning ratvar.
+/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar
+ descname = "Structure, Win Condition"
+ name = "Ark of the Clockwork Justiciar"
+ desc = "Tears apart a rift in spacetime to Reebe, the Celestial Derelict, using a massive amount of components.\n\
+ This gateway will, after some time, call forth Ratvar from his exile and massively empower all scriptures and tools."
+ invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \
+ "THE TIME HAS COME FOR OUR MASTER TO BREAK THE CHAINS OF EXILE!!", \
+ "LEND US YOUR AID! ENGINE COMES!!")
+ channel_time = 150
+ consumed_components = list(BELLIGERENT_EYE = ARK_SUMMON_COST, VANGUARD_COGWHEEL = ARK_SUMMON_COST, GEIS_CAPACITOR = ARK_SUMMON_COST, REPLICANT_ALLOY = ARK_SUMMON_COST, HIEROPHANT_ANSIBLE = ARK_SUMMON_COST)
+ invokers_required = 6
+ multiple_invokers_used = TRUE
+ object_path = /obj/structure/destructible/clockwork/massive/celestial_gateway
+ creator_message = null
+ usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. It will periodically give indication of its general position to everyone on the station \
+ as well as being loud enough to be heard throughout the entire sector. Defend it with your life!"
+ tier = SCRIPTURE_JUDGEMENT
+ sort_priority = 1
+
+/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar/check_special_requirements()
+ if(!slab.no_cost)
+ if(GLOB.ratvar_awakens)
+ to_chat(invoker, "\"I am already here, idiot.\"")
+ return FALSE
+ for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
+ var/area/gate_area = get_area(G)
+ to_chat(invoker, "There is already an Ark at [gate_area.map_name]!")
+ return FALSE
+ var/area/A = get_area(invoker)
+ var/turf/T = get_turf(invoker)
+ if(!T || !(T.z in GLOB.station_z_levels) || istype(A, /area/shuttle) || !A.blob_allowed)
+ to_chat(invoker, "You must be on the station to activate the Ark!")
+ return FALSE
+ if(GLOB.clockwork_gateway_activated)
+ to_chat(invoker, "Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!")
+ return FALSE
+ return ..()
+
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
index d22a2f69b7..6ac3151c49 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
@@ -487,3 +487,27 @@
invoker.light_range = 0
invoker.update_light()
return ..()
+
+/*//Belligerent: Channeled for up to fifteen times over thirty seconds. Forces non-servants that can hear the chant to walk, doing minor damage. Nar-Sian cultists are burned.
+/datum/clockwork_scripture/channeled/belligerent
+ descname = "Channeled, Area Slowdown"
+ name = "Belligerent"
+ desc = "Forces all nearby non-servants to walk rather than run, doing minor damage. Chanted every two seconds for up to thirty seconds."
+ chant_invocations = list("Punish their blindness!", "Take time, make slow!")
+ chant_amount = 15
+ chant_interval = 20
+ channel_time = 20
+ power_cost = 300
+ usage_tip = "Useful for crowd control in a populated area and disrupting mass movement."
+ tier = SCRIPTURE_DRIVER
+ primary_component = BELLIGERENT_EYE
+ sort_priority = 1
+ quickbind = TRUE
+ quickbind_desc = "Forces nearby non-Servants to walk, doing minor damage with each chant.
Maximum 15 chants."
+
+/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number)
+ for(var/mob/living/carbon/C in hearers(7, invoker))
+ C.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
+ new /obj/effect/temp_visual/ratvar/belligerent(get_turf(invoker))
+ return TRUE
+ */
\ No newline at end of file
diff --git a/code/modules/antagonists/clockcult/clock_structures/prolonging_prism.dm b/code/modules/antagonists/clockcult/clock_structures/prolonging_prism.dm
new file mode 100644
index 0000000000..155413a612
--- /dev/null
+++ b/code/modules/antagonists/clockcult/clock_structures/prolonging_prism.dm
@@ -0,0 +1,135 @@
+//Prolonging Prism: A prism that consumes power to delay the shuttle
+/obj/structure/destructible/clockwork/powered/prolonging_prism
+ name = "prolonging prism"
+ desc = "A dark onyx prism, held in midair by spiraling tendrils of stone."
+ clockwork_desc = "A powerful prism that will delay the arrival of an emergency shuttle."
+ icon_state = "prolonging_prism_inactive"
+ active_icon = "prolonging_prism"
+ inactive_icon = "prolonging_prism_inactive"
+ unanchored_icon = "prolonging_prism_unwrenched"
+ construction_value = 20
+ max_integrity = 125
+ break_message = "The prism falls to the ground with a heavy thud!"
+ debris = list(/obj/item/clockwork/alloy_shards/small = 3, \
+ /obj/item/clockwork/alloy_shards/medium = 1, \
+ /obj/item/clockwork/alloy_shards/large = 1, \
+ /obj/item/clockwork/component/vanguard_cogwheel/onyx_prism = 1)
+ var/static/list/component_refund = list(VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1)
+ var/static/delay_cost = 3000
+ var/static/delay_cost_increase = 1250
+ var/static/delay_remaining = 0
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/examine(mob/user)
+ ..()
+ if(is_servant_of_ratvar(user) || isobserver(user))
+ if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
+ to_chat(user, "An emergency shuttle has arrived and this prism is no longer useful; attempt to activate it to gain a partial refund of components used.")
+ else
+ var/efficiency = get_efficiency_mod(TRUE)
+ to_chat(user, "It requires at least [DisplayPower(get_delay_cost())] of power to attempt to delay the arrival of an emergency shuttle by [2 * efficiency] minutes.")
+ to_chat(user, "This cost increases by [DisplayPower(delay_cost_increase)] for every previous activation.")
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/forced_disable(bad_effects)
+ if(active)
+ if(bad_effects)
+ try_use_power(MIN_CLOCKCULT_POWER*4)
+ visible_message("[src] emits an airy chuckling sound and falls dark!")
+ toggle()
+ return TRUE
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/attack_hand(mob/living/user)
+ if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user))
+ if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
+ to_chat(user, "You break [src] apart, refunding some of the components used.")
+ for(var/i in component_refund)
+ generate_cache_component(i, src)
+ take_damage(max_integrity)
+ return 0
+ if(active)
+ return 0
+ var/turf/T = get_turf(src)
+ if(!T || !(T.z in GLOB.station_z_levels))
+ to_chat(user, "[src] must be on the station to function!")
+ return 0
+ if(SSshuttle.emergency.mode != SHUTTLE_CALL)
+ to_chat(user, "No emergency shuttles are attempting to arrive at the station!")
+ return 0
+ if(!try_use_power(get_delay_cost()))
+ to_chat(user, "[src] needs more power to function!")
+ return 0
+ delay_cost += delay_cost_increase
+ delay_remaining += PRISM_DELAY_DURATION
+ toggle(0, user)
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/process()
+ var/turf/own_turf = get_turf(src)
+ if(SSshuttle.emergency.mode != SHUTTLE_CALL || delay_remaining <= 0 || !own_turf || !(own_turf.z in GLOB.station_z_levels))
+ forced_disable(FALSE)
+ return
+ . = ..()
+ var/delay_amount = 40
+ delay_remaining -= delay_amount
+ var/efficiency = get_efficiency_mod()
+ SSshuttle.emergency.setTimer(SSshuttle.emergency.timeLeft(1) + (delay_amount * efficiency))
+ var/highest_y
+ var/highest_x
+ var/lowest_y
+ var/lowest_x
+ var/list/prism_turfs = list()
+ for(var/t in SSshuttle.emergency.ripple_area(SSshuttle.getDock("emergency_home")))
+ prism_turfs[t] = TRUE
+ var/turf/T = t
+ if(!highest_y || T.y > highest_y)
+ highest_y = T.y
+ if(!highest_x || T.x > highest_x)
+ highest_x = T.x
+ if(!lowest_y || T.y < lowest_y)
+ lowest_y = T.y
+ if(!lowest_x || T.x < lowest_x)
+ lowest_x = T.x
+ var/mean_y = Lerp(lowest_y, highest_y)
+ var/mean_x = Lerp(lowest_x, highest_x)
+ if(prob(50))
+ mean_y = Ceiling(mean_y)
+ else
+ mean_y = Floor(mean_y)
+ if(prob(50))
+ mean_x = Ceiling(mean_x)
+ else
+ mean_x = Floor(mean_x)
+ var/turf/semi_random_center_turf = locate(mean_x, mean_y, ZLEVEL_STATION_PRIMARY)
+ for(var/t in getline(src, semi_random_center_turf))
+ prism_turfs[t] = TRUE
+ var/placement_style = prob(50)
+ for(var/t in prism_turfs)
+ var/turf/T = t
+ if(placement_style)
+ if(IsOdd(T.x + T.y))
+ seven_random_hexes(T, efficiency)
+ else if(prob(50 * efficiency))
+ new /obj/effect/temp_visual/ratvar/prolonging_prism(T)
+ else
+ if(IsEven(T.x + T.y))
+ seven_random_hexes(T, efficiency)
+ else if(prob(50 * efficiency))
+ new /obj/effect/temp_visual/ratvar/prolonging_prism(T)
+ CHECK_TICK //we may be going over a hell of a lot of turfs
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/get_delay_cost()
+ return Floor(delay_cost, MIN_CLOCKCULT_POWER)
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/seven_random_hexes(turf/T, efficiency)
+ var/static/list/hex_states = list("prismhex1", "prismhex2", "prismhex3", "prismhex4", "prismhex5", "prismhex6", "prismhex7")
+ var/mutable_appearance/hex_combo
+ for(var/n in hex_states) //BUILD ME A HEXAGON
+ if(prob(50 * efficiency))
+ if(!hex_combo)
+ hex_combo = mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)
+ else
+ hex_combo.add_overlay(mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER))
+ if(hex_combo) //YOU BUILT A HEXAGON
+ hex_combo.pixel_x = -16
+ hex_combo.pixel_y = -16
+ hex_combo.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ hex_combo.plane = GAME_PLANE
+ new /obj/effect/temp_visual/ratvar/prolonging_prism(T, hex_combo)
diff --git a/code/modules/antagonists/clockcult/clock_structures/tinkerers_cache.dm b/code/modules/antagonists/clockcult/clock_structures/tinkerers_cache.dm
new file mode 100644
index 0000000000..cd33cf7adc
--- /dev/null
+++ b/code/modules/antagonists/clockcult/clock_structures/tinkerers_cache.dm
@@ -0,0 +1,116 @@
+//Tinkerer's cache: Stores components for later use.
+/obj/structure/destructible/clockwork/cache
+ name = "tinkerer's cache"
+ desc = "A large brass spire with a flaming hole in its center."
+ clockwork_desc = "A brass container capable of storing a large amount of components.\n\
+ Shares components with all other caches and will gradually generate components if near a Clockwork Wall."
+ icon_state = "tinkerers_cache"
+ unanchored_icon = "tinkerers_cache_unwrenched"
+ construction_value = 10
+ break_message = "The cache's fire winks out before it falls in on itself!"
+ max_integrity = 80
+ light_color = "#C2852F"
+ var/wall_generation_cooldown
+ var/turf/closed/wall/clockwork/linkedwall //if we've got a linked wall and are producing
+ var/static/linked_caches = 0 //how many caches are linked to walls; affects how fast components are produced
+
+/obj/structure/destructible/clockwork/cache/Initialize()
+ . = ..()
+ START_PROCESSING(SSobj, src)
+ GLOB.clockwork_caches++
+ update_slab_info()
+ set_light(2, 0.7)
+
+/obj/structure/destructible/clockwork/cache/Destroy()
+ GLOB.clockwork_caches--
+ update_slab_info()
+ STOP_PROCESSING(SSobj, src)
+ if(linkedwall)
+ linked_caches--
+ linkedwall.linkedcache = null
+ linkedwall = null
+ return ..()
+
+/obj/structure/destructible/clockwork/cache/process()
+ if(!anchored)
+ if(linkedwall)
+ linked_caches--
+ linkedwall.linkedcache = null
+ linkedwall = null
+ return
+ for(var/turf/closed/wall/clockwork/C in range(4, src))
+ if(!C.linkedcache && !linkedwall)
+ linked_caches++
+ C.linkedcache = src
+ linkedwall = C
+ wall_generation_cooldown = world.time + get_production_time()
+ visible_message("[src] starts to whirr in the presence of [C]...")
+ break
+ if(linkedwall && wall_generation_cooldown <= world.time)
+ wall_generation_cooldown = world.time + get_production_time()
+ var/component_id = generate_cache_component(null, src)
+ playsound(linkedwall, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1)
+ visible_message("Something cl[pick("ank", "ink", "unk", "ang")]s around inside of [src]...")
+
+/obj/structure/destructible/clockwork/cache/attackby(obj/item/I, mob/living/user, params)
+ if(!is_servant_of_ratvar(user))
+ return ..()
+ if(istype(I, /obj/item/clockwork/component))
+ var/obj/item/clockwork/component/C = I
+ if(!anchored)
+ to_chat(user, "[src] needs to be secured to place [C] into it!")
+ else
+ GLOB.clockwork_component_cache[C.component_id]++
+ update_slab_info()
+ to_chat(user, "You add [C] to [src].")
+ user.drop_item()
+ qdel(C)
+ return 1
+ else if(istype(I, /obj/item/clockwork/slab))
+ var/obj/item/clockwork/slab/S = I
+ if(!anchored)
+ to_chat(user, "[src] needs to be secured to offload your slab's components into it!")
+ else
+ for(var/i in S.stored_components)
+ GLOB.clockwork_component_cache[i] += S.stored_components[i]
+ S.stored_components[i] = 0
+ update_slab_info()
+ user.visible_message("[user] empties [S] into [src].", "You offload your slab's components into [src].")
+ return 1
+ else
+ return ..()
+
+/obj/structure/destructible/clockwork/cache/update_anchored(mob/user, do_damage)
+ ..()
+ if(anchored)
+ set_light(2, 0.7)
+ else
+ set_light(0)
+
+/obj/structure/destructible/clockwork/cache/attack_hand(mob/living/user)
+ ..()
+ if(is_servant_of_ratvar(user))
+ if(linkedwall)
+ if(wall_generation_cooldown > world.time)
+ var/temp_time = (wall_generation_cooldown - world.time) * 0.1
+ to_chat(user, "[src] will produce a component in [temp_time] second[temp_time == 1 ? "":"s"].")
+ else
+ to_chat(user, "[src] is about to produce a component!")
+ else if(anchored)
+ to_chat(user, "[src] is unlinked! Construct a Clockwork Wall nearby to generate components!")
+ else
+ to_chat(user, "[src] needs to be secured to generate components!")
+
+/obj/structure/destructible/clockwork/cache/examine(mob/user)
+ ..()
+ if(is_servant_of_ratvar(user) || isobserver(user))
+ if(linkedwall)
+ to_chat(user, "It is linked to a Clockwork Wall and will generate a component every [DisplayTimeText(get_production_time())]!")
+ else
+ to_chat(user, "It is unlinked! Construct a Clockwork Wall nearby to generate components!")
+ to_chat(user, "Stored components:")
+ for(var/i in GLOB.clockwork_component_cache)
+ to_chat(user, "[get_component_icon(i)] [get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]: [GLOB.clockwork_component_cache[i]]")
+
+/obj/structure/destructible/clockwork/cache/proc/get_production_time()
+ return (CACHE_PRODUCTION_TIME + (ACTIVE_CACHE_SLOWDOWN * linked_caches)) * get_efficiency_mod(TRUE)
diff --git a/code/modules/antagonists/clockcult/clock_structures/tinkerers_daemon.dm b/code/modules/antagonists/clockcult/clock_structures/tinkerers_daemon.dm
new file mode 100644
index 0000000000..4ceb7c3e26
--- /dev/null
+++ b/code/modules/antagonists/clockcult/clock_structures/tinkerers_daemon.dm
@@ -0,0 +1,171 @@
+//Tinkerer's Daemon: A machine that rapidly produces components at a power cost.
+/obj/structure/destructible/clockwork/powered/tinkerers_daemon
+ name = "tinkerer's daemon"
+ desc = "A strange machine with three small brass obelisks attached to it."
+ clockwork_desc = "An efficient machine that can rapidly produce components at a small power cost. It will only function if active daemons are outnumbered by servants at a rate to 5:1."
+ icon_state = "tinkerers_daemon"
+ active_icon = "tinkerers_daemon"
+ inactive_icon = "tinkerers_daemon"
+ unanchored_icon = "tinkerers_daemon_unwrenched"
+ max_integrity = 100
+ construction_value = 20
+ break_message = "The daemon shatters into millions of pieces, leaving only a disc of metal!"
+ debris = list(/obj/item/clockwork/alloy_shards/medium = 1, \
+ /obj/item/clockwork/alloy_shards/small = 6, \
+ /obj/item/clockwork/component/replicant_alloy/replication_plate = 1)
+ var/static/mutable_appearance/daemon_glow = mutable_appearance('icons/obj/clockwork_objects.dmi', "tinkerglow")
+ var/static/mutable_appearance/component_glow = mutable_appearance('icons/obj/clockwork_objects.dmi', "t_random_component")
+ var/component_id_to_produce
+ var/production_time = 0 //last time we produced a component
+ var/production_cooldown = 70
+
+/obj/structure/destructible/clockwork/powered/tinkerers_daemon/Destroy()
+ GLOB.active_daemons -= src
+ return ..()
+
+/obj/structure/destructible/clockwork/powered/tinkerers_daemon/examine(mob/user)
+ ..()
+ if(is_servant_of_ratvar(user) || isobserver(user))
+ if(active)
+ if(component_id_to_produce)
+ to_chat(user, "It is currently producing [get_component_name(component_id_to_produce)][component_id_to_produce != REPLICANT_ALLOY ? "s":""].")
+ else
+ to_chat(user, "It is currently producing random components.")
+ to_chat(user, "It will produce a component every [round((production_cooldown*0.1) * get_efficiency_mod(TRUE), 0.1)] seconds and requires at least the following power for each component type:")
+ for(var/i in GLOB.clockwork_component_cache)
+ to_chat(user, "[get_component_icon(i)] [get_component_name(i)]: [DisplayPower(get_component_cost(i))] ([GLOB.clockwork_component_cache[i]] exist[GLOB.clockwork_component_cache[i] == 1 ? "s" : ""])")
+
+/obj/structure/destructible/clockwork/powered/tinkerers_daemon/forced_disable(bad_effects)
+ if(active)
+ if(bad_effects)
+ try_use_power(MIN_CLOCKCULT_POWER*4)
+ visible_message("[src] shuts down with a horrible grinding noise!")
+ playsound(src, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, 1)
+ else
+ visible_message("[src] shuts down!")
+ toggle()
+ return TRUE
+
+/obj/structure/destructible/clockwork/powered/tinkerers_daemon/attack_hand(mob/living/user)
+ if(!is_servant_of_ratvar(user))
+ to_chat(user, "You place your hand on the daemon, but nothing happens.")
+ return
+ if(active)
+ toggle(0, user)
+ else
+ if(!anchored)
+ to_chat(user, "[src] needs to be secured to the floor before it can be activated!")
+ return FALSE
+ if(!GLOB.clockwork_caches)
+ to_chat(user, "\"You require a cache for this daemon to operate. Get to it.\"")
+ return
+ var/min_power_usable = 0
+ for(var/i in GLOB.clockwork_component_cache)
+ if(!min_power_usable)
+ min_power_usable = get_component_cost(i)
+ else
+ min_power_usable = min(min_power_usable, get_component_cost(i))
+ if(total_accessable_power() < min_power_usable)
+ to_chat(user, "\"You need more power to activate this daemon, friend.\"")
+ return
+ var/servants = 0
+ for(var/mob/living/L in GLOB.living_mob_list)
+ if(is_servant_of_ratvar(L))
+ servants++
+ if(servants * 0.2 < 1)
+ to_chat(user, "\"There are too few servants for daemons to work.\"")
+ return
+ var/choice = alert(user,"Activate Daemon...",,"Specific Component","Random Component","Cancel")
+ switch(choice)
+ if("Specific Component")
+ var/list/components = list()
+ for(var/i in GLOB.clockwork_component_cache)
+ components["[get_component_name(i)] ([DisplayPower(get_component_cost(i))])"] = i
+ var/input_component = input(user, "Choose a component type.", name) as null|anything in components
+ component_id_to_produce = components[input_component]
+ servants = 0
+ for(var/mob/living/L in GLOB.living_mob_list)
+ if(is_servant_of_ratvar(L))
+ servants++
+ if(!is_servant_of_ratvar(user) || !user.canUseTopic(src, !issilicon(user), NO_DEXTERY) || active || !GLOB.clockwork_caches || servants * 0.2 < 1)
+ return
+ if(!component_id_to_produce)
+ to_chat(user, "You decide not to select a component and activate the daemon.")
+ return
+ if(total_accessable_power() < get_component_cost(component_id_to_produce))
+ to_chat(user, "There is too little power to produce this type of component!")
+ return
+ toggle(0, user)
+ if("Random Component")
+ component_id_to_produce = null
+ servants = 0
+ for(var/mob/living/L in GLOB.living_mob_list)
+ if(is_servant_of_ratvar(L))
+ servants++
+ if(!is_servant_of_ratvar(user) || !user.canUseTopic(src, !issilicon(user), NO_DEXTERY) || active || !GLOB.clockwork_caches || servants * 0.2 < 1)
+ return
+ toggle(0, user)
+
+/obj/structure/destructible/clockwork/powered/tinkerers_daemon/toggle(fast_process, mob/living/user)
+ . = ..()
+ if(active)
+ GLOB.active_daemons += src
+ var/component_color = get_component_color(component_id_to_produce)
+ daemon_glow.color = component_color
+ add_overlay(daemon_glow)
+ component_glow.icon_state = "t_[component_id_to_produce ? component_id_to_produce :"random_component"]"
+ component_glow.color = component_color
+ add_overlay(component_glow)
+ production_time = world.time + production_cooldown //don't immediately produce when turned on after being off
+ set_light(2, 0.9, get_component_color_bright(component_id_to_produce))
+ else
+ GLOB.active_daemons -= src
+ cut_overlays()
+ set_light(0)
+
+/obj/structure/destructible/clockwork/powered/tinkerers_daemon/proc/get_component_cost(id)
+ return max(MIN_CLOCKCULT_POWER*2, (MIN_CLOCKCULT_POWER*2) * (1 + round(GLOB.clockwork_component_cache[id] * 0.2)))
+
+/obj/structure/destructible/clockwork/powered/tinkerers_daemon/process()
+ var/servants = 0
+ for(var/mob/living/L in GLOB.living_mob_list)
+ if(is_servant_of_ratvar(L))
+ servants++
+ while(servants * 0.2 < LAZYLEN(GLOB.active_daemons))
+ var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = GLOB.active_daemons[1]
+ if(!istype(D))
+ break
+ if(D.active)
+ D.forced_disable(FALSE)
+ if(D == src)
+ return
+ . = ..()
+ var/min_power_usable = 0
+ if(!component_id_to_produce)
+ for(var/i in GLOB.clockwork_component_cache)
+ if(!min_power_usable)
+ min_power_usable = get_component_cost(i)
+ else
+ min_power_usable = min(min_power_usable, get_component_cost(i))
+ else
+ min_power_usable = get_component_cost(component_id_to_produce)
+ if(!GLOB.clockwork_caches || . < min_power_usable) //if we don't have enough to produce the lowest or what we chose to produce, cancel out
+ forced_disable(FALSE)
+ return
+ if(production_time <= world.time)
+ var/component_to_generate = component_id_to_produce
+ if(!component_to_generate)
+ component_to_generate = get_weighted_component_id() //more likely to generate components that we have less of
+ if(!try_use_power(get_component_cost(component_to_generate)))
+ component_to_generate = null
+ if(!component_id_to_produce)
+ for(var/i in GLOB.clockwork_component_cache)
+ if(try_use_power(get_component_cost(i))) //if we fail but are producing random, try and get a different component to produce
+ component_to_generate = i
+ break
+ if(component_to_generate)
+ generate_cache_component(component_to_generate, src)
+ production_time = world.time + (production_cooldown * get_efficiency_mod(TRUE)) //go on cooldown
+ visible_message("[src] hums as it produces a component.")
+ else
+ forced_disable(FALSE) //we shouldn't actually ever get here, as we should cancel out way before this