Adds things to help the cult become station based

Adds (or re-adds I guess) the old spells and stuctures from parts based clock cult, soon to be meant for construction/power generation as well as possible QoL things
This commit is contained in:
Keate Senior
2020-07-09 16:30:52 -04:00
parent bdaaa6d944
commit 928a7a956f
8 changed files with 1091 additions and 0 deletions
@@ -124,3 +124,434 @@
#undef MARAUDER_SLOWDOWN_PERCENTAGE
#undef MARAUDER_SHIELD_REGEN_TIME
/*//Clockwork guardian: Slow but with high damage, resides inside of a servant. Created via the Memory Allocation scripture.
/mob/living/simple_animal/hostile/clockwork/marauder/guardian
name = "clockwork guardian"
desc = "A stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield and stands ready by its master."
icon_state = "clockwork_marauder"
health = 300
maxHealth = 300
speed = 1
obj_damage = 40
melee_damage_lower = 12
melee_damage_upper = 12
attacktext = "slashes"
attack_sound = 'sound/weapons/bladeslice.ogg'
weather_immunities = list("lava")
movement_type = FLYING
loot = list(/obj/item/clockwork/component/geis_capacitor/fallen_armor)
var/true_name = "Meme Master 69" //Required to call forth the guardian
var/global/list/possible_true_names = list("Servant", "Warden", "Serf", "Page", "Usher", "Knave", "Vassal", "Escort")
var/mob/living/host //The mob that the guardian is living inside of
var/recovering = FALSE //If the guardian is recovering from recalling
var/blockchance = 17 //chance to block attacks entirely
var/counterchance = 30 //chance to counterattack after blocking
var/static/list/damage_heal_order = list(OXY, BURN, BRUTE, TOX) //we heal our host's damage in this order
light_range = 2
light_power = 1.1
playstyle_string = "<span class='sevtug'>You are a clockwork guardian</span><b>, 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 <span class='sevtug_small'><i>:b</i></span> 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.</span>"
/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, "<span class='userdanger'>Your strength has returned. You can once again come forward!</span>")
to_chat(host, "<span class='userdanger'>Your guardian is now strong enough to come forward again!</span>")
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, "<span class='userdanger'>Your host is dead!</span>")
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, "<span class='userdanger'>You're too far from your host and rapidly taking damage!</span>")
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, "<span class='userdanger'>You're too far from your host and rapidly taking damage!</span>")
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/death(gibbed)
emerge_from_host(FALSE, TRUE)
unbind_from_host()
visible_message("<span class='warning'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
"<span class='userdanger'>Your equipment falls away. You feel a moment of confusion before your fragile form is annihilated.</span>")
. = ..()
/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, "<span class='userdanger'>The presence of a brandished holy artifact weakens your armor!</span>")
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 = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>HOST<br>[resulthealth]</font></div>"
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>[round((health / maxHealth) * 100, 0.5)]%</font>"
/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("<span class='boldannounce'>[src] blocks [target && isitem(textobject) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>", \
"<span class='userdanger'>You block [target && isitem(textobject) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>")
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 = "<span class='sevtug'>[src] ([true_name])</span>"
message = "<span class='sevtug_small'>\"[message]\"</span>" //Processed output
to_chat(src, "[name_part]<span class='sevtug_small'>:</span> [message]")
to_chat(host, "[name_part]<span class='sevtug_small'>:</span> [message]")
for(var/M in GLOB.mob_list)
if(isobserver(M))
var/link = FOLLOW_LINK(M, src)
to_chat(M, "[link] [name_part] <span class='sevtug_small'>(to</span> <span class='sevtug'>[findtextEx(host.name, host.real_name) ? "[host.name]" : "[host.real_name] (as [host.name])"]</span><span class='sevtug_small'>):</span> [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, "<span class='warning'>You don't have a host!</span>")
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("<span class='warning'>[host]'s skin flashes crimson!</span>", "<span class='sevtug'>You feel [true_name]'s consciousness settle in your mind.</span>")
visible_message("<span class='warning'>[src] suddenly disappears!</span>", "<span class='sevtug'>You return to [host].</span>")
forceMove(host)
if(resulthealth > GUARDIAN_EMERGE_THRESHOLD && health != maxHealth)
recovering = TRUE
to_chat(src, "<span class='userdanger'>You have weakened and will need to recover before manifesting again!</span>")
to_chat(host, "<span class='sevtug'>[true_name] has weakened and will need to recover before manifesting again!</span>")
return TRUE
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/try_emerge()
if(!host)
to_chat(src, "<span class='warning'>You don't have a host!</span>")
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, "<span class='warning'>Your host must be at [GUARDIAN_EMERGE_THRESHOLD]% or less health to emerge like this!</span>")
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, "<span class='sevtug'>[true_name] is too weak to come forth!</span>")
else
to_chat(host, "<span class='sevtug'>[true_name] tries to emerge to protect you, but it's too weak!</span>")
to_chat(src, "<span class='userdanger'>You try to come forth, but you're too weak!</span>")
return FALSE
if(!force)
if(hostchosen) //guardian approved
to_chat(host, "<span class='sevtug'>Your words echo with power as [true_name] emerges from your body!</span>")
else
to_chat(host, "<span class='sevtug'>[true_name] emerges from your body to protect you!</span>")
forceMove(host.loc)
visible_message("<span class='warning'>[host]'s skin glows red as [name] emerges from their body!</span>", "<span class='sevtug_small'>You exit the safety of [host]'s body!</span>")
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, "<span class='warning'>Your guardian seems to have been destroyed!</span>")
return FALSE
var/name_part = "<span class='sevtug'>Servant [findtextEx(owner.name, owner.real_name) ? "[owner.name]" : "[owner.real_name] (as [owner.name])"]</span>"
message = "<span class='sevtug_small'>\"[message]\"</span>" //Processed output
to_chat(owner, "[name_part]<span class='sevtug_small'>:</span> [message]")
to_chat(linked_guardian, "[name_part]<span class='sevtug_small'>:</span> [message]")
for(var/M in GLOB.mob_list)
if(isobserver(M))
var/link = FOLLOW_LINK(M, src)
to_chat(M, "[link] [name_part] <span class='sevtug_small'>(to</span> <span class='sevtug'>[linked_guardian] ([linked_guardian.true_name])</span><span class='sevtug_small'>):</span> [message]")
return TRUE
*/
@@ -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 = "<span class='brass'>You form a prolonging prism, which will delay the arrival of an emergency shuttle at a massive power cost.</span>"
observer_message = "<span class='warning'>An onyx prism forms in midair and sprouts tendrils to support itself!</span>"
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, "<span class='inathneq'>\"It is too late to construct one of these, champion.\"</span>")
return FALSE
var/turf/T = get_turf(invoker)
if(!T || !(T.z in GLOB.station_z_levels))
to_chat(invoker, "<span class='inathneq'>\"You must be on the station to construct one of these, champion.\"</span>")
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 = "<span class='brass'>You form a tinkerer's daemon which can rapidly collect components at a power cost.</span>"
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.<br>\
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, "<span class='warning'>You can only house one marauder at a time!</span>")
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("<span class='warning'>A purple tendril appears from [invoker]'s [slab.name] and impales itself in [invoker.p_their()] forehead!</span>", \
"<span class='sevtug'>A tendril flies from [slab] into your forehead. You begin waiting while it painfully rearranges your thought pattern...</span>")
invoker.notransform = TRUE //Vulnerable during the process
slab.busy = "Thought Modification in progress"
if(!do_after(invoker, 50, target = invoker))
invoker.visible_message("<span class='warning'>The tendril, covered in blood, retracts from [invoker]'s head and back into the [slab.name]!</span>", \
"<span class='userdanger'>Total agony overcomes you as the tendril is forced out early!</span>")
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, "<span class='warning'>The tendril shivers slightly as it selects a marauder...</span>")
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("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
"<span class='warning'>The tendril was unsuccessful! Perhaps you should try again another time.</span>")
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("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
"<span class='sevtug'>[M.true_name], a clockwork marauder, has taken up residence in your mind. Communicate with it via the \"Linked Minds\" action button.</span>")
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"
@@ -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.<br><b>Click your slab to disable.</b>"
slab_overlay = "geis"
ranged_type = /obj/effect/proc_holder/slab/geis
ranged_message = "<span class='sevtug_small'><i>You charge the clockwork slab with divine energy.</i>\n\
<b>Left-click a target within melee range to bind!\n\
Click your slab to cancel.</b></span>"
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 = "<span class='brass'>You form a tinkerer's cache, which is capable of storing components, which will automatically be used by slabs.</span>"
observer_message = "<span class='warning'>A hollow brass spire rises and begins to blaze!</span>"
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
*/
@@ -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, "<span class='big_brass'>\"I am already here, idiot.\"</span>")
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, "<span class='userdanger'>There is already an Ark at [gate_area.map_name]!</span>")
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, "<span class='warning'>You must be on the station to activate the Ark!</span>")
return FALSE
if(GLOB.clockwork_gateway_activated)
to_chat(invoker, "<span class='warning'>Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!</span>")
return FALSE
return ..()
@@ -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.<br><b>Maximum 15 chants.</b>"
/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
*/
@@ -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 = "<span class='warning'>The prism falls to the ground with a heavy thud!</span>"
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, "<span class='inathneq'>An emergency shuttle has arrived and this prism is no longer useful; attempt to activate it to gain a partial refund of components used.</span>")
else
var/efficiency = get_efficiency_mod(TRUE)
to_chat(user, "<span class='inathneq_small'>It requires at least <b>[DisplayPower(get_delay_cost())]</b> of power to attempt to delay the arrival of an emergency shuttle by <b>[2 * efficiency]</b> minutes.</span>")
to_chat(user, "<span class='inathneq_small'>This cost increases by <b>[DisplayPower(delay_cost_increase)]</b> for every previous activation.</span>")
/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("<span class='warning'>[src] emits an airy chuckling sound and falls dark!</span>")
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, "<span class='brass'>You break [src] apart, refunding some of the components used.</span>")
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, "<span class='warning'>[src] must be on the station to function!</span>")
return 0
if(SSshuttle.emergency.mode != SHUTTLE_CALL)
to_chat(user, "<span class='warning'>No emergency shuttles are attempting to arrive at the station!</span>")
return 0
if(!try_use_power(get_delay_cost()))
to_chat(user, "<span class='warning'>[src] needs more power to function!</span>")
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)
@@ -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 = "<span class='warning'>The cache's fire winks out before it falls in on itself!</span>"
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("<span class='warning'>[src] starts to whirr in the presence of [C]...</span>")
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("<span class='[get_component_span(component_id)]'>Something</span><span class='warning'> cl[pick("ank", "ink", "unk", "ang")]s around inside of [src]...</span>")
/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, "<span class='warning'>[src] needs to be secured to place [C] into it!</span>")
else
GLOB.clockwork_component_cache[C.component_id]++
update_slab_info()
to_chat(user, "<span class='notice'>You add [C] to [src].</span>")
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, "<span class='warning'>[src] needs to be secured to offload your slab's components into it!</span>")
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("<span class='notice'>[user] empties [S] into [src].</span>", "<span class='notice'>You offload your slab's components into [src].</span>")
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, "<span class='alloy'>[src] will produce a component in <b>[temp_time]</b> second[temp_time == 1 ? "":"s"].</span>")
else
to_chat(user, "<span class='brass'>[src] is about to produce a component!</span>")
else if(anchored)
to_chat(user, "<span class='alloy'>[src] is unlinked! Construct a Clockwork Wall nearby to generate components!</span>")
else
to_chat(user, "<span class='alloy'>[src] needs to be secured to generate components!</span>")
/obj/structure/destructible/clockwork/cache/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
if(linkedwall)
to_chat(user, "<span class='brass'>It is linked to a Clockwork Wall and will generate a component every <b>[DisplayTimeText(get_production_time())]</b>!</span>")
else
to_chat(user, "<span class='alloy'>It is unlinked! Construct a Clockwork Wall nearby to generate components!</span>")
to_chat(user, "<b>Stored components:</b>")
for(var/i in GLOB.clockwork_component_cache)
to_chat(user, "[get_component_icon(i)] <span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[GLOB.clockwork_component_cache[i]]</b></span>")
/obj/structure/destructible/clockwork/cache/proc/get_production_time()
return (CACHE_PRODUCTION_TIME + (ACTIVE_CACHE_SLOWDOWN * linked_caches)) * get_efficiency_mod(TRUE)
@@ -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 = "<span class='warning'>The daemon shatters into millions of pieces, leaving only a disc of metal!</span>"
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, "<span class='[get_component_span(component_id_to_produce)]_small'>It is currently producing [get_component_name(component_id_to_produce)][component_id_to_produce != REPLICANT_ALLOY ? "s":""].</span>")
else
to_chat(user, "<span class='brass'>It is currently producing random components.</span>")
to_chat(user, "<span class='nezbere_small'>It will produce a component every <b>[round((production_cooldown*0.1) * get_efficiency_mod(TRUE), 0.1)]</b> seconds and requires at least the following power for each component type:</span>")
for(var/i in GLOB.clockwork_component_cache)
to_chat(user, "[get_component_icon(i)] <span class='[get_component_span(i)]_small'><i>[get_component_name(i)]:</i> <b>[DisplayPower(get_component_cost(i))]</b> <i>([GLOB.clockwork_component_cache[i]] exist[GLOB.clockwork_component_cache[i] == 1 ? "s" : ""])</i></span>")
/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("<span class='warning'>[src] shuts down with a horrible grinding noise!</span>")
playsound(src, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, 1)
else
visible_message("<span class='warning'>[src] shuts down!</span>")
toggle()
return TRUE
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user))
to_chat(user, "<span class='warning'>You place your hand on the daemon, but nothing happens.</span>")
return
if(active)
toggle(0, user)
else
if(!anchored)
to_chat(user, "<span class='warning'>[src] needs to be secured to the floor before it can be activated!</span>")
return FALSE
if(!GLOB.clockwork_caches)
to_chat(user, "<span class='nezbere'>\"You require a cache for this daemon to operate. Get to it.\"</span>")
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, "<span class='nezbere'>\"You need more power to activate this daemon, friend.\"</span>")
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, "<span class='nezbere'>\"There are too few servants for daemons to work.\"</span>")
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, "<span class='warning'>You decide not to select a component and activate the daemon.</span>")
return
if(total_accessable_power() < get_component_cost(component_id_to_produce))
to_chat(user, "<span class='warning'>There is too little power to produce this type of component!</span>")
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("<span class='warning'>[src] hums as it produces a </span><span class='[get_component_span(component_to_generate)]'>component</span><span class='warning'>.</span>")
else
forced_disable(FALSE) //we shouldn't actually ever get here, as we should cancel out way before this