From 09b426df79bbcf7078ba7e98d92373d70128a3f2 Mon Sep 17 00:00:00 2001 From: Joan Lung Date: Tue, 25 Oct 2016 16:50:04 -0400 Subject: [PATCH] Splits various massive clockwork cult code files up into various folders (#21177) * Splits various massive clockwork cult code files up into various folders * JUST1C4R * 4BSURD * this is faintly horrifying to look at * that's right i don't need to double it, just to swap the order --- code/game/gamemodes/clock_cult/clock_cult.dm | 33 +- .../game/gamemodes/clock_cult/clock_effect.dm | 25 + .../clock_cult/clock_effects/clock_overlay.dm | 46 + .../clock_cult/clock_effects/clock_sigils.dm | 329 +++++ .../clock_effects/general_markers.dm | 57 + .../clock_effects/spatial_gateway.dm | 186 +++ .../{ => clock_helpers}/clock_powerdrain.dm | 0 .../clock_helpers/component_helpers.dm | 118 ++ .../clock_helpers/hierophant_network.dm | 47 + .../proselytizer_helpers.dm} | 161 +-- .../clock_helpers/ratvarian_language.dm | 107 ++ .../clock_helpers/scripture_checks.dm | 37 + .../{clock_armor.dm => clockwork_armor.dm} | 0 .../clock_items/clockwork_proselytizer.dm | 150 +++ .../{clock_slab.dm => clockwork_slab.dm} | 0 .../gamemodes/clock_cult/clock_machines.dm | 676 ---------- .../gamemodes/clock_cult/clock_scripture.dm | 1171 +---------------- .../scripture_applications.dm | 257 ++++ .../clock_scriptures/scripture_drivers.dm | 279 ++++ .../clock_scriptures/scripture_judgement.dm | 108 ++ .../clock_scriptures/scripture_revenant.dm | 228 ++++ .../clock_scriptures/scripture_scripts.dm | 292 ++++ .../gamemodes/clock_cult/clock_structure.dm | 200 +++ .../gamemodes/clock_cult/clock_structures.dm | 928 ------------- .../ark_of_the_clockwork_justicar.dm} | 215 +-- .../clock_structures/clock_shells.dm | 47 + .../clock_structures/clockwork_obelisk.dm | 69 + .../clock_structures/interdiction_lens.dm | 96 ++ .../clock_structures/mania_motor.dm | 135 ++ .../clock_structures/mending_motor.dm | 105 ++ .../clock_structures/ocular_warden.dm | 90 ++ .../ratvar_the_clockwork_justicar.dm | 143 ++ .../clock_structures/tinkerers_cache.dm | 89 ++ .../clock_structures/tinkerers_daemon.dm | 130 ++ .../clock_cult/clock_structures/wall_gear.dm | 56 + .../gamemodes/clock_cult/clock_unsorted.dm | 372 ------ code/modules/mob/living/living_defense.dm | 2 +- tgstation.dme | 39 +- 38 files changed, 3534 insertions(+), 3489 deletions(-) create mode 100644 code/game/gamemodes/clock_cult/clock_effect.dm create mode 100644 code/game/gamemodes/clock_cult/clock_effects/clock_overlay.dm create mode 100644 code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm create mode 100644 code/game/gamemodes/clock_cult/clock_effects/general_markers.dm create mode 100644 code/game/gamemodes/clock_cult/clock_effects/spatial_gateway.dm rename code/game/gamemodes/clock_cult/{ => clock_helpers}/clock_powerdrain.dm (100%) create mode 100644 code/game/gamemodes/clock_cult/clock_helpers/component_helpers.dm create mode 100644 code/game/gamemodes/clock_cult/clock_helpers/hierophant_network.dm rename code/game/gamemodes/clock_cult/{clock_items/clock_proselytizer.dm => clock_helpers/proselytizer_helpers.dm} (63%) create mode 100644 code/game/gamemodes/clock_cult/clock_helpers/ratvarian_language.dm create mode 100644 code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm rename code/game/gamemodes/clock_cult/clock_items/{clock_armor.dm => clockwork_armor.dm} (100%) create mode 100644 code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm rename code/game/gamemodes/clock_cult/clock_items/{clock_slab.dm => clockwork_slab.dm} (100%) delete mode 100644 code/game/gamemodes/clock_cult/clock_machines.dm create mode 100644 code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm create mode 100644 code/game/gamemodes/clock_cult/clock_scriptures/scripture_drivers.dm create mode 100644 code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm create mode 100644 code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm create mode 100644 code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structure.dm delete mode 100644 code/game/gamemodes/clock_cult/clock_structures.dm rename code/game/gamemodes/clock_cult/{clock_ratvar.dm => clock_structures/ark_of_the_clockwork_justicar.dm} (51%) create mode 100644 code/game/gamemodes/clock_cult/clock_structures/clock_shells.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/interdiction_lens.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/mending_motor.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/tinkerers_cache.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/tinkerers_daemon.dm create mode 100644 code/game/gamemodes/clock_cult/clock_structures/wall_gear.dm delete mode 100644 code/game/gamemodes/clock_cult/clock_unsorted.dm diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 0f1e5ef2231..84e9c7ae1ab 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -17,14 +17,17 @@ Game-wise, clockwork slabs will generate components over time, with more powerfu This file's folder contains: clock_cult.dm: Core gamemode files. - clock_items.dm: Items (excluding the proselytizer). - clock_machines.dm: Machinery like the mending motor. - clock_mobs.dm: Hostile and benign clockwork creatures. - clock_proselytizer: The clockwork proselytizer and all of its special interactions. - clock_ratvar.dm: The Ark of the Clockwork Justiciar and Ratvar himself. Important enough to have his own file. - clock_scripture.dm: Scripture and rites. - clock_structures.dm: Structures and effects - clock_unsorted.dm: Anything else with no place to be + clock_effect.dm: The base clockwork effect code. + - Effect files are in game/gamemodes/clock_cult/clock_effects/ + clock_item.dm: The base clockwork item code. + - Item files are in game/gamemodes/clock_cult/clock_items/ + clock_mobs.dm: Hostile clockwork creatures. + clock_scripture.dm: The base Scripture code. + - Scripture files are in game/gamemodes/clock_cult/clock_scripture/ + clock_structure.dm: The base clockwork structure code, including clockwork machines. + - Structure files, and Ratvar, are in game/gamemodes/clock_cult/clock_structures/ + + game/gamemodes/clock_cult/clock_helpers/ contains several helper procs, including the Ratvarian language. clockcult defines are in __DEFINES/clockcult.dm @@ -47,19 +50,19 @@ Credit where due: /proc/is_eligible_servant(mob/living/M) if(!istype(M)) - return 0 + return FALSE if(M.mind) if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain"))) - return 0 + return FALSE if(M.mind.enslaved_to && !is_servant_of_ratvar(M.mind.enslaved_to)) - return 0 + return FALSE else - return 0 + return FALSE if(iscultist(M) || isconstruct(M) || M.isloyal()) - return 0 + return FALSE if(ishuman(M) || isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab)) - return 1 - return 0 + return TRUE + return FALSE /proc/add_servant_of_ratvar(mob/living/L, silent = FALSE) var/update_type = /datum/antagonist/clockcultist diff --git a/code/game/gamemodes/clock_cult/clock_effect.dm b/code/game/gamemodes/clock_cult/clock_effect.dm new file mode 100644 index 00000000000..69e973b4eb9 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_effect.dm @@ -0,0 +1,25 @@ +//The base clockwork effect. Can have an alternate desc and will show up in the list of clockwork objects. +/obj/effect/clockwork + name = "meme machine" + desc = "Still don't know what it is." + var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description + icon = 'icons/effects/clockwork_effects.dmi' + icon_state = "ratvars_flame" + anchored = 1 + density = 0 + opacity = 0 + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + +/obj/effect/clockwork/New() + ..() + all_clockwork_objects += src + +/obj/effect/clockwork/Destroy() + all_clockwork_objects -= src + return ..() + +/obj/effect/clockwork/examine(mob/user) + if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc) + desc = clockwork_desc + ..() + desc = initial(desc) \ No newline at end of file diff --git a/code/game/gamemodes/clock_cult/clock_effects/clock_overlay.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_overlay.dm new file mode 100644 index 00000000000..9115b57885d --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_effects/clock_overlay.dm @@ -0,0 +1,46 @@ +//an "overlay" used by clockwork walls and floors to appear normal to mesons. +/obj/effect/clockwork/overlay + mouse_opacity = 0 + var/atom/linked + +/obj/effect/clockwork/overlay/examine(mob/user) + if(linked) + linked.examine(user) + +/obj/effect/clockwork/overlay/ex_act() + return FALSE + +/obj/effect/clockwork/overlay/singularity_pull(S, current_size) + return + +/obj/effect/clockwork/overlay/Destroy() + if(linked) + linked = null + ..() + return QDEL_HINT_PUTINPOOL + +/obj/effect/clockwork/overlay/wall + name = "clockwork wall" + icon = 'icons/turf/walls/clockwork_wall.dmi' + icon_state = "clockwork_wall" + canSmoothWith = list(/obj/effect/clockwork/overlay/wall, /obj/structure/falsewall/brass) + smooth = SMOOTH_TRUE + layer = CLOSED_TURF_LAYER + +/obj/effect/clockwork/overlay/wall/New() + ..() + queue_smooth_neighbors(src) + addtimer(GLOBAL_PROC, "queue_smooth", 1, FALSE, src) + +/obj/effect/clockwork/overlay/wall/Destroy() + queue_smooth_neighbors(src) + ..() + return QDEL_HINT_QUEUE + +/obj/effect/clockwork/overlay/floor + icon = 'icons/turf/floors.dmi' + icon_state = "clockwork_floor" + layer = TURF_LAYER + +/obj/effect/clockwork/overlay/floor/bloodcult //this is used by BLOOD CULT, it shouldn't use such a path... + icon_state = "cult" \ No newline at end of file diff --git a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm new file mode 100644 index 00000000000..d1ae6f42677 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm @@ -0,0 +1,329 @@ +//Sigils: Rune-like markings on the ground with various effects. +/obj/effect/clockwork/sigil + name = "sigil" + desc = "A strange set of markings drawn on the ground." + clockwork_desc = "A sigil of some purpose." + icon_state = "sigil" + layer = LOW_OBJ_LAYER + alpha = 50 + resistance_flags = NONE + var/affects_servants = FALSE + var/stat_affected = CONSCIOUS + var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]" + +/obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params) + if(I.force && !is_servant_of_ratvar(user)) + user.visible_message("[user] scatters [src] with [I]!", "You scatter [src] with [I]!") + qdel(src) + return 1 + ..() + +/obj/effect/clockwork/sigil/attack_hand(mob/user) + if(iscarbon(user) && !user.stat && (!is_servant_of_ratvar(user) || (is_servant_of_ratvar(user) && user.a_intent == "harm"))) + user.visible_message("[user] stamps out [src]!", "You stomp on [src], scattering it into thousands of particles.") + qdel(src) + return 1 + ..() + +/obj/effect/clockwork/sigil/ex_act(severity) + visible_message("[src] scatters into thousands of particles.") + qdel(src) + +/obj/effect/clockwork/sigil/Crossed(atom/movable/AM) + ..() + if(isliving(AM)) + var/mob/living/L = AM + if(L.stat <= stat_affected) + if((!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && affects_servants)) && L.mind) + if(L.null_rod_check()) + var/obj/item/I = L.null_rod_check() + L.visible_message("[L]'s [I.name] [resist_string], protecting them from [src]'s effects!", \ + "Your [I.name] [resist_string], protecting you!") + return + sigil_effects(L) + return 1 + +/obj/effect/clockwork/sigil/proc/sigil_effects(mob/living/L) + + +//Sigil of Transgression: Stuns the first non-servant to walk on it and flashes all nearby non_servants. Nar-Sian cultists are damaged and knocked down for a longer stun +/obj/effect/clockwork/sigil/transgression + name = "dull sigil" + desc = "A dull, barely-visible golden sigil. It's as though light was carved into the ground." + icon = 'icons/effects/clockwork_effects.dmi' + clockwork_desc = "A sigil that will stun the first non-servant to cross it. Nar-Sie's dogs will be knocked down." + icon_state = "sigildull" + color = "#FAE48C" + +/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L) + var/target_flashed = L.flash_act() + for(var/mob/living/M in viewers(5, src)) + if(!is_servant_of_ratvar(M) && M != L) + M.flash_act() + if(iscultist(L)) + L << "\"Watch your step, wretch.\"" + L.adjustBruteLoss(10) + L.Weaken(7) + L.visible_message("[src] appears around [L] in a burst of light!", \ + "[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!") + L.Stun(5) + PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/transgression, get_turf(src)) + qdel(src) + return 1 + + +//Sigil of Submission: After a short time, converts any non-servant standing on it. Knocks down and silences them for five seconds afterwards. +/obj/effect/clockwork/sigil/submission + name = "ominous sigil" + desc = "A luminous golden sigil. Something about it really bothers you." + clockwork_desc = "A sigil that will enslave the first person to cross it, provided they remain on it for seven seconds." + icon_state = "sigilsubmission" + color = "#FAE48C" + alpha = 125 + stat_affected = UNCONSCIOUS + resist_string = "glows faintly yellow" + var/convert_time = 70 + var/glow_light = 2 //soft light + var/glow_falloff = 1 + var/delete_on_finish = TRUE + var/sigil_name = "Sigil of Submission" + var/glow_type + +/obj/effect/clockwork/sigil/submission/New() + ..() + SetLuminosity(glow_light,glow_falloff) + +/obj/effect/clockwork/sigil/submission/proc/post_channel(mob/living/L) + +/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L) + L.visible_message("[src] begins to glow a piercing magenta!", "You feel something start to invade your mind...") + animate(src, color = "#AF0AAF", time = convert_time) + var/obj/effect/overlay/temp/ratvar/sigil/glow + if(glow_type) + glow = PoolOrNew(glow_type, get_turf(src)) + animate(glow, alpha = 255, time = convert_time) + var/I = 0 + while(I < convert_time && get_turf(L) == get_turf(src)) + I++ + sleep(1) + if(get_turf(L) != get_turf(src)) + if(glow) + qdel(glow) + animate(src, color = initial(color), time = 20) + visible_message("[src] slowly stops glowing!") + return 0 + post_channel(L) + if(is_eligible_servant(L)) + L << "\"You belong to me now.\"" + add_servant_of_ratvar(L) + L.Weaken(3) //Completely defenseless for about five seconds - mainly to give them time to read over the information they've just been presented with + L.Stun(3) + if(iscarbon(L)) + var/mob/living/carbon/C = L + C.silent += 5 + var/message = "[sigil_name] in [get_area(src)] [is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]" + for(var/M in mob_list) + if(isobserver(M)) + var/link = FOLLOW_LINK(M, L) + M << "[link] [message] [L.real_name]!" + else if(is_servant_of_ratvar(M)) + if(M == L) + M << "[message] you!" + else + M << "[message] [L.real_name]!" + if(delete_on_finish) + qdel(src) + else + animate(src, color = initial(color), time = 20) + visible_message("[src] slowly stops glowing!") + return 1 + + +//Sigil of Accession: After a short time, converts any non-servant standing on it though implants. Knocks down and silences them for five seconds afterwards. +/obj/effect/clockwork/sigil/submission/accession + name = "terrifying sigil" + desc = "A luminous brassy sigil. Something about it makes you want to flee." + clockwork_desc = "A sigil that will enslave any person who crosses it, provided they remain on it for seven seconds. \n\ + It can convert a mindshielded target once before disppearing, but can convert any number of non-implanted targets." + icon_state = "sigiltransgression" + color = "#A97F1B" + alpha = 200 + glow_light = 4 //bright light + glow_falloff = 3 + delete_on_finish = FALSE + sigil_name = "Sigil of Accession" + glow_type = /obj/effect/overlay/temp/ratvar/sigil/accession + resist_string = "glows bright orange" + +/obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L) + if(L.isloyal()) + var/mob/living/carbon/C = L + delete_on_finish = TRUE + C.visible_message("[C] visibly trembles!", \ + "[text2ratvar("You will be mine and his. This puny trinket will not stop me.")]") + for(var/obj/item/weapon/implant/mindshield/M in C.implants) + qdel(M) + + +//Sigil of Transmission: Stores power for clockwork machinery, serving as a battery. +/obj/effect/clockwork/sigil/transmission + name = "suspicious sigil" + desc = "A glowing orange sigil. The air around it feels staticky." + clockwork_desc = "A sigil that will serve as a battery for clockwork structures. Use Volt Void while standing on it to charge it." + icon_state = "sigiltransmission" + color = "#EC8A2D" + alpha = 50 + resist_string = "glows faintly" + var/power_charge = REPLICANT_ALLOY_POWER //starts with REPLICANT_ALLOY_POWER by default + +/obj/effect/clockwork/sigil/transmission/ex_act(severity) + if(severity == 3) + modify_charge(-500) + visible_message("[src] flares a brilliant orange!") + else + ..() + +/obj/effect/clockwork/sigil/transmission/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "It is storing [power_charge]W of power." + +/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L) + if(power_charge) + L << "You feel a slight, static shock." + return 1 + +/obj/effect/clockwork/sigil/transmission/New() + ..() + alpha = min(initial(alpha) + power_charge*0.02, 255) + +/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount) + if(power_charge - amount < 0) + return 0 + power_charge -= amount + alpha = min(initial(alpha) + power_charge*0.02, 255) + return 1 + + +//Vitality Matrix: Drains health from non-servants to heal or even revive servants. +/obj/effect/clockwork/sigil/vitality + name = "comforting sigil" + desc = "A faint blue sigil. Looking at it makes you feel protected." + clockwork_desc = "A sigil that will drain non-servants that remain on it. Servants that remain on it will be healed if it has any vitality drained." + icon_state = "sigilvitality" + color = "#123456" + alpha = 75 + affects_servants = TRUE + stat_affected = DEAD + resist_string = "glows shimmering yellow" + var/vitality = 0 + var/base_revive_cost = 20 + var/sigil_active = FALSE + var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets + +/obj/effect/clockwork/sigil/vitality/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "It is storing [ratvar_awakens ? "INFINITE":"[vitality]"] units of vitality." + user << "It requires at least [base_revive_cost] units of vitality to revive dead servants, in addition to any damage the servant has." + +/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L) + if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active) + return 0 + visible_message("[src] begins to glow bright blue!") + animate(src, alpha = 255, time = 10) + sleep(10) + sigil_active = TRUE +//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality + while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && vitality)) && get_turf(L) == get_turf(src)) + if(animation_number >= 4) + PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/vitality, get_turf(src)) + animation_number = 0 + animation_number++ + if(!is_servant_of_ratvar(L)) + var/vitality_drained = 0 + if(L.stat == DEAD) + vitality_drained = L.maxHealth + var/obj/effect/overlay/temp/ratvar/sigil/vitality/V = PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/vitality, get_turf(src)) + animate(V, alpha = 0, transform = matrix()*2, time = 8) + playsound(L, 'sound/magic/WandODeath.ogg', 50, 1) + L.visible_message("[L] collapses in on [L.p_them()]self as [src] flares bright blue!") + L << "\"[text2ratvar("Your life will not be wasted.")]\"" + for(var/obj/item/W in L) + if(!L.unEquip(W)) + qdel(W) + L.dust() + else + vitality_drained = L.adjustToxLoss(1.5) + if(vitality_drained) + vitality += vitality_drained + else + break + else + var/clone_to_heal = L.getCloneLoss() + var/tox_to_heal = L.getToxLoss() + var/burn_to_heal = L.getFireLoss() + var/brute_to_heal = L.getBruteLoss() + var/oxy_to_heal = L.getOxyLoss() + var/total_damage = clone_to_heal + tox_to_heal + burn_to_heal + brute_to_heal + oxy_to_heal + if(L.stat == DEAD) + var/revival_cost = base_revive_cost + total_damage - oxy_to_heal //ignores oxygen damage + if(ratvar_awakens) + revival_cost = 0 + var/mob/dead/observer/ghost = L.get_ghost(TRUE) + if(ghost) + if(vitality >= revival_cost) + ghost.reenter_corpse() + L.revive(1, 1) + playsound(L, 'sound/magic/Staff_Healing.ogg', 50, 1) + L.visible_message("[L] suddenly gets back up, [L.p_their()] mouth dripping blue ichor!", \ + "\"[text2ratvar("You will be okay, child.")]\"") + vitality -= revival_cost + break + else + break + if(!total_damage) + break + var/vitality_for_cycle = min(vitality, 3) + var/vitality_used = 0 + if(ratvar_awakens) + vitality_for_cycle = 3 + + if(clone_to_heal && vitality_for_cycle) + var/healing = min(vitality_for_cycle, clone_to_heal) + vitality_for_cycle -= healing + L.adjustCloneLoss(-healing) + vitality_used += healing + + if(tox_to_heal && vitality_for_cycle) + var/healing = min(vitality_for_cycle, tox_to_heal) + vitality_for_cycle -= healing + L.adjustToxLoss(-healing) + vitality_used += healing + + if(burn_to_heal && vitality_for_cycle) + var/healing = min(vitality_for_cycle, burn_to_heal) + vitality_for_cycle -= healing + L.adjustFireLoss(-healing) + vitality_used += healing + + if(brute_to_heal && vitality_for_cycle) + var/healing = min(vitality_for_cycle, brute_to_heal) + vitality_for_cycle -= healing + L.adjustBruteLoss(-healing) + vitality_used += healing + + if(oxy_to_heal && vitality_for_cycle) + var/healing = min(vitality_for_cycle, oxy_to_heal) + vitality_for_cycle -= healing + L.adjustOxyLoss(-healing) + vitality_used += healing + + if(!ratvar_awakens) + vitality -= vitality_used + sleep(2) + + animation_number = initial(animation_number) + sigil_active = FALSE + animate(src, alpha = initial(alpha), time = 20) + visible_message("[src] slowly stops glowing!") diff --git a/code/game/gamemodes/clock_cult/clock_effects/general_markers.dm b/code/game/gamemodes/clock_cult/clock_effects/general_markers.dm new file mode 100644 index 00000000000..d9a85bd0332 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_effects/general_markers.dm @@ -0,0 +1,57 @@ +//massive markers for Revenant and Judgement scripture. +/obj/effect/clockwork/general_marker + name = "general marker" + desc = "Some big guy. For you." + clockwork_desc = "One of Ratvar's generals." + alpha = 200 + layer = MASSIVE_OBJ_LAYER + +/obj/effect/clockwork/general_marker/New() + ..() + animate(src, alpha = 0, time = 10) + QDEL_IN(src, 10) + +/obj/effect/clockwork/general_marker/inathneq + name = "Inath-neq, the Resonant Cogwheel" + desc = "A humanoid form blazing with blue fire. It radiates an aura of kindness and caring." + clockwork_desc = "One of Ratvar's four generals. Before her current form, Inath-neq was a powerful warrior priestess commanding the Resonant Cogs, a sect of Ratvarian warriors renowned for \ + their prowess. After a lost battle with Nar-Sian cultists, Inath-neq was struck down and stated in her dying breath, \ + \"The Resonant Cogs shall not fall silent this day, but will come together to form a wheel that shall never stop turning.\" Ratvar, touched by this, granted Inath-neq an eternal body and \ + merged her soul with those of the Cogs slain with her on the battlefield." + icon = 'icons/effects/187x381.dmi' + icon_state = "inath-neq" + pixel_x = -77 + pixel_y = -174 + +/obj/effect/clockwork/general_marker/nezbere + name = "Nezbere, the Brass Eidolon" + desc = "A towering colossus clad in nigh-impenetrable brass armor. Its gaze is stern yet benevolent, even upon you." + clockwork_desc = "One of Ratvar's four generals. Nezbere is responsible for the design, testing, and creation of everything in Ratvar's domain, and his loyalty to Ratvar knows no bounds. \ + It is said that Ratvar once asked him to destroy the plans for a weapon Nezbere had made that could have harmed him and Nezbere responded by not only destroying the plans, \ + but by taking his own life so that the device could never be replicated. Nezbere's zealotry is unmatched." + icon = 'icons/effects/340x428.dmi' + icon_state = "nezbere" + pixel_x = -154 + pixel_y = -198 + +/obj/effect/clockwork/general_marker/sevtug + name = "Sevtug, the Formless Pariah" + desc = "A sinister cloud of purple energy. Looking at it gives you a headache." + clockwork_desc = "One of Ratvar's four generals. Sevtug taught him how to manipulate minds and is one of his oldest allies. Sevtug serves Ratvar loyally out of a hope that one day, he will \ + be able to use a moment of weakness in the Justicar to usurp him, but such a day will never come. And so, he serves with dedication, if not necessarily any sort of decorum, never aware he is \ + the one being made a fool of." + icon = 'icons/effects/211x247.dmi' + icon_state = "sevtug" + pixel_x = -89 + pixel_y = -107 + +/obj/effect/clockwork/general_marker/nzcrentr + name = "Nzcrentr, the Eternal Thunderbolt" + desc = "A terrifying spiked construct crackling with limitless energy." + clockwork_desc = "One of Ratvar's four generals. Before becoming one of Ratvar's generals, Nzcrentr sook out any and all sentient life to slaughter it for sport. \ + Nzcrentr was coerced by Ratvar into entering a shell constructed by Nezbere, ostensibly made to grant Nzcrentr more power. In reality, the shell was made to trap and control it. \ + Nzcrentr now serves loyally, though even one of Nezbere's finest creations was not enough to totally eliminate its will." + icon = 'icons/effects/254x361.dmi' + icon_state = "nzcrentr" + pixel_x = -111 + pixel_y = -164 diff --git a/code/game/gamemodes/clock_cult/clock_effects/spatial_gateway.dm b/code/game/gamemodes/clock_cult/clock_effects/spatial_gateway.dm new file mode 100644 index 00000000000..73afbeabd3b --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_effects/spatial_gateway.dm @@ -0,0 +1,186 @@ +//Spatial gateway: A usually one-way rift to another location. +/obj/effect/clockwork/spatial_gateway + name = "spatial gateway" + desc = "A gently thrumming tear in reality." + clockwork_desc = "A gateway in reality." + icon_state = "spatial_gateway" + density = 1 + var/sender = TRUE //If this gateway is made for sending, not receiving + var/both_ways = FALSE + var/lifetime = 25 //How many deciseconds this portal will last + var/uses = 1 //How many objects or mobs can go through the portal + var/obj/effect/clockwork/spatial_gateway/linked_gateway //The gateway linked to this one + +/obj/effect/clockwork/spatial_gateway/New() + ..() + addtimer(src, "check_setup", 1) + +/obj/effect/clockwork/spatial_gateway/proc/check_setup() + if(!linked_gateway) + qdel(src) + return + if(both_ways) + clockwork_desc = "A gateway in reality. It can both send and receive objects." + else + clockwork_desc = "A gateway in reality. It can only [sender ? "send" : "receive"] objects." + QDEL_IN(src, lifetime) + +//set up a gateway with another gateway +/obj/effect/clockwork/spatial_gateway/proc/setup_gateway(obj/effect/clockwork/spatial_gateway/gatewayB, set_duration, set_uses, two_way) + if(!gatewayB || !set_duration || !uses) + return FALSE + linked_gateway = gatewayB + gatewayB.linked_gateway = src + if(two_way) + both_ways = TRUE + gatewayB.both_ways = TRUE + else + sender = TRUE + gatewayB.sender = FALSE + gatewayB.density = FALSE + lifetime = set_duration + gatewayB.lifetime = set_duration + uses = set_uses + gatewayB.uses = set_uses + return TRUE + +/obj/effect/clockwork/spatial_gateway/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "It has [uses] uses remaining." + +/obj/effect/clockwork/spatial_gateway/attack_ghost(mob/user) + if(linked_gateway) + user.forceMove(get_turf(linked_gateway)) + ..() + +/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user) + if(!uses) + return FALSE + if(user.pulling && user.a_intent == "grab" && isliving(user.pulling)) + var/mob/living/L = user.pulling + if(L.buckled || L.anchored || L.has_buckled_mobs()) + return FALSE + user.visible_message("[user] shoves [L] into [src]!", "You shove [L] into [src]!") + user.stop_pulling() + pass_through_gateway(L) + return TRUE + if(!user.canUseTopic(src)) + return FALSE + user.visible_message("[user] climbs through [src]!", "You brace yourself and step through [src]...") + pass_through_gateway(user) + return TRUE + +/obj/effect/clockwork/spatial_gateway/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/weapon/nullrod)) + user.visible_message("[user] dispels [src] with [I]!", "You close [src] with [I]!") + qdel(linked_gateway) + qdel(src) + return TRUE + if(istype(I, /obj/item/clockwork/slab)) + user << "\"I don't think you want to drop your slab into that\".\n\"If you really want to, try throwing it.\"" + return TRUE + if(user.drop_item() && uses) + user.visible_message("[user] drops [I] into [src]!", "You drop [I] into [src]!") + pass_through_gateway(I) + return TRUE + return ..() + +/obj/effect/clockwork/spatial_gateway/ex_act(severity) + if(severity == 1 && uses) + uses = 0 + visible_message("[src] is disrupted!") + animate(src, alpha = 0, transform = matrix()*2, time = 10) + QDEL_IN(src, 10) + linked_gateway.uses = 0 + linked_gateway.visible_message("[linked_gateway] is disrupted!") + animate(linked_gateway, alpha = 0, transform = matrix()*2, time = 10) + QDEL_IN(linked_gateway, 10) + return TRUE + return FALSE + +/obj/effect/clockwork/spatial_gateway/Bumped(atom/A) + ..() + if(isliving(A) || istype(A, /obj/item)) + pass_through_gateway(A) + +/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A) + if(!linked_gateway) + qdel(src) + return FALSE + if(!sender) + visible_message("[A] bounces off of [src]!") + return FALSE + if(!uses) + return FALSE + if(isliving(A)) + var/mob/living/user = A + user << "You pass through [src] and appear elsewhere!" + linked_gateway.visible_message("A shape appears in [linked_gateway] before emerging!") + playsound(src, 'sound/effects/EMPulse.ogg', 50, 1) + playsound(linked_gateway, 'sound/effects/EMPulse.ogg', 50, 1) + transform = matrix() * 1.5 + animate(src, transform = matrix() / 1.5, time = 10) + linked_gateway.transform = matrix() * 1.5 + animate(linked_gateway, transform = matrix() / 1.5, time = 10) + A.forceMove(get_turf(linked_gateway)) + uses = max(0, uses - 1) + linked_gateway.uses = max(0, linked_gateway.uses - 1) + addtimer(src, "check_uses", 10) + return TRUE + +/obj/effect/clockwork/spatial_gateway/proc/check_uses() + if(!uses) + qdel(src) + qdel(linked_gateway) + +//This proc creates and sets up a gateway from invoker input. +/atom/movable/proc/procure_gateway(mob/living/invoker, time_duration, gateway_uses, two_way) + var/list/possible_targets = list() + var/list/teleportnames = list() + var/list/duplicatenamecount = list() + + for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects) + if(!O.Adjacent(invoker) && O != src && (O.z <= ZLEVEL_SPACEMAX)) //don't list obelisks that we're next to + var/area/A = get_area(O) + var/locname = initial(A.name) + var/resultkey = "[locname] [O.name]" + if(resultkey in teleportnames) //why the fuck did you put two obelisks in the same area + duplicatenamecount[resultkey]++ + resultkey = "[resultkey] ([duplicatenamecount[resultkey]])" + else + teleportnames.Add(resultkey) + duplicatenamecount[resultkey] = 1 + possible_targets[resultkey] = O + + for(var/mob/living/L in living_mob_list) + if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && L != invoker && (L.z <= ZLEVEL_SPACEMAX)) //People right next to the invoker can't be portaled to, for obvious reasons + var/resultkey = "[L.name] ([L.real_name])" + if(resultkey in teleportnames) + duplicatenamecount[resultkey]++ + resultkey = "[resultkey] ([duplicatenamecount[resultkey]])" + else + teleportnames.Add(resultkey) + duplicatenamecount[resultkey] = 1 + possible_targets[resultkey] = L + + if(!possible_targets.len) + invoker << "There are no other eligible targets for a Spatial Gateway!" + return FALSE + var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets + var/atom/movable/target = possible_targets[input_target_key] + if(!src || !target || !invoker || !invoker.canUseTopic(src, BE_CLOSE) || !is_servant_of_ratvar(invoker) || (istype(src, /obj/item) && invoker.get_active_held_item() != src)) + return FALSE //if any of the involved things no longer exist, the invoker is stunned, too far away to use the object, or does not serve ratvar, or if the object is an item and not in the mob's active hand, fail + var/istargetobelisk = istype(target, /obj/structure/destructible/clockwork/powered/clockwork_obelisk) + if(istargetobelisk) + gateway_uses *= 2 + time_duration *= 2 + invoker.visible_message("The air in front of [invoker] ripples before suddenly tearing open!", \ + "With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [time_duration / 10] seconds and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].") + var/obj/effect/clockwork/spatial_gateway/S1 = new(istype(src, /obj/structure/destructible/clockwork/powered/clockwork_obelisk) ? get_turf(src) : get_step(get_turf(invoker), invoker.dir)) + var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir)) + + //Set up the portals now that they've spawned + S1.setup_gateway(S2, time_duration, gateway_uses, two_way) + S2.visible_message("The air in front of [target] ripples before suddenly tearing open!") + return TRUE diff --git a/code/game/gamemodes/clock_cult/clock_powerdrain.dm b/code/game/gamemodes/clock_cult/clock_helpers/clock_powerdrain.dm similarity index 100% rename from code/game/gamemodes/clock_cult/clock_powerdrain.dm rename to code/game/gamemodes/clock_cult/clock_helpers/clock_powerdrain.dm diff --git a/code/game/gamemodes/clock_cult/clock_helpers/component_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/component_helpers.dm new file mode 100644 index 00000000000..b49d1795b5a --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_helpers/component_helpers.dm @@ -0,0 +1,118 @@ +//generates a component in the global component cache, either random based on lowest or a specific component +/proc/generate_cache_component(specific_component_id) + if(specific_component_id) + clockwork_component_cache[specific_component_id]++ + else + var/component_to_generate = get_weighted_component_id() + clockwork_component_cache[component_to_generate]++ + +//returns a chosen component id based on the lowest amount of that component in the global cache, the global cache plus the slab if there are caches, or the slab if there are no caches. +/proc/get_weighted_component_id(obj/item/clockwork/slab/storage_slab) + . = list() + if(storage_slab) + if(clockwork_caches) + for(var/i in clockwork_component_cache) + .[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache[i] + storage_slab.stored_components[i]), 1) + else + for(var/i in clockwork_component_cache) + .[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*storage_slab.stored_components[i], 1) + else + for(var/i in clockwork_component_cache) + .[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache[i], 1) + . = pickweight(.) + +//returns a component name from a component id +/proc/get_component_name(id) + switch(id) + if("belligerent_eye") + return "Belligerent Eye" + if("vanguard_cogwheel") + return "Vanguard Cogwheel" + if("guvax_capacitor") + return "Guvax Capacitor" + if("replicant_alloy") + return "Replicant Alloy" + if("hierophant_ansible") + return "Hierophant Ansible" + else + return null + +//returns a component id from a component name +/proc/get_component_id(name) + switch(name) + if("Belligerent Eye") + return "belligerent_eye" + if("Vanguard Cogwheel") + return "vanguard_cogwheel" + if("Guvax Capacitor") + return "guvax_capacitor" + if("Replicant Alloy") + return "replicant_alloy" + if("Hierophant Ansible") + return "hierophant_ansible" + else + return null + +//returns a component spanclass from a component id +/proc/get_component_span(id) + switch(id) + if("belligerent_eye") + return "neovgre" + if("vanguard_cogwheel") + return "inathneq" + if("guvax_capacitor") + return "sevtug" + if("replicant_alloy") + return "nezbere" + if("hierophant_ansible") + return "nzcrentr" + else + return null + +//returns a component color from a component id +/proc/get_component_color(id) + switch(id) + if("belligerent_eye") + return "#6E001A" + if("vanguard_cogwheel") + return "#1E8CE1" + if("guvax_capacitor") + return "#AF0AAF" + if("replicant_alloy") + return "#42474D" + if("hierophant_ansible") + return "#DAAA18" + else + return "#BE8700" + +//returns a type for a floating component animation from a component id +/proc/get_component_animation_type(id) + switch(id) + if("belligerent_eye") + return /obj/effect/overlay/temp/ratvar/component + if("vanguard_cogwheel") + return /obj/effect/overlay/temp/ratvar/component/cogwheel + if("guvax_capacitor") + return /obj/effect/overlay/temp/ratvar/component/capacitor + if("replicant_alloy") + return /obj/effect/overlay/temp/ratvar/component/alloy + if("hierophant_ansible") + return /obj/effect/overlay/temp/ratvar/component/ansible + else + return null + +//returns a type for a component from a component id +/proc/get_component_type(id) + switch(id) + if("belligerent_eye") + return /obj/item/clockwork/component/belligerent_eye + if("vanguard_cogwheel") + return /obj/item/clockwork/component/vanguard_cogwheel + if("guvax_capacitor") + return /obj/item/clockwork/component/guvax_capacitor + if("replicant_alloy") + return /obj/item/clockwork/component/replicant_alloy + if("hierophant_ansible") + return /obj/item/clockwork/component/hierophant_ansible + else + return null \ No newline at end of file diff --git a/code/game/gamemodes/clock_cult/clock_helpers/hierophant_network.dm b/code/game/gamemodes/clock_cult/clock_helpers/hierophant_network.dm new file mode 100644 index 00000000000..4e4697fadc5 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_helpers/hierophant_network.dm @@ -0,0 +1,47 @@ +//Sends a string to all servants and optionally ghosts, who will get a follow link to whatever is provided as the target. +/proc/hierophant_message(message, servantsonly, atom/target) + if(!message) + return FALSE + for(var/M in mob_list) + if(!servantsonly && isobserver(M)) + if(target) + var/link = FOLLOW_LINK(M, target) + M << "[link] [message]" + else + M << message + else if(is_servant_of_ratvar(M)) + M << message + return TRUE + +//Sends a titled message from a mob to all servants of ratvar and ghosts. +/proc/titled_hierophant_message(mob/user, message, name_span = "heavy_brass", message_span = "brass", user_title = "Servant") + if(!user || !message) + return FALSE + var/parsed_message = "[user_title ? "[user_title] ":""][findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: \ + \"[message]\"" + hierophant_message(parsed_message, FALSE, user) + return TRUE + +//Hierophant Network action, allows a servant with it to communicate to other servants. +/datum/action/innate/hierophant + name = "Hierophant Network" + desc = "Allows you to communicate with other Servants." + button_icon_state = "hierophant" + background_icon_state = "bg_clock" + check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS + buttontooltipstyle = "clockcult" + var/title = "Servant" + var/span_for_name = "heavy_brass" + var/span_for_message = "brass" + +/datum/action/innate/hierophant/IsAvailable() + if(!is_servant_of_ratvar(owner)) + return FALSE + return ..() + +/datum/action/innate/hierophant/Activate() + var/input = stripped_input(usr, "Please enter a message to send to other servants.", "Hierophant Network", "") + if(!input || !IsAvailable()) + return + + titled_hierophant_message(owner, input, span_for_name, span_for_message, title) diff --git a/code/game/gamemodes/clock_cult/clock_items/clock_proselytizer.dm b/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm similarity index 63% rename from code/game/gamemodes/clock_cult/clock_items/clock_proselytizer.dm rename to code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm index fee7c3d104f..fd263fc53bd 100644 --- a/code/game/gamemodes/clock_cult/clock_items/clock_proselytizer.dm +++ b/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm @@ -1,153 +1,4 @@ - -/obj/item/clockwork/clockwork_proselytizer //Clockwork proselytizer (yes, that's a real word): Converts applicable objects to Ratvarian variants. - name = "clockwork proselytizer" - desc = "An odd, L-shaped device that hums with energy." - clockwork_desc = "A device that allows the replacing of mundane objects with Ratvarian variants. It requires liquified Replicant Alloy to function." - icon_state = "clockwork_proselytizer" - w_class = 3 - force = 5 - flags = NOBLUDGEON - var/stored_alloy = 0 //Requires this to function; each chunk of replicant alloy provides REPLICANT_ALLOY_UNIT - var/max_alloy = REPLICANT_ALLOY_UNIT * 10 - var/uses_alloy = TRUE - var/metal_to_alloy = FALSE - var/repairing = null //what we're currently repairing, if anything - -/obj/item/clockwork/clockwork_proselytizer/preloaded - stored_alloy = REPLICANT_WALL_MINUS_FLOOR+REPLICANT_WALL_TOTAL - -/obj/item/clockwork/clockwork_proselytizer/scarab - name = "scarab proselytizer" - clockwork_desc = "A cogscarab's internal proselytizer. It can only be successfully used by a cogscarab and requires liquified Replicant Alloy to function." - metal_to_alloy = TRUE - item_state = "nothing" - w_class = 1 - var/debug = FALSE - -/obj/item/clockwork/clockwork_proselytizer/scarab/proselytize(atom/target, mob/living/user) - if(!debug && !isdrone(user)) - return 0 - return ..() - -/obj/item/clockwork/clockwork_proselytizer/scarab/debug - clockwork_desc = "A cogscarab's internal proselytizer. It can convert nearly any object into a Ratvarian variant." - uses_alloy = FALSE - debug = TRUE - -/obj/item/clockwork/clockwork_proselytizer/examine(mob/living/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "Can be used to convert walls, floors, windows, airlocks, windoors, and grilles to clockwork variants." - user << "Can also form some objects into Replicant Alloy, as well as reform Clockwork Walls into Clockwork Floors, and vice versa." - if(metal_to_alloy) - user << "It can convert rods, metal, and plasteel to liquified replicant alloy at a low rate." - if(uses_alloy) - user << "It has [stored_alloy]/[max_alloy] units of liquified alloy stored." - user << "Use it on a Tinkerer's Cache, strike it with Replicant Alloy, or attack Replicant Alloy with it to add additional liquified alloy." - user << "Use it in-hand to remove stored liquified alloy." - -/obj/item/clockwork/clockwork_proselytizer/attack_self(mob/living/user) - if(is_servant_of_ratvar(user) && uses_alloy) - if(!can_use_alloy(REPLICANT_ALLOY_UNIT)) - user << "[src] [stored_alloy ? "Lacks enough":"Contains no"] alloy to reform[stored_alloy ? "":" any"] into solidified alloy!" - return - modify_stored_alloy(-REPLICANT_ALLOY_UNIT) - playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) - new/obj/item/clockwork/component/replicant_alloy(user.loc) - user << "You force [stored_alloy ? "some":"all"] of the alloy in [src]'s compartments to reform and solidify. \ - It now contains [stored_alloy]/[max_alloy] units of liquified alloy." - -/obj/item/clockwork/clockwork_proselytizer/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user) && uses_alloy) - if(!can_use_alloy(-REPLICANT_ALLOY_UNIT)) - user << "[src]'s replicant alloy compartments are full!" - return 0 - modify_stored_alloy(REPLICANT_ALLOY_UNIT) - playsound(user, 'sound/machines/click.ogg', 50, 1) - clockwork_say(user, text2ratvar("Transmute into fuel."), TRUE) - user << "You force [I] to liquify and pour it into [src]'s compartments. It now contains [stored_alloy]/[max_alloy] units of liquified alloy." - user.drop_item() - qdel(I) - return 1 - else - return ..() - -/obj/item/clockwork/clockwork_proselytizer/afterattack(atom/target, mob/living/user, proximity_flag, params) - if(!target || !user || !proximity_flag) - return 0 - if(!is_servant_of_ratvar(user)) - return ..() - proselytize(target, user) - -/obj/item/clockwork/clockwork_proselytizer/proc/modify_stored_alloy(amount) - if(can_use_alloy(RATVAR_ALLOY_CHECK)) //Ratvar makes it free - amount = 0 - stored_alloy = Clamp(stored_alloy + amount, 0, max_alloy) - return 1 - -/obj/item/clockwork/clockwork_proselytizer/proc/can_use_alloy(amount) - if(amount == RATVAR_ALLOY_CHECK) - if(ratvar_awakens || !uses_alloy) - return TRUE - else - return FALSE - if(stored_alloy - amount < 0) - return FALSE - if(stored_alloy - amount > max_alloy) - return FALSE - return TRUE - -/obj/item/clockwork/clockwork_proselytizer/proc/proselytize(atom/target, mob/living/user) - if(!target || !user) - return 0 - var/target_type = target.type - var/list/proselytize_values = target.proselytize_vals(user, src) //relevant values for proselytizing stuff, given as an associated list - if(!islist(proselytize_values)) - if(proselytize_values != TRUE) //if we get true, fail, but don't send a message for whatever reason - user << "[target] cannot be proselytized!" - return 0 - if(repairing) - user << "You are currently repairing [repairing] with [src]!" - return 0 - if(!uses_alloy) - proselytize_values["alloy_cost"] = 0 - - if(!can_use_alloy(proselytize_values["alloy_cost"])) - if(stored_alloy - proselytize_values["alloy_cost"] < 0) - user << "You need [proselytize_values["alloy_cost"]] liquified alloy to proselytize [target]!" - else if(stored_alloy - proselytize_values["alloy_cost"] > max_alloy) - user << "You have too much liquified alloy stored to proselytize [target]!" - return 0 - - if(can_use_alloy(RATVAR_ALLOY_CHECK)) //Ratvar makes it faster - proselytize_values["operation_time"] *= 0.5 - - user.visible_message("[user]'s [name] begins tearing apart [target]!", "You begin proselytizing [target]...") - playsound(target, 'sound/machines/click.ogg', 50, 1) - if(proselytize_values["operation_time"] && !do_after(user, proselytize_values["operation_time"], target = target)) - return 0 - if(!can_use_alloy(proselytize_values["alloy_cost"])) //Check again to prevent bypassing via spamclick - return 0 - if(!target || target.type != target_type) - return 0 - if(repairing) - return 0 - user.visible_message("[user]'s [name] disgorges a chunk of metal and shapes it over what's left of [target]!", \ - "You proselytize [target].") - playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - var/new_thing_type = proselytize_values["new_obj_type"] - if(isturf(target)) - var/turf/T = target - T.ChangeTurf(new_thing_type) - else - if(proselytize_values["dir_in_new"]) - new new_thing_type(get_turf(target), proselytize_values["spawn_dir"]) - else - var/atom/A = new new_thing_type(get_turf(target)) - A.setDir(proselytize_values["spawn_dir"]) - qdel(target) - modify_stored_alloy(-proselytize_values["alloy_cost"]) - return 1 +//For the clockwork proselytizer, this proc exists to make it easy to customize what the proselytizer does when hitting something. //if a valid target, returns an associated list in this format; //list("operation_time" = 15, "new_obj_type" = /obj/structure/window/reinforced/clockwork, "alloy_cost" = 5, "spawn_dir" = dir, "dir_in_new" = TRUE) @@ -157,6 +8,7 @@ /atom/proc/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return FALSE +//Turf conversion /turf/closed/wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_TOTAL, "spawn_dir" = SOUTH) @@ -185,6 +37,7 @@ return FALSE return list("operation_time" = 100, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH) +//Metal conversion /obj/item/stack/rods/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) if(get_amount() >= 10) var/sheets_to_make = round(get_amount() * 0.1) @@ -218,6 +71,7 @@ user << "You need at least 10 sheets of plasteel to convert into brass." return TRUE +//Brass directly to alloy; scarab only /obj/item/stack/sheet/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) if(!proselytizer.metal_to_alloy) return FALSE @@ -225,6 +79,7 @@ var/prosel_time = -amount*1 return list("operation_time" = -prosel_time, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_cost, "spawn_dir" = SOUTH) +//Airlock conversion /obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) var/doortype = /obj/machinery/door/airlock/clockwork if(glass) @@ -234,6 +89,7 @@ /obj/machinery/door/airlock/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return FALSE +//Window conversion /obj/structure/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) var/windowtype = /obj/structure/window/reinforced/clockwork var/new_dir = TRUE @@ -249,12 +105,14 @@ /obj/structure/window/reinforced/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return FALSE +//Windoor conversion /obj/machinery/door/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return list("operation_time" = 30, "new_obj_type" = /obj/machinery/door/window/clockwork, "alloy_cost" = REPLICANT_STANDARD, "spawn_dir" = dir, "dir_in_new" = TRUE) /obj/machinery/door/window/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return FALSE +//Grille conversion /obj/structure/grille/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) var/grilletype = /obj/structure/grille/ratvar var/prosel_time = 15 @@ -266,6 +124,7 @@ /obj/structure/grille/ratvar/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return FALSE +//Hitting a clockwork structure will try to repair it. /obj/structure/destructible/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) . = TRUE if(proselytizer.repairing) //no spamclicking for fast repairs, bucko @@ -319,6 +178,7 @@ "You finish repairing [src]. It is now at [obj_integrity]/[max_integrity] integrity.") return +//Hitting a tinkerer's cache will try to fill the proselytizer with alloy after trying to repair. /obj/structure/destructible/clockwork/cache/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) . = ..() if(proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK) || proselytizer.stored_alloy + REPLICANT_ALLOY_UNIT > proselytizer.max_alloy) @@ -341,6 +201,7 @@ "You finish filling [proselytizer] with liquified alloy. It now contains [proselytizer.stored_alloy]/[proselytizer.max_alloy] units of liquified alloy.") return +//Convert shards, wall gears, and replicant alloy directly to liquid alloy /obj/structure/destructible/clockwork/wall_gear/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return list("operation_time" = 10, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_GEAR, "spawn_dir" = SOUTH) diff --git a/code/game/gamemodes/clock_cult/clock_helpers/ratvarian_language.dm b/code/game/gamemodes/clock_cult/clock_helpers/ratvarian_language.dm new file mode 100644 index 00000000000..8bdd607b79b --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_helpers/ratvarian_language.dm @@ -0,0 +1,107 @@ +/* +The Ratvarian Language + In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar-Sie's language, but is in fact derived from +aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar-Sian cult). + + While the canon states that the language of Ratvar and his servants is incomprehensible to the unenlightened as it is a derivative of the most ancient known language, in reality it is +actually very simple. To translate a plain English sentence to Ratvar's tongue, simply move all of the letters thirteen places ahead, starting from "a" if the end of the alphabet is reached. +This cipher is known as "rot13" for "rotate 13 places" and there are many sites online that allow instant translation between English and rot13 - one of the benefits is that moving the translated +sentence thirteen places ahead changes it right back to plain English. + + There are, however, a few parts of the Ratvarian tongue that aren't typical and are implemented for fluff reasons. Some words may have graves, or hyphens (prefix and postfix), making the plain +English translation apparent but disjoined (for instance, "Orubyq zl-cbjre!" translates directly to "Behold my-power!") although this can be ignored without impacting overall quality. When +translating from Ratvar's tongue to plain English, simply remove the disjointments and use the finished sentence. This would make "Orubyq zl-cbjre!" into "Behold my power!" after removing the +abnormal spacing, hyphens, and grave accents. + +List of nuances: +- Any time the WORD "of" occurs, it is linked to the previous word by a hyphen. (i.e. "V nz-bs Ratvar." directly translates to "I am-of Ratvar.") +- Any time "th", followed by any two letters occurs, you add a grave (`) between those two letters, i.e; "Thi`s" +- In the same vein, any time "ti", followed by one letter occurs, you add a grave (`) between "i" and the letter, i.e; "Ti`me" +- Whereever "te" or "et" appear and there is another letter next to the e(i.e; "m"etal, greate"r"), add a hyphen between "e" and the letter, i.e; "M-etal", "Greate-r" +- Where "gua" appears, add a hyphen between "gu" and "a", i.e "Gu-ard" +- Where the WORD "and" appears it is linked to all surrounding words by hyphens, i.e; "Sword-and-shield" +- Where the WORD "to" appears, it is linked to the following word by a hyphen, i.e; "to-use" +- Where the WORD "my" appears, it is linked to the following word by a hyphen, i.e; "my-light" +- Although "Ratvar" translates to "Engine" in English, the word "Ratvar" is used regardless of language as it is a proper noun. + - The same rule applies to Ratvar's four generals: Nezbere (Armorer), Sevtug (Fright), Nzcrentr (Amperage), and Inath-neq (Vangu-Ard), although these words can be used in proper context if one is + not referring to the four generals and simply using the words themselves. +*/ + +//Regexes used to alter english to ratvarian style +#define RATVAR_OF_MATCH regex("(\\w)\\s(\[oO]\[fF])","g") +#define RATVAR_OF_REPLACEMENT "$1-$2" +#define RATVAR_GUA_MATCH regex("(\[gG]\[uU])(\[aA])","g") +#define RATVAR_GUA_REPLACEMENT "$1-$2" +#define RATVAR_TH_MATCH regex("(\[tT]\[hH]\\w)(\\w)","g") +#define RATVAR_TH_REPLACEMENT "$1`$2" +#define RATVAR_TI_MATCH regex("(\[tT]\[iI])(\\w)","g") +#define RATVAR_TI_REPLACEMENT "$1`$2" +#define RATVAR_ET_MATCH regex("(\\w)(\[eE]\[tT])","g") +#define RATVAR_ET_REPLACEMENT "$1-$2" +#define RATVAR_TE_MATCH regex("(\[tT]\[eE])(\\w)","g") +#define RATVAR_TE_REPLACEMENT "$1-$2" +#define RATVAR_PRE_AND_MATCH regex("(\\w)\\s(\[aA]\[nN]\[dD])","g") +#define RATVAR_PRE_AND_REPLACEMENT "$1-$2" +#define RATVAR_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])\\s(\\w)","g") +#define RATVAR_POST_AND_REPLACEMENT "$1-$2" +#define RATVAR_TO_MATCH regex("(\\s)(\[tT]\[oO])\\s(\\w)","g") +#define RATVAR_TO_REPLACEMENT "$1$2-$3" +#define RATVAR_MY_MATCH regex("(\\s)(\[mM]\[yY])\\s(\\w)","g") +#define RATVAR_MY_REPLACEMENT "$1$2-$3" + +//Regexes used to remove ratvarian styling from english +#define REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH regex("(\\w)-(\[aA]\[nN]\[dD])","g") //specifically structured to support -emphasis-, including with -and- +#define REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT "$1 $2" +#define REVERSE_RATVAR_HYPHEN_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])-(\\w)","g") +#define REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT "$1 $2" +#define REVERSE_RATVAR_HYPHEN_TO_MY_MATCH regex("(\[tTmM]\[oOyY])-","g") +#define REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT "$1 " +#define REVERSE_RATVAR_HYPHEN_TE_MATCH regex("(\[tT]\[eE])-","g") +#define REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT "$1" +#define REVERSE_RATVAR_HYPHEN_ET_MATCH regex("-(\[eE]\[tT])","g") +#define REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT "$1" +#define REVERSE_RATVAR_HYPHEN_GUA_MATCH regex("(\[gG]\[uU])-(\[aA])","g") +#define REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT "$1$2" +#define REVERSE_RATVAR_HYPHEN_OF_MATCH regex("-(\[oO]\[fF])","g") +#define REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT " $1" + + +/proc/text2ratvar(text) //Takes english and applies ratvarian styling rules (and rot13) to it + var/ratvarian = replacetext(text, RATVAR_OF_MATCH, RATVAR_OF_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_GUA_MATCH, RATVAR_GUA_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_TH_MATCH, RATVAR_TH_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_TI_MATCH, RATVAR_TI_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_ET_MATCH, RATVAR_ET_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_TE_MATCH, RATVAR_TE_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_PRE_AND_MATCH, RATVAR_PRE_AND_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_POST_AND_MATCH, RATVAR_POST_AND_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_TO_MATCH, RATVAR_TO_REPLACEMENT) + ratvarian = replacetext(ratvarian, RATVAR_MY_MATCH, RATVAR_MY_REPLACEMENT) + return rot13(ratvarian) + +/proc/ratvar2text(ratvarian) //Reverts ravarian styling and rot13 in text. + var/text = replacetext(rot13(ratvarian), "`", "") + text = replacetext(text, REVERSE_RATVAR_HYPHEN_GUA_MATCH, REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT) + text = replacetext(text, REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH, REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT) + text = replacetext(text, REVERSE_RATVAR_HYPHEN_POST_AND_MATCH, REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT) + text = replacetext(text, REVERSE_RATVAR_HYPHEN_TO_MY_MATCH, REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT) + text = replacetext(text, REVERSE_RATVAR_HYPHEN_TE_MATCH, REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT) + text = replacetext(text, REVERSE_RATVAR_HYPHEN_ET_MATCH, REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT) + text = replacetext(text, REVERSE_RATVAR_HYPHEN_OF_MATCH, REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT) + return text + +//Causes the mob or AM in question to speak a message; it assumes that the message is already translated to ratvar speech using text2ratvar() +/proc/clockwork_say(atom/movable/AM, message, whisper=FALSE) + var/list/spans = list(SPAN_ROBOT) + + var/old_languages_spoken = AM.languages_spoken + AM.languages_spoken = HUMAN //anyone who can understand HUMAN will hear weird shitty ratvar speak, otherwise it'll get starred out + if(isliving(AM)) + var/mob/living/L = AM + if(!whisper) + L.say(message, "clock", spans) + else + L.whisper(message) + else + AM.say(message) + AM.languages_spoken = old_languages_spoken diff --git a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm new file mode 100644 index 00000000000..a11a7ac45f8 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm @@ -0,0 +1,37 @@ +//returns a list of scriptures and if they're unlocked or not +/proc/scripture_unlock_check() + var/servants = 0 + var/unconverted_ai_exists = FALSE + for(var/mob/living/M in living_mob_list) + if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M))) + servants++ + else if(isAI(M)) + unconverted_ai_exists = TRUE + . = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_REVENANT = FALSE, SCRIPTURE_JUDGEMENT = FALSE) + //Drivers: always unlocked + .[SCRIPTURE_SCRIPT] = (servants >= 5 && clockwork_caches >= 1) + //Script: 5 or more non-brain servants and 1+ clockwork caches + .[SCRIPTURE_APPLICATION] = (servants >= 8 && clockwork_caches >= 3 && clockwork_construction_value >= 100) + //Application: 8 or more non-brain servants, 3+ clockwork caches, and at least 100 CV + .[SCRIPTURE_REVENANT] = (servants >= 10 && clockwork_caches >= 4 && clockwork_construction_value >= 200) + //Revenant: 10 or more non-brain servants, 4+ clockwork caches, and at least 200 CV + .[SCRIPTURE_JUDGEMENT] = (servants >= 12 && clockwork_caches >= 5 && clockwork_construction_value >= 300 && !unconverted_ai_exists) + //Judgement: 12 or more non-brain servants, 5+ clockwork caches, at least 300 CV, and there are no living, non-servant ais + +//reports to servants when scripture is locked or unlocked +/proc/scripture_unlock_alert(list/previous_states) + . = scripture_unlock_check() + for(var/i in .) + if(.[i] != previous_states[i]) + hierophant_message("Hierophant Network: [i] Scripture has been [.[i] ? "un":""]locked.") + +//changes construction value +/proc/change_construction_value(amount) + clockwork_construction_value += amount + +//throws the no cache alert if there are no caches and clears it otherwise +/proc/cache_check(mob/M) + if(!clockwork_caches) + M.throw_alert("nocache", /obj/screen/alert/clockwork/nocache) + else + M.clear_alert("nocache") diff --git a/code/game/gamemodes/clock_cult/clock_items/clock_armor.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_armor.dm similarity index 100% rename from code/game/gamemodes/clock_cult/clock_items/clock_armor.dm rename to code/game/gamemodes/clock_cult/clock_items/clockwork_armor.dm diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm new file mode 100644 index 00000000000..554966eec32 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm @@ -0,0 +1,150 @@ + +/obj/item/clockwork/clockwork_proselytizer //Clockwork proselytizer (yes, that's a real word): Converts applicable objects to Ratvarian variants. + name = "clockwork proselytizer" + desc = "An odd, L-shaped device that hums with energy." + clockwork_desc = "A device that allows the replacing of mundane objects with Ratvarian variants. It requires liquified Replicant Alloy to function." + icon_state = "clockwork_proselytizer" + w_class = 3 + force = 5 + flags = NOBLUDGEON + var/stored_alloy = 0 //Requires this to function; each chunk of replicant alloy provides REPLICANT_ALLOY_UNIT + var/max_alloy = REPLICANT_ALLOY_UNIT * 10 + var/uses_alloy = TRUE + var/metal_to_alloy = FALSE + var/repairing = null //what we're currently repairing, if anything + +/obj/item/clockwork/clockwork_proselytizer/preloaded + stored_alloy = REPLICANT_WALL_MINUS_FLOOR+REPLICANT_WALL_TOTAL + +/obj/item/clockwork/clockwork_proselytizer/scarab + name = "scarab proselytizer" + clockwork_desc = "A cogscarab's internal proselytizer. It can only be successfully used by a cogscarab and requires liquified Replicant Alloy to function." + metal_to_alloy = TRUE + item_state = "nothing" + w_class = 1 + var/debug = FALSE + +/obj/item/clockwork/clockwork_proselytizer/scarab/proselytize(atom/target, mob/living/user) + if(!debug && !isdrone(user)) + return 0 + return ..() + +/obj/item/clockwork/clockwork_proselytizer/scarab/debug + clockwork_desc = "A cogscarab's internal proselytizer. It can convert nearly any object into a Ratvarian variant." + uses_alloy = FALSE + debug = TRUE + +/obj/item/clockwork/clockwork_proselytizer/examine(mob/living/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "Can be used to convert walls, floors, windows, airlocks, windoors, and grilles to clockwork variants." + user << "Can also form some objects into Replicant Alloy, as well as reform Clockwork Walls into Clockwork Floors, and vice versa." + if(metal_to_alloy) + user << "It can convert rods, metal, and plasteel to liquified replicant alloy at a low rate." + if(uses_alloy) + user << "It has [stored_alloy]/[max_alloy] units of liquified alloy stored." + user << "Use it on a Tinkerer's Cache, strike it with Replicant Alloy, or attack Replicant Alloy with it to add additional liquified alloy." + user << "Use it in-hand to remove stored liquified alloy." + +/obj/item/clockwork/clockwork_proselytizer/attack_self(mob/living/user) + if(is_servant_of_ratvar(user) && uses_alloy) + if(!can_use_alloy(REPLICANT_ALLOY_UNIT)) + user << "[src] [stored_alloy ? "Lacks enough":"Contains no"] alloy to reform[stored_alloy ? "":" any"] into solidified alloy!" + return + modify_stored_alloy(-REPLICANT_ALLOY_UNIT) + playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) + new/obj/item/clockwork/component/replicant_alloy(user.loc) + user << "You force [stored_alloy ? "some":"all"] of the alloy in [src]'s compartments to reform and solidify. \ + It now contains [stored_alloy]/[max_alloy] units of liquified alloy." + +/obj/item/clockwork/clockwork_proselytizer/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user) && uses_alloy) + if(!can_use_alloy(-REPLICANT_ALLOY_UNIT)) + user << "[src]'s replicant alloy compartments are full!" + return 0 + modify_stored_alloy(REPLICANT_ALLOY_UNIT) + playsound(user, 'sound/machines/click.ogg', 50, 1) + clockwork_say(user, text2ratvar("Transmute into fuel."), TRUE) + user << "You force [I] to liquify and pour it into [src]'s compartments. It now contains [stored_alloy]/[max_alloy] units of liquified alloy." + user.drop_item() + qdel(I) + return 1 + else + return ..() + +/obj/item/clockwork/clockwork_proselytizer/afterattack(atom/target, mob/living/user, proximity_flag, params) + if(!target || !user || !proximity_flag) + return 0 + if(!is_servant_of_ratvar(user)) + return ..() + proselytize(target, user) + +/obj/item/clockwork/clockwork_proselytizer/proc/modify_stored_alloy(amount) + if(can_use_alloy(RATVAR_ALLOY_CHECK)) //Ratvar makes it free + amount = 0 + stored_alloy = Clamp(stored_alloy + amount, 0, max_alloy) + return 1 + +/obj/item/clockwork/clockwork_proselytizer/proc/can_use_alloy(amount) + if(amount == RATVAR_ALLOY_CHECK) + if(ratvar_awakens || !uses_alloy) + return TRUE + else + return FALSE + if(stored_alloy - amount < 0) + return FALSE + if(stored_alloy - amount > max_alloy) + return FALSE + return TRUE + +/obj/item/clockwork/clockwork_proselytizer/proc/proselytize(atom/target, mob/living/user) + if(!target || !user) + return 0 + var/target_type = target.type + var/list/proselytize_values = target.proselytize_vals(user, src) //relevant values for proselytizing stuff, given as an associated list + if(!islist(proselytize_values)) + if(proselytize_values != TRUE) //if we get true, fail, but don't send a message for whatever reason + user << "[target] cannot be proselytized!" + return 0 + if(repairing) + user << "You are currently repairing [repairing] with [src]!" + return 0 + if(!uses_alloy) + proselytize_values["alloy_cost"] = 0 + + if(!can_use_alloy(proselytize_values["alloy_cost"])) + if(stored_alloy - proselytize_values["alloy_cost"] < 0) + user << "You need [proselytize_values["alloy_cost"]] liquified alloy to proselytize [target]!" + else if(stored_alloy - proselytize_values["alloy_cost"] > max_alloy) + user << "You have too much liquified alloy stored to proselytize [target]!" + return 0 + + if(can_use_alloy(RATVAR_ALLOY_CHECK)) //Ratvar makes it faster + proselytize_values["operation_time"] *= 0.5 + + user.visible_message("[user]'s [name] begins tearing apart [target]!", "You begin proselytizing [target]...") + playsound(target, 'sound/machines/click.ogg', 50, 1) + if(proselytize_values["operation_time"] && !do_after(user, proselytize_values["operation_time"], target = target)) + return 0 + if(!can_use_alloy(proselytize_values["alloy_cost"])) //Check again to prevent bypassing via spamclick + return 0 + if(!target || target.type != target_type) + return 0 + if(repairing) + return 0 + user.visible_message("[user]'s [name] disgorges a chunk of metal and shapes it over what's left of [target]!", \ + "You proselytize [target].") + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + var/new_thing_type = proselytize_values["new_obj_type"] + if(isturf(target)) + var/turf/T = target + T.ChangeTurf(new_thing_type) + else + if(proselytize_values["dir_in_new"]) + new new_thing_type(get_turf(target), proselytize_values["spawn_dir"]) + else + var/atom/A = new new_thing_type(get_turf(target)) + A.setDir(proselytize_values["spawn_dir"]) + qdel(target) + modify_stored_alloy(-proselytize_values["alloy_cost"]) + return 1 diff --git a/code/game/gamemodes/clock_cult/clock_items/clock_slab.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm similarity index 100% rename from code/game/gamemodes/clock_cult/clock_items/clock_slab.dm rename to code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm diff --git a/code/game/gamemodes/clock_cult/clock_machines.dm b/code/game/gamemodes/clock_cult/clock_machines.dm deleted file mode 100644 index f97908a5397..00000000000 --- a/code/game/gamemodes/clock_cult/clock_machines.dm +++ /dev/null @@ -1,676 +0,0 @@ -//////////////////////// -// CLOCKWORK MACHINES // -//////////////////////// -//not-actually-machines - -/obj/structure/destructible/clockwork/powered - var/obj/machinery/power/apc/target_apc - var/active = FALSE - var/needs_power = TRUE - var/active_icon = null //icon_state while process() is being called - var/inactive_icon = null //icon_state while process() isn't being called - -/obj/structure/destructible/clockwork/powered/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - var/powered = total_accessable_power() - user << "It has access to [powered == INFINITY ? "INFINITY":"[powered]"]W of power." - -/obj/structure/destructible/clockwork/powered/Destroy() - SSfastprocess.processing -= src - SSobj.processing -= src - return ..() - -/obj/structure/destructible/clockwork/powered/process() - var/powered = total_accessable_power() - return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define - -/obj/structure/destructible/clockwork/powered/proc/toggle(fast_process, mob/living/user) - if(user) - if(!is_servant_of_ratvar(user)) - return 0 - user.visible_message("[user] [active ? "dis" : "en"]ables [src].", "You [active ? "dis" : "en"]able [src].") - active = !active - if(active) - icon_state = active_icon - if(fast_process) - START_PROCESSING(SSfastprocess, src) - else - START_PROCESSING(SSobj, src) - else - icon_state = inactive_icon - if(fast_process) - STOP_PROCESSING(SSfastprocess, src) - else - STOP_PROCESSING(SSobj, src) - - -/obj/structure/destructible/clockwork/powered/proc/total_accessable_power() //how much power we have and can use - if(!needs_power || ratvar_awakens) - return INFINITY //oh yeah we've got power why'd you ask - - var/power = 0 - power += accessable_apc_power() - power += accessable_sigil_power() - return power - -/obj/structure/destructible/clockwork/powered/proc/accessable_apc_power() - var/power = 0 - var/area/A = get_area(src) - var/area/targetAPCA - for(var/obj/machinery/power/apc/APC in apcs_list) - var/area/APCA = get_area(APC) - if(APCA == A) - target_apc = APC - if(target_apc) - targetAPCA = get_area(target_apc) - if(targetAPCA != A) - target_apc = null - else if(target_apc.cell) - var/apccharge = target_apc.cell.charge - if(apccharge >= MIN_CLOCKCULT_POWER) - power += apccharge - return power - -/obj/structure/destructible/clockwork/powered/proc/accessable_sigil_power() - var/power = 0 - for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src)) - power += T.power_charge - return power - - -/obj/structure/destructible/clockwork/powered/proc/try_use_power(amount) //try to use an amount of power - if(!needs_power || ratvar_awakens) - return 1 - if(amount <= 0) - return 0 - var/power = total_accessable_power() - if(!power || power < amount) - return 0 - return use_power(amount) - -/obj/structure/destructible/clockwork/powered/proc/use_power(amount) //we've made sure we had power, so now we use it - var/sigilpower = accessable_sigil_power() - var/list/sigils_in_range = list() - for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src)) - sigils_in_range |= T - while(sigilpower && amount >= MIN_CLOCKCULT_POWER) - for(var/S in sigils_in_range) - var/obj/effect/clockwork/sigil/transmission/T = S - if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(MIN_CLOCKCULT_POWER)) - sigilpower -= MIN_CLOCKCULT_POWER - amount -= MIN_CLOCKCULT_POWER - var/apcpower = accessable_apc_power() - while(apcpower >= MIN_CLOCKCULT_POWER && amount >= MIN_CLOCKCULT_POWER) - if(target_apc.cell.use(MIN_CLOCKCULT_POWER)) - apcpower -= MIN_CLOCKCULT_POWER - amount -= MIN_CLOCKCULT_POWER - target_apc.update() - target_apc.update_icon() - else - apcpower = 0 - if(amount) - return 0 - else - return 1 - -/obj/structure/destructible/clockwork/powered/proc/return_power(amount) //returns a given amount of power to all nearby sigils - if(amount <= 0) - return 0 - var/list/sigils_in_range = list() - for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src)) - sigils_in_range |= T - if(!sigils_in_range.len) - return 0 - while(amount >= MIN_CLOCKCULT_POWER) - for(var/S in sigils_in_range) - var/obj/effect/clockwork/sigil/transmission/T = S - if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(-MIN_CLOCKCULT_POWER)) - amount -= MIN_CLOCKCULT_POWER - return 1 - - -/obj/structure/destructible/clockwork/powered/interdiction_lens //Interdiction lens: A powerful artifact that constantly disrupts electronics but, if it fails to find something to disrupt, turns off. - name = "interdiction lens" - desc = "An ominous, double-pronged brass totem. There's a strange gemstone clasped between the pincers." - clockwork_desc = "A powerful totem that constantly drains nearby electronics and funnels the power drained into nearby Sigils of Transmission." - icon_state = "interdiction_lens" - construction_value = 25 - active_icon = "interdiction_lens_active" - inactive_icon = "interdiction_lens" - break_message = "The lens flares a blinding violet before shattering!" - break_sound = 'sound/effects/Glassbr3.ogg' - var/recharging = 0 //world.time when the lens was last used - var/recharge_time = 1200 //if it drains no power and affects no objects, it turns off for two minutes - var/disabled = FALSE //if it's actually usable - var/interdiction_range = 14 //how large an area it drains and disables in - -/obj/structure/destructible/clockwork/powered/interdiction_lens/examine(mob/user) - ..() - user << "Its gemstone [recharging > world.time ? "has been breached by writhing tendrils of blackness that cover the totem" \ - : "vibrates in place and thrums with power"]." - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "If it fails to drain any electronics, it will disable itself for [round(recharge_time/600, 1)] minutes." - -/obj/structure/destructible/clockwork/powered/interdiction_lens/toggle(fast_process, mob/living/user) - ..() - if(active) - SetLuminosity(4,2) - else - SetLuminosity(0) - -/obj/structure/destructible/clockwork/powered/interdiction_lens/attack_hand(mob/living/user) - if(user.canUseTopic(src, BE_CLOSE)) - if(disabled) - user << "As you place your hand on the gemstone, cold tendrils of black matter crawl up your arm. You quickly pull back." - return 0 - toggle(0, user) - -/obj/structure/destructible/clockwork/powered/interdiction_lens/process() - if(recharging > world.time) - return - if(disabled) - visible_message("The writhing tendrils return to the gemstone, which begins to glow with power!") - flick("interdiction_lens_recharged", src) - disabled = FALSE - toggle(0) - else - var/successfulprocess = FALSE - var/power_drained = 0 - var/list/atoms_to_test = list() - for(var/A in spiral_range_turfs(interdiction_range, src)) - var/turf/T = A - for(var/M in T) - atoms_to_test |= M - - CHECK_TICK - - for(var/M in atoms_to_test) - var/atom/movable/A = M - if(!A || qdeleted(A)) - continue - power_drained += A.power_drain(TRUE) - - if(istype(A, /obj/machinery/camera)) - var/obj/machinery/camera/C = A - if(C.isEmpProof() || !C.status) - continue - successfulprocess = TRUE - if(C.emped) - continue - C.emp_act(1) - else if(istype(A, /obj/item/device/radio)) - var/obj/item/device/radio/O = A - successfulprocess = TRUE - if(O.emped || !O.on) - continue - O.emp_act(1) - else if((isliving(A) && !is_servant_of_ratvar(A)) || istype(A, /obj/structure/closet) || istype(A, /obj/item/weapon/storage)) //other things may have radios in them but we don't care - for(var/obj/item/device/radio/O in A.GetAllContents()) - successfulprocess = TRUE - if(O.emped || !O.on) - continue - O.emp_act(1) - - CHECK_TICK - - if(power_drained && power_drained >= MIN_CLOCKCULT_POWER && return_power(power_drained)) - successfulprocess = TRUE - playsound(src, 'sound/items/PSHOOM.ogg', 50, 1, interdiction_range-7, 1) - - if(!successfulprocess) - visible_message("The gemstone suddenly turns horribly dark, writhing tendrils covering it!") - recharging = world.time + recharge_time - flick("interdiction_lens_discharged", src) - icon_state = "interdiction_lens_inactive" - SetLuminosity(2,1) - disabled = TRUE - - - -/obj/structure/destructible/clockwork/powered/mending_motor //Mending motor: A prism that consumes replicant alloy to repair nearby mechanical servants at a quick rate. - name = "mending motor" - desc = "A dark onyx prism, held in midair by spiraling tendrils of stone." - clockwork_desc = "A powerful prism that rapidly repairs nearby mechanical servants and clockwork structures." - icon_state = "mending_motor_inactive" - active_icon = "mending_motor" - inactive_icon = "mending_motor_inactive" - construction_value = 20 - max_integrity = 125 - obj_integrity = 125 - break_message = "The prism collapses with a heavy thud!" - debris = list(/obj/item/clockwork/alloy_shards/small = 5, \ - /obj/item/clockwork/alloy_shards/medium = 1, \ - /obj/item/clockwork/alloy_shards/large = 1, \ - /obj/item/clockwork/component/vanguard_cogwheel = 1) - var/stored_alloy = 0 - var/max_alloy = REPLICANT_ALLOY_POWER * 10 - var/mob_cost = 200 - var/structure_cost = 250 - var/cyborg_cost = 300 - -/obj/structure/destructible/clockwork/powered/mending_motor/prefilled - stored_alloy = REPLICANT_ALLOY_POWER //starts with 1 replicant alloy's worth of power - -/obj/structure/destructible/clockwork/powered/mending_motor/total_accessable_power() - . = ..() - if(. != INFINITY) - . += accessable_alloy_power() - -/obj/structure/destructible/clockwork/powered/mending_motor/proc/accessable_alloy_power() - return stored_alloy - -/obj/structure/destructible/clockwork/powered/mending_motor/use_power(amount) - var/alloypower = accessable_alloy_power() - while(alloypower >= MIN_CLOCKCULT_POWER && amount >= MIN_CLOCKCULT_POWER) - stored_alloy -= MIN_CLOCKCULT_POWER - alloypower -= MIN_CLOCKCULT_POWER - amount -= MIN_CLOCKCULT_POWER - return ..() - -/obj/structure/destructible/clockwork/powered/mending_motor/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "It contains [stored_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER]/[max_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER] units of liquified alloy, \ - which is equivalent to [stored_alloy]W/[max_alloy]W of power." - user << "It requires [mob_cost]W to heal clockwork mobs, [structure_cost]W for clockwork structures, and [cyborg_cost]W for cyborgs." - -/obj/structure/destructible/clockwork/powered/mending_motor/process() - if(..() < mob_cost) - visible_message("[src] emits an airy chuckling sound and falls dark!") - toggle() - return - for(var/atom/movable/M in range(5, src)) - if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab)) - var/mob/living/simple_animal/hostile/clockwork/W = M - var/fatigued = FALSE - if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder)) - var/mob/living/simple_animal/hostile/clockwork/marauder/E = M - if(E.fatigue) - fatigued = TRUE - if((!fatigued && W.health == W.maxHealth) || W.stat) - continue - if(!try_use_power(mob_cost)) - break - W.adjustHealth(-20) - else if(istype(M, /obj/structure/destructible/clockwork)) - var/obj/structure/destructible/clockwork/C = M - if(C.obj_integrity == C.max_integrity) - continue - if(!try_use_power(structure_cost)) - break - C.obj_integrity = min(C.obj_integrity + 20, C.max_integrity) - else if(issilicon(M)) - var/mob/living/silicon/S = M - if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S)) - continue - if(!try_use_power(cyborg_cost)) - break - S.adjustBruteLoss(-20) - S.adjustFireLoss(-10) - return 1 - -/obj/structure/destructible/clockwork/powered/mending_motor/attack_hand(mob/living/user) - if(user.canUseTopic(src, BE_CLOSE)) - if(total_accessable_power() < mob_cost) - user << "[src] needs more power or replicant alloy to function!" - return 0 - toggle(0, user) - -/obj/structure/destructible/clockwork/powered/mending_motor/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user)) - if(stored_alloy + REPLICANT_ALLOY_POWER > max_alloy) - user << "[src] is too full to accept any more alloy!" - return 0 - playsound(user, 'sound/machines/click.ogg', 50, 1) - clockwork_say(user, text2ratvar("Transmute into fuel."), TRUE) - user << "You force [I] to liquify and pour it into [src]'s compartments. \ - It now contains [stored_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER]/[max_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER] units of liquified alloy." - stored_alloy = stored_alloy + REPLICANT_ALLOY_POWER - user.drop_item() - qdel(I) - return 1 - else - return ..() - - - -/obj/structure/destructible/clockwork/powered/mania_motor //Mania motor: A pair of antenna that, while active, cause braindamage and hallucinations in nearby human mobs. - name = "mania motor" - desc = "A pair of antenna with what appear to be sockets around the base. It reminds you of an antlion." - clockwork_desc = "A transmitter that allows Sevtug to whisper into the minds of nearby non-servants, causing hallucinations and brain damage as long as it remains powered." - icon_state = "mania_motor_inactive" - active_icon = "mania_motor" - inactive_icon = "mania_motor_inactive" - construction_value = 20 - max_integrity = 80 - obj_integrity = 80 - break_message = "The antenna break off, leaving a pile of shards!" - debris = list(/obj/item/clockwork/alloy_shards/large = 1, \ - /obj/item/clockwork/alloy_shards/small = 3, \ - /obj/item/clockwork/component/guvax_capacitor/antennae = 1) - var/mania_cost = 200 - var/convert_attempt_cost = 200 - var/convert_cost = 200 - - var/mania_messages = list("\"Go nuts.\"", "\"Take a crack at crazy.\"", "\"Make a bid for insanity.\"", "\"Get kooky.\"", "\"Move towards mania.\"", "\"Become bewildered.\"", "\"Wax wild.\"", \ - "\"Go round the bend.\"", "\"Land in lunacy.\"", "\"Try dementia.\"", "\"Strive to get a screw loose.\"") - var/compel_messages = list("\"Come closer.\"", "\"Approach the transmitter.\"", "\"Touch the antennae.\"", "\"I always have to deal with idiots. Move towards the mania motor.\"", \ - "\"Advance forward and place your head between the antennae - that's all it's good for.\"", "\"If you were smarter, you'd be over here already.\"", "\"Move FORWARD, you fool.\"") - var/convert_messages = list("\"You won't do. Go to sleep while I tell these nitwits how to convert you.\"", "\"You are insufficient. I must instruct these idiots in the art of conversion.\"", \ - "\"Oh of course, someone we can't convert. These servants are fools.\"", "\"How hard is it to use a Sigil, anyway? All it takes is dragging someone onto it.\"", \ - "\"How do they fail to use a Sigil of Accession, anyway?\"", "\"Why is it that all servants are this inept?\"", "\"It's quite likely you'll be stuck here for a while.\"") - var/close_messages = list("\"Well, you can't reach the motor from THERE, you moron.\"", "\"Interesting location. I'd prefer if you went somewhere you could ACTUALLY TOUCH THE ANTENNAE!\"", \ - "\"Amazing. You somehow managed to wedge yourself somewhere you can't actually reach the motor from.\"", "\"Such a show of idiocy is unparalleled. Perhaps I should put you on display?\"", \ - "\"Did you do this on purpose? I can't imagine you doing so accidentally. Oh, wait, I can.\"", "\"How is it that such smart creatures can still do something AS STUPID AS THIS!\"") - - -/obj/structure/destructible/clockwork/powered/mania_motor/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "It requires [mania_cost]W to run, and [convert_attempt_cost + convert_cost]W to convert humans adjecent to it." - -/obj/structure/destructible/clockwork/powered/mania_motor/process() - if(try_use_power(mania_cost)) - var/turf/T = get_turf(src) - var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected - for(var/mob/living/carbon/human/H in view(1, src)) - if(is_servant_of_ratvar(H)) - continue - if(H.Adjacent(src) && try_use_power(convert_attempt_cost)) - if(is_eligible_servant(H) && try_use_power(convert_cost)) - H << "\"[text2ratvar("You are mine and his, now.")]\"" - H.playsound_local(T, hum, 80, 1) - add_servant_of_ratvar(H) - else if(!H.stat) - if(H.getBrainLoss() >= 100) - H.Paralyse(5) - H << "[text2ratvar(pick(convert_messages))]" - else - H.adjustBrainLoss(100) - H.visible_message("[H] reaches out and touches [src].", "You touch [src] involuntarily.") - else - visible_message("[src]'s antennae fizzle quietly.") - playsound(src, 'sound/effects/light_flicker.ogg', 50, 1) - for(var/mob/living/carbon/human/H in range(10, src)) - if(is_servant_of_ratvar(H)) - if(H.getBrainLoss() || H.hallucination || H.druggy || H.dizziness || H.confused) - H.adjustBrainLoss(-H.getBrainLoss()) //heals servants of braindamage, hallucination, druggy, dizziness, and confusion - H.hallucination = 0 - H.adjust_drugginess(-H.druggy) - H.dizziness = 0 - H.confused = 0 - else if(!H.null_rod_check() && H.stat == CONSCIOUS) - var/distance = get_dist(T, get_turf(H)) - var/falloff_distance = min((110) - distance * 10, 80) - var/sound_distance = falloff_distance * 0.5 - var/targetbrainloss = H.getBrainLoss() - if(distance >= 4 && prob(falloff_distance * 0.5)) - H << "[text2ratvar(pick(mania_messages))]" - H.playsound_local(T, hum, sound_distance, 1) - switch(distance) - if(2 to 3) - if(prob(falloff_distance * 0.5)) - if(prob(falloff_distance)) - H << "[text2ratvar(pick(mania_messages))]" - else - H << "[text2ratvar(pick(compel_messages))]" - if(targetbrainloss <= 50) - H.adjustBrainLoss(50 - targetbrainloss) //got too close had brain eaten - H.adjust_drugginess(Clamp(7, 0, 100 - H.druggy)) - H.hallucination = min(H.hallucination + 7, 100) - H.dizziness = min(H.dizziness + 3, 45) - H.confused = min(H.confused + 3, 45) - if(4 to 5) - if(targetbrainloss <= 50) - H.adjustBrainLoss(1) - H.adjust_drugginess(Clamp(5, 0, 80 - H.druggy)) - H.hallucination = min(H.hallucination + 5, 80) - H.dizziness = min(H.dizziness + 2, 30) - H.confused = min(H.confused + 2, 30) - if(6 to 7) - if(targetbrainloss <= 30) - H.adjustBrainLoss(1) - H.adjust_drugginess(Clamp(2, 0, 60 - H.druggy)) - H.hallucination = min(H.hallucination + 2, 60) - H.dizziness = min(H.dizziness + 2, 15) - H.confused = min(H.confused + 2, 15) - if(8 to 9) - if(targetbrainloss <= 10) - H.adjustBrainLoss(1) - H.adjust_drugginess(Clamp(2, 0, 40 - H.druggy)) - H.hallucination = min(H.hallucination + 2, 40) - if(10 to INFINITY) - H.adjust_drugginess(Clamp(2, 0, 20 - H.druggy)) - H.hallucination = min(H.hallucination + 2, 20) - else //if it's a distance of 1 and they can't see it/aren't adjacent or they're on top of it(how'd they get on top of it and still trigger this???) - if(prob(falloff_distance * 0.5)) - if(prob(falloff_distance)) - H << "[text2ratvar(pick(compel_messages))]" - else if(prob(falloff_distance * 0.5)) - H << "[text2ratvar(pick(close_messages))]" - else - H << "[text2ratvar(pick(mania_messages))]" - if(targetbrainloss <= 99) - H.adjustBrainLoss(99 - targetbrainloss) - H.adjust_drugginess(Clamp(10, 0, 150 - H.druggy)) - H.hallucination = min(H.hallucination + 10, 150) - H.dizziness = min(H.dizziness + 5, 60) - H.confused = min(H.confused + 5, 60) - - else - visible_message("[src] hums loudly, then the sockets at its base fall dark!") - playsound(src, 'sound/effects/screech.ogg', 40, 1) - toggle(0) - -/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user) - if(user.canUseTopic(src, BE_CLOSE)) - if(!total_accessable_power() >= mania_cost) - user << "[src] needs more power to function!" - return 0 - toggle(0, user) - - - -/obj/structure/destructible/clockwork/powered/clockwork_obelisk - name = "clockwork obelisk" - desc = "A large brass obelisk hanging in midair." - clockwork_desc = "A powerful obelisk that can send a message to all servants or open a gateway to a target servant or clockwork obelisk." - icon_state = "obelisk_inactive" - active_icon = "obelisk" - inactive_icon = "obelisk_inactive" - construction_value = 20 - max_integrity = 150 - obj_integrity = 150 - break_message = "The obelisk falls to the ground, undamaged!" - debris = list(/obj/item/clockwork/alloy_shards/small = 3, \ - /obj/item/clockwork/component/hierophant_ansible/obelisk = 1) - var/hierophant_cost = MIN_CLOCKCULT_POWER //how much it costs to broadcast with large text - var/gateway_cost = 2000 //how much it costs to open a gateway - var/gateway_active = FALSE - -/obj/structure/destructible/clockwork/powered/clockwork_obelisk/New() - ..() - toggle(1) - -/obj/structure/destructible/clockwork/powered/clockwork_obelisk/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "It requires [hierophant_cost]W to broadcast over the Hierophant Network, and [gateway_cost]W to open a Spatial Gateway." - -/obj/structure/destructible/clockwork/powered/clockwork_obelisk/process() - if(locate(/obj/effect/clockwork/spatial_gateway) in loc) - icon_state = active_icon - density = 0 - gateway_active = TRUE - else - icon_state = inactive_icon - density = 1 - gateway_active = FALSE - -/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user) - if(!is_servant_of_ratvar(user) || !total_accessable_power() >= hierophant_cost) - user << "You place your hand on the obelisk, but it doesn't react." - return - var/choice = alert(user,"You place your hand on the obelisk...",,"Hierophant Broadcast","Spatial Gateway","Cancel") - switch(choice) - if("Hierophant Broadcast") - if(gateway_active) - user << "The obelisk is sustaining a gateway and cannot broadcast!" - return - var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "") - if(!input || !user.canUseTopic(src, BE_CLOSE)) - return - if(gateway_active) - user << "The obelisk is sustaining a gateway and cannot broadcast!" - return - if(!try_use_power(hierophant_cost)) - user << "The obelisk lacks the power to broadcast!" - return - clockwork_say(user, text2ratvar("Hierophant Broadcast, activate!")) - titled_hierophant_message(user, input, "big_brass", "large_brass") - if("Spatial Gateway") - if(gateway_active) - user << "The obelisk is already sustaining a gateway!" - return - if(!try_use_power(gateway_cost)) - user << "The obelisk lacks the power to open a gateway!" - return - if(procure_gateway(user, 100, 5, 1) && !gateway_active) - clockwork_say(user, text2ratvar("Spatial Gateway, activate!")) - else - return_power(gateway_cost) - if("Cancel") - return - - - -/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 outnumbered by servants at a rate to 5:1." - icon_state = "tinkerers_daemon" - active_icon = "tinkerers_daemon" - inactive_icon = "tinkerers_daemon" - max_integrity = 100 - obj_integrity = 100 - break_message = "The daemon shatters into millions of pieces!" - debris = list(/obj/item/clockwork/alloy_shards/large = 2, \ - /obj/item/clockwork/alloy_shards/medium = 4, \ - /obj/item/clockwork/alloy_shards/small = 6) - var/image/daemon_glow - var/image/component_glow - var/component_id_to_produce - var/production_time = 0 //last time we produced a component - var/production_cooldown = 120 - -/obj/structure/destructible/clockwork/powered/tinkerers_daemon/New() - ..() - clockwork_daemons++ - -/obj/structure/destructible/clockwork/powered/tinkerers_daemon/Destroy() - clockwork_daemons-- - 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) - user << "It is currently producing [get_component_name(component_id_to_produce)][component_id_to_produce != "replicant_alloy" ? "s":""]." - else - user << "It is currently producing random components." - user << "It will produce a component every [production_cooldown*0.1] seconds and requires at least the following power for each component type:" - for(var/i in clockwork_component_cache) - user << "[get_component_name(i)]: [get_component_cost(i)]W ([clockwork_component_cache[i]] exist[clockwork_component_cache[i] == 1 ? "s" : ""])" - -/obj/structure/destructible/clockwork/powered/tinkerers_daemon/attack_hand(mob/living/user) - if(!is_servant_of_ratvar(user)) - user << "You place your hand on the daemon, but nothing happens." - return - if(active) - toggle(0, user) - else - if(!clockwork_caches) - user << "There are no clockwork caches! Activating this daemon would be a waste of power." - 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 clockwork_component_cache) - components["[get_component_name(i)] ([get_component_cost(i)]W)"] = i - var/input_component = input(user, "Choose a component type.", name) as null|anything in components - component_id_to_produce = components[input_component] - if(!user.canUseTopic(src, BE_CLOSE) || active) - return - if(!component_id_to_produce) - user << "You decide not to select a component and activate the daemon." - return - if(total_accessable_power() < get_component_cost(component_id_to_produce)) - user << "There is too little power to produce this type of component!" - return - toggle(0, user) - if("Random Component") - component_id_to_produce = null - toggle(0, user) - -/obj/structure/destructible/clockwork/powered/tinkerers_daemon/toggle(fast_process, mob/living/user) - . = ..() - if(active) - var/component_color = get_component_color(component_id_to_produce) - if(!daemon_glow) - daemon_glow = new('icons/obj/clockwork_objects.dmi', "tinkerglow") - daemon_glow.color = component_color - add_overlay(daemon_glow) - if(!component_glow) - component_glow = new('icons/obj/clockwork_objects.dmi', "t_[component_id_to_produce ? component_id_to_produce :"random_component"]") - else - 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 afteer being off - else - cut_overlays() - -/obj/structure/destructible/clockwork/powered/tinkerers_daemon/proc/get_component_cost(id) - return max(MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER * (1 + round(clockwork_component_cache[id] * 0.2))) - -/obj/structure/destructible/clockwork/powered/tinkerers_daemon/process() - var/servants = 0 - for(var/mob/living/L in living_mob_list) - if(is_servant_of_ratvar(L)) - servants++ - . = ..() - var/min_power_usable = 0 - if(!component_id_to_produce) - for(var/i in 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(!clockwork_caches || servants * 0.2 < clockwork_daemons || . < min_power_usable) //if we don't have enough to produce the lowest or what we chose to produce, cancel out - visible_message("[src] shuts down!") - toggle() - 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 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) - PoolOrNew(get_component_animation_type(component_to_generate), get_turf(src)) - clockwork_component_cache[component_to_generate]++ - production_time = world.time + production_cooldown //go on cooldown - visible_message("[src] hums as it produces a [get_component_name(component_to_generate)].") - else - visible_message("[src] shuts down!") //we shouldn't actually ever get here, as we should cancel out way before this - toggle() diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm index 9646645908a..e02586f8fca 100644 --- a/code/game/gamemodes/clock_cult/clock_scripture.dm +++ b/code/game/gamemodes/clock_cult/clock_scripture.dm @@ -36,7 +36,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or if(can_recite() && has_requirements() && check_special_requirements()) if(slab.busy) invoker << "[slab] refuses to work, displaying the message: \"[slab.busy]!\"" - return 0 + return FALSE slab.busy = "Invocation ([name]) in progress" if(!ratvar_awakens && !slab.no_cost) for(var/i in consumed_components) @@ -65,15 +65,15 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or if(slab) slab.busy = null qdel(src) - return 1 + return TRUE /datum/clockwork_scripture/proc/can_recite() //If the words can be spoken if(!ticker || !ticker.mode || !slab || !invoker) - return 0 + return FALSE if(!invoker.can_speak_vocal()) invoker << "You are unable to speak the words of the scripture!" - return 0 - return 1 + return FALSE + return TRUE /datum/clockwork_scripture/proc/has_requirements() //if we have the components and invokers to do it if(!ratvar_awakens && !slab.no_cost) @@ -89,7 +89,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or if(failed) component_printout += "" invoker << component_printout - return 0 + return FALSE if(multiple_invokers_used && !multiple_invokers_optional && !ratvar_awakens && !slab.no_cost) var/nearby_servants = 0 for(var/mob/living/L in range(1, invoker)) @@ -97,11 +97,11 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or nearby_servants++ if(nearby_servants < invokers_required) invoker << "There aren't enough non-mute servants nearby ([nearby_servants]/[invokers_required])!" - return 0 - return 1 + return FALSE + return TRUE /datum/clockwork_scripture/proc/check_special_requirements() //Special requirements for scriptures, checked three times during invocation - return 1 + return TRUE /datum/clockwork_scripture/proc/recital() //The process of speaking the words if(!channel_time && invocations.len) @@ -115,24 +115,24 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or clockwork_say(invoker, text2ratvar(invocation), whispered) invoker << "You [channel_time <= 0 ? "recite" : "begin reciting"] a piece of scripture entitled \"[name]\"." if(!channel_time) - return 1 + return TRUE for(var/invocation in invocations) if(!do_after(invoker, channel_time / invocations.len, target = invoker)) slab.busy = null - return 0 + return FALSE if(multiple_invokers_used) for(var/mob/living/L in range(1, invoker)) if(is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal()) clockwork_say(L, text2ratvar(invocation), whispered) else clockwork_say(invoker, text2ratvar(invocation), whispered) - return 1 + return TRUE /datum/clockwork_scripture/proc/scripture_effects() //The actual effects of the recital after its conclusion - -/datum/clockwork_scripture/channeled //Channeled scripture begins instantly but runs constantly +//Channeled scripture begins instantly but runs constantly +/datum/clockwork_scripture/channeled var/list/chant_invocations = list("AYY LMAO") var/chant_amount = 5 //Times the chant is spoken var/chant_interval = 10 //Amount of deciseconds between times the chant is actually spoken aloud @@ -146,16 +146,17 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or clockwork_say(invoker, text2ratvar(pick(chant_invocations)), whispered) chant_effects(i) if(invoker && slab) - invoker << "You cease your chant." chant_end_effects() - return 1 + return TRUE /datum/clockwork_scripture/channeled/proc/chant_effects(chant_number) //The chant's periodic effects + /datum/clockwork_scripture/channeled/proc/chant_end_effects() //The chant's effect upon ending + invoker << "You cease your chant." - -/datum/clockwork_scripture/create_object //Creates an object at the invoker's feet +//Creates an object at the invoker's feet +/datum/clockwork_scripture/create_object var/object_path = /obj/item/clockwork //The path of the object created var/creator_message = "You create a meme." //Shown to the invoker var/observer_message @@ -172,11 +173,11 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or var/turf/T = get_turf(invoker) if(!space_allowed && isspaceturf(T)) invoker << "You need solid ground to place this object!" - return 0 + return FALSE if(one_per_tile && (locate(prevent_path) in T)) invoker << "You can only place one of this object on each tile!" - return 0 - return 1 + return FALSE + return TRUE /datum/clockwork_scripture/create_object/scripture_effects() if(creator_message && observer_message) @@ -184,1130 +185,4 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or else if(creator_message) invoker << creator_message new object_path (get_turf(invoker)) - return 1 - -///////////// -// DRIVERS // -///////////// - -/datum/clockwork_scripture/channeled/belligerent //Belligerent: Channeled for up to fiteen times over thirty seconds. Forces non-servants that can hear the chant to walk. Nar-Sian cultists are burned. - 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 - required_components = list("belligerent_eye" = 1) - usage_tip = "Useful for crowd control in a populated area and disrupting mass movement." - tier = SCRIPTURE_DRIVER - sort_priority = 1 - var/noncultist_damage = 2 //damage per chant to noncultists - var/cultist_damage = 8 //damage per chant to non-walking cultists - -/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number) - for(var/mob/living/carbon/C in hearers(7, invoker)) - var/number_legs = C.get_num_legs() - if(!is_servant_of_ratvar(C) && !C.null_rod_check() && number_legs) //you have legs right - C.apply_damage(noncultist_damage * 0.5, BURN, "l_leg") - C.apply_damage(noncultist_damage * 0.5, BURN, "r_leg") - if(C.m_intent != "walk") - if(!iscultist(C)) - C << "Your leg[number_legs > 1 ? "s shiver":" shivers"] with pain!" - else //Cultists take extra burn damage - C << "Your leg[number_legs > 1 ? "s burn":" burns"] with pain!" - C.apply_damage(cultist_damage * 0.5, BURN, "l_leg") - C.apply_damage(cultist_damage * 0.5, BURN, "r_leg") - C.m_intent = "walk" - - - -/datum/clockwork_scripture/create_object/judicial_visor //Judicial Visor: Creates a judicial visor. - descname = "Delayed Area Stun Glasses" - name = "Judicial Visor" - desc = "Forms a visor that, when worn, will grant the ability to smite an area, stunning, muting, and damaging the nonfaithful. \ - Cultists of Nar-Sie will be set on fire, though they will be stunned for half the time." - invocations = list("Grant me the flames of Engine!") - channel_time = 10 - required_components = list("belligerent_eye" = 2) - consumed_components = list("belligerent_eye" = 1) - whispered = TRUE - object_path = /obj/item/clothing/glasses/judicial_visor - creator_message = "You form a judicial visor, which is capable of smiting the unworthy." - usage_tip = "The visor has a thirty-second cooldown once used, and the marker it creates has a delay of 3 seconds before exploding." - tier = SCRIPTURE_DRIVER - space_allowed = TRUE - sort_priority = 2 - - - -/datum/clockwork_scripture/vanguard //Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker. - descname = "Self Stun Immunity" - name = "Vanguard" - desc = "Provides twenty seconds of stun immunity. At the end of the twenty seconds, the invoker is stunned for the equivalent of 25% of all stuns they absorbed. \ - Excessive absorption will cause unconsciousness." - invocations = list("Shield me...", "...from darkness!") - channel_time = 30 - required_components = list("vanguard_cogwheel" = 1) - usage_tip = "You cannot reactivate Vanguard while still shielded by it." - tier = SCRIPTURE_DRIVER - sort_priority = 3 - -/datum/clockwork_scripture/vanguard/check_special_requirements() - if(islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time) - invoker << "You are already shielded by a Vanguard!" - return 0 - return 1 - -/datum/clockwork_scripture/vanguard/scripture_effects() - invoker.apply_status_effect(STATUS_EFFECT_VANGUARD) - return 1 - - - -/datum/clockwork_scripture/sentinels_compromise //Sentinel's Compromise: Allows the invoker to select a nearby servant convert their brute and burn damage into half as much toxin damage. - descname = "Convert Brute/Burn to Half Toxin" - name = "Sentinel's Compromise" - desc = "Heals all brute and burn damage on a nearby living, friendly servant, but deals 50% of the damage they had as toxin damage." - invocations = list("Mend the wounds of...", "...my inferior flesh.") - channel_time = 30 - required_components = list("vanguard_cogwheel" = 2) - consumed_components = list("vanguard_cogwheel" = 1) - usage_tip = "The Compromise is very fast to invoke." - tier = SCRIPTURE_DRIVER - sort_priority = 4 - -/datum/clockwork_scripture/sentinels_compromise/scripture_effects() - var/list/nearby_cultists = list() - for(var/mob/living/C in range(7, invoker)) - if(C.stat != DEAD && is_servant_of_ratvar(C) && (C.getBruteLoss() || C.getFireLoss())) - nearby_cultists += C - if(!nearby_cultists.len) - invoker << "There are no eligible servants nearby!" - return 0 - var/mob/living/L = input(invoker, "Choose a fellow servant to heal.", name) as null|anything in nearby_cultists - if(!L || !invoker || !invoker.canUseTopic(slab)) - return 0 - var/brutedamage = L.getBruteLoss() - var/burndamage = L.getFireLoss() - var/totaldamage = brutedamage + burndamage - if(!totaldamage) - invoker << "[L] is not burned or bruised!" - return 0 - L.adjustToxLoss(totaldamage * 0.5) - L.adjustBruteLoss(-brutedamage) - L.adjustFireLoss(-burndamage) - var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20 - var/targetturf = get_turf(L) - for(var/i in 1 to healseverity) - PoolOrNew(/obj/effect/overlay/temp/heal, list(targetturf, "#1E8CE1")) - invoker << "You bathe [L] in Inath-neq's power!" - L.visible_message("A blue light washes over [L], mending [L.p_their()] bruises and burns!", \ - "You feel Inath-neq's power healing your wounds, but a deep nausea overcomes you!") - playsound(targetturf, 'sound/magic/Staff_Healing.ogg', 50, 1) - return 1 - - - -/datum/clockwork_scripture/guvax //Guvax: Converts anyone adjacent to the invoker after completion. - descname = "Melee Area Convert" - name = "Guvax" - desc = "Enlists all nearby living unshielded creatures into servitude to Ratvar. Also purges holy water from nearby Servants." - invocations = list("Enlighten this heathen!", "All are insects before Engine!", "Purge all untruths and honor Engine.") - channel_time = 50 - required_components = list("guvax_capacitor" = 1) - usage_tip = "Only works on those in melee range and does not penetrate mindshield implants. Much more efficient than a Sigil of Submission at low Servant amounts." - tier = SCRIPTURE_DRIVER - sort_priority = 5 - -/datum/clockwork_scripture/guvax/run_scripture() - var/servants = 0 - for(var/mob/living/M in living_mob_list) - if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M))) - servants++ - if(servants > 5) - servants -= 5 - channel_time = min(channel_time + servants*10, 200) //if above 5 servants, is much slower - return ..() - -/datum/clockwork_scripture/guvax/scripture_effects() - for(var/mob/living/L in hearers(1, get_turf(invoker))) //Affects silicons - if(!is_servant_of_ratvar(L)) - if(L.stat != DEAD) - add_servant_of_ratvar(L) - else - if(L.reagents && L.reagents.has_reagent("holywater")) - L.reagents.remove_reagent("holywater", 1000) - L << "Ratvar's light flares, banishing the darkness. Your devotion remains intact!" - return 1 - - - -/datum/clockwork_scripture/channeled/taunting_tirade //Taunting Tirade: Channeled for up to five times over thirty seconds. Confuses non-servants that can hear it and allows movement for a brief time after each channel - descname = "Channeled, Mobile Area Confusion" - name = "Taunting Tirade" - desc = "Weakens, confuses and dizzies all nearby non-servants with a short invocation, then allows movement for five seconds. Chanted every second for up to thirty seconds." - chant_invocations = list("Hostiles on my back!", "Enemies on my trail!", "Gonna try and shake my tail.", "Bogeys on my six!") - chant_amount = 5 - chant_interval = 10 - required_components = list("guvax_capacitor" = 2) - consumed_components = list("guvax_capacitor" = 1) - usage_tip = "Useful for fleeing attackers, as few will be able to follow someone using this scripture." - tier = SCRIPTURE_DRIVER - sort_priority = 6 - var/flee_time = 47 //allow fleeing for 5 seconds - var/grace_period = 3 //very short grace period so you don't have to stop immediately - var/datum/progressbar/progbar - -/datum/clockwork_scripture/channeled/taunting_tirade/chant_effects(chant_number) - for(var/mob/living/L in hearers(7, invoker)) - if(!is_servant_of_ratvar(L) && !L.null_rod_check()) - L.confused = min(L.confused + 20, 100) - L.dizziness = min(L.dizziness + 20, 100) - L.Weaken(1) - invoker.visible_message("[invoker] is suddenly covered with a thin layer of dark purple smoke!") - invoker.color = "#AF0AAF" - animate(invoker, color = initial(invoker.color), time = flee_time+grace_period) - if(chant_number != chant_amount) //if this is the last chant, we don't have a movement period because the chant is over - var/endtime = world.time + flee_time - var/starttime = world.time - progbar = new(invoker, flee_time, invoker) - progbar.bar.color = "#AF0AAF" - animate(progbar.bar, color = initial(progbar.bar.color), time = flee_time+grace_period) - while(world.time < endtime) - sleep(1) - progbar.update(world.time - starttime) - qdel(progbar) - sleep(grace_period) - -/datum/clockwork_scripture/channeled/taunting_tirade/chant_end_effects() - qdel(progbar) - - - -/datum/clockwork_scripture/replicant //Replicant: Creates a new clockwork slab. Doesn't use create_object because of its unique behavior. - descname = "New Clockwork Slab" - name = "Replicant" - desc = "Creates a new clockwork slab." - invocations = list("Metal, become greater!") - channel_time = 10 - required_components = list("replicant_alloy" = 1) - whispered = TRUE - usage_tip = "This is inefficient as a way to produce components, as the slab produced must be held by someone with no other slabs to produce components." - tier = SCRIPTURE_DRIVER - sort_priority = 7 - -/datum/clockwork_scripture/replicant/scripture_effects() - invoker << "You copy a piece of replicant alloy and command it into a new slab." //No visible message, for stealth purposes - var/obj/item/clockwork/slab/S = new(get_turf(invoker)) - invoker.put_in_hands(S) //Put it in your hands if possible - return 1 - - - -/datum/clockwork_scripture/create_object/tinkerers_cache //Tinkerer's Cache: Creates a tinkerer's cache. - descname = "Necessary, 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." - invocations = list("Constructing...", "...a cache!") - channel_time = 50 - required_components = list("belligerent_eye" = 0, "vanguard_cogwheel" = 0, "guvax_capacitor" = 0, "replicant_alloy" = 2, "hierophant_ansible" = 0) - consumed_components = list("belligerent_eye" = 0, "vanguard_cogwheel" = 0, "guvax_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 very efficient." - tier = SCRIPTURE_DRIVER - one_per_tile = TRUE - sort_priority = 8 - -/datum/clockwork_scripture/create_object/tinkerers_cache/New() - var/cache_cost_increase = min(round(clockwork_caches*0.2), 5) - for(var/i in required_components) - if(i != "replicant_alloy") - required_components[i] += cache_cost_increase - for(var/i in consumed_components) - if(i != "replicant_alloy") - consumed_components[i] += cache_cost_increase - return ..() - - - -/datum/clockwork_scripture/create_object/wraith_spectacles //Wraith Spectacles: Creates a pair of wraith spectacles. - descname = "Xray Vision Glasses" - name = "Wraith Spectacles" - desc = "Fabricates a pair of glasses that provides true sight but quickly damage vision, eventually causing blindness if worn for too long." - invocations = list("Show the truth of this world to me!") - channel_time = 10 - required_components = list("hierophant_ansible" = 1) - whispered = TRUE - object_path = /obj/item/clothing/glasses/wraith_spectacles - creator_message = "You form a pair of wraith spectacles, which will grant true sight when worn." - usage_tip = "\"True sight\" means that you are able to see through walls and in darkness." - tier = SCRIPTURE_DRIVER - space_allowed = TRUE - sort_priority = 9 - - - -/datum/clockwork_scripture/create_object/sigil_of_transgression //Sigil of Transgression: Creates a sigil of transgression. - descname = "Stun Trap" - name = "Sigil of Transgression" - desc = "Wards a tile with a sigil. The next person to cross the sigil will be smitten and unable to move. Nar-Sian cultists are stunned altogether." - invocations = list("Divinity, dazzle...", "...those who tresspass here!") - channel_time = 50 - required_components = list("hierophant_ansible" = 2) - consumed_components = list("hierophant_ansible" = 1) - whispered = TRUE - object_path = /obj/effect/clockwork/sigil/transgression - creator_message = "A sigil silently appears below you. The next non-servant to cross it will be immobilized." - usage_tip = "The sigil, while fairly powerful in its stun, does not induce muteness in its victim." - tier = SCRIPTURE_DRIVER - one_per_tile = TRUE - sort_priority = 10 - -///////////// -// SCRIPTS // -///////////// - -/datum/clockwork_scripture/create_object/ocular_warden //Ocular Warden: Creates an ocular warden. - descname = "Turret" - name = "Ocular Warden" - desc = "Forms an automatic short-range turret that deals low sustained damage to the unenlightened in its range." - invocations = list("Guardians...", "...of the Engine...", "...defend us!") - channel_time = 120 - required_components = list("belligerent_eye" = 2, "replicant_alloy" = 1) - consumed_components = list("belligerent_eye" = 1, "replicant_alloy" = 1) - object_path = /obj/structure/destructible/clockwork/ocular_warden - creator_message = "You form an ocular warden, which will focus its searing gaze upon nearby unenlightened." - observer_message = "A brass eye takes shape and slowly rises into the air, its red iris glaring!" - usage_tip = "Although powerful, the warden is very weak and should optimally be placed behind barricades." - tier = SCRIPTURE_SCRIPT - one_per_tile = TRUE - space_allowed = TRUE - sort_priority = 11 - -/datum/clockwork_scripture/create_object/ocular_warden/check_special_requirements() - for(var/obj/structure/destructible/clockwork/ocular_warden/W in range(3, invoker)) - invoker << "You sense another ocular warden too near this location. Placing another this close would cause them to fight." //fluff message - return 0 - return ..() - - -/datum/clockwork_scripture/channeled/volt_void //Volt Void: Channeled for up to thirty times over thirty seconds. Consumes power from most power storages and deals slight burn damage to the invoker. - descname = "Channeled, Area Power Drain" - name = "Volt Void" //Alternative name: "On all levels but physical, I am a power sink" - desc = "Drains energy from nearby power sources, dealing burn damage if the total power consumed is above a threshhold. Channeled every second for a maximum of thirty seconds." - chant_invocations = list("Draw charge to this shell!") - chant_amount = 30 - chant_interval = 10 - required_components = list("guvax_capacitor" = 1, "hierophant_ansible" = 2) - consumed_components = list("guvax_capacitor" = 1, "hierophant_ansible" = 1) - usage_tip = "If standing on a Sigil of Transmission, will transfer power to it. Augumented limbs will also be healed unless above a very high threshhold." - tier = SCRIPTURE_SCRIPT - sort_priority = 20 - var/total_power_drained = 0 - var/power_damage_threshhold = 3000 - var/augument_damage_threshhold = 6000 - -/datum/clockwork_scripture/channeled/volt_void/chant_effects(chant_number) - playsound(invoker, 'sound/effects/EMPulse.ogg', 50, 1) - var/power_drained = 0 - for(var/atom/movable/A in view(7, invoker)) - power_drained += A.power_drain(TRUE) - var/obj/effect/clockwork/sigil/transmission/ST = locate(/obj/effect/clockwork/sigil/transmission) in get_turf(invoker) - if(ST && power_drained >= 50) - var/sigil_drain = 0 - while(power_drained >= 50) - ST.modify_charge(-50) - power_drained -= 50 - sigil_drain += 10 - power_drained += sigil_drain //readd part of the power given to the sigil to the power drained this cycle - ST.visible_message("[ST] flares a brilliant orange!") - total_power_drained += power_drained - if(power_drained >= 100 && total_power_drained >= power_damage_threshhold) - var/power_damage = power_drained * 0.01 - invoker.visible_message("[invoker] flares a brilliant orange!", "You feel the warmth of electricity running into your body.") - if(ishuman(invoker)) - var/mob/living/carbon/human/H = invoker - for(var/X in H.bodyparts) - var/obj/item/bodypart/BP = X - if(ratvar_awakens || (BP.status == BODYPART_ROBOTIC && total_power_drained < augument_damage_threshhold)) //if ratvar is alive, it won't damage and will always heal augumented limbs - if(BP.heal_damage(power_damage, power_damage, 1, 0)) //heals one point of burn and brute for every ~100W drained on augumented limbs - H.update_damage_overlays() - else - if(BP.receive_damage(0, power_damage)) - H.update_damage_overlays() - else if(isanimal(invoker)) - var/mob/living/simple_animal/A = invoker - A.adjustHealth(-power_damage) //if a simple animal is using volt void, just heal it - return 1 - - - -/datum/clockwork_scripture/create_object/clockwork_proselytizer //Clockwork Proselytizer: Creates a clockwork proselytizer. - descname = "Necessary, Converts Objects" - name = "Clockwork Proselytizer" - desc = "Forms a device that, when used on certain objects, converts them into their Ratvarian equivalents. It requires replicant alloys to function." - invocations = list("With this device...", "...his presence shall be made known.") - channel_time = 20 - required_components = list("guvax_capacitor" = 1, "replicant_alloy" = 2) - consumed_components = list("guvax_capacitor" = 1, "replicant_alloy" = 1) - whispered = TRUE - object_path = /obj/item/clockwork/clockwork_proselytizer/preloaded - creator_message = "You form a clockwork proselytizer, which is already pre-loaded with a small amount of replicant alloy." - usage_tip = "Clockwork walls cause adjacent tinkerer's caches to generate components passively, making them a vital tool. Clockwork floors heal servants standing on them." - tier = SCRIPTURE_SCRIPT - space_allowed = TRUE - sort_priority = 17 - - - -/datum/clockwork_scripture/fellowship_armory //Fellowship Armory: Arms the invoker and nearby servants with Ratvarian armor. - descname = "Area Servant Armor" - name = "Fellowship Armory" - desc = "Equips the invoker and any nearby servants with Ratvarian armor. This armor provides high melee resistance but a weakness to lasers. \ - It grows faster to invoke with more nearby servants." - invocations = list("Shield me...", "...with the...", "... fragments of Engine!") - channel_time = 110 //effectively 100 because it counts the invoker - required_components = list("vanguard_cogwheel" = 2, "replicant_alloy" = 1) - consumed_components = list("vanguard_cogwheel" = 1, "replicant_alloy" = 1) - usage_tip = "Before using, advise adjacent allies to remove their helmets, external suits, gloves, and shoes." - tier = SCRIPTURE_SCRIPT - multiple_invokers_used = TRUE - multiple_invokers_optional = TRUE - sort_priority = 14 - -/datum/clockwork_scripture/fellowship_armory/run_scripture() - for(var/mob/living/L in range(1, invoker)) - if(is_servant_of_ratvar(L) && L.can_speak_vocal()) - channel_time = max(channel_time - 10, 0) - return ..() - -/datum/clockwork_scripture/fellowship_armory/scripture_effects() - for(var/mob/living/L in range(1, invoker)) - if(!is_servant_of_ratvar(L)) - continue - L.visible_message("Strange armor appears on [L]!", "A bright shimmer runs down your body, equipping you with Ratvarian armor.") - playsound(L, 'sound/magic/clockwork/fellowship_armory.ogg', 50, 1) - L.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head) - L.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit) - L.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves) - L.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes) - return 1 - - - -/datum/clockwork_scripture/function_call //Function Call: Grants the invoker the ability to call forth a Ratvarian spear that deals significant damage to silicons. - descname = "Summonable Spear" - name = "Function Call" - desc = "Grants the invoker the ability to call forth a powerful Ratvarian spear every three minutes. The spear will deal significant damage to Nar-Sie's dogs and silicon lifeforms, but will \ - vanish three minutes after being summoned." - invocations = list("Grant me...", "...the might of brass!") - channel_time = 20 - required_components = list("replicant_alloy" = 2, "hierophant_ansible" = 1) - consumed_components = list("replicant_alloy" = 1, "hierophant_ansible" = 1) - whispered = TRUE - usage_tip = "You can impale human targets with the spear by pulling them, then attacking. Throwing the spear at a mob will do massive damage and stun them, but break the spear." - tier = SCRIPTURE_SCRIPT - sort_priority = 18 - -/datum/clockwork_scripture/function_call/check_special_requirements() - for(var/datum/action/innate/function_call/F in invoker.actions) - invoker << "You have already bound a Ratvarian spear to yourself!" - return 0 - return invoker.can_hold_items() - -/datum/clockwork_scripture/function_call/scripture_effects() - invoker.visible_message("A shimmer of yellow light infuses [invoker]!", \ - "You bind a Ratvarian spear to yourself. Use the \"Function Call\" action button to call it forth.") - var/datum/action/innate/function_call/F = new() - F.Grant(invoker) - return 1 - - -/datum/clockwork_scripture/spatial_gateway - descname = "Teleport Gate" - name = "Spatial Gateway" - desc = "Tears open a miniaturized gateway in spacetime to any conscious servant that can transport objects or creatures to its destination. \ - Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration." - invocations = list("Spatial Gateway...", "...activate!") - channel_time = 80 - required_components = list("vanguard_cogwheel" = 1, "hierophant_ansible" = 2) - consumed_components = list("vanguard_cogwheel" = 1, "hierophant_ansible" = 1) - multiple_invokers_used = TRUE - multiple_invokers_optional = TRUE - usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal." - tier = SCRIPTURE_SCRIPT - sort_priority = 19 - -/datum/clockwork_scripture/spatial_gateway/check_special_requirements() - if(!isturf(invoker.loc)) - invoker << "You must not be inside an object to use this scripture!" - return 0 - var/other_servants = 0 - for(var/mob/living/L in living_mob_list) - if(is_servant_of_ratvar(L) && !L.stat != DEAD) - other_servants++ - for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects) - other_servants++ - if(!other_servants) - invoker << "There are no other servants or clockwork obelisks!" - return 0 - return 1 - -/datum/clockwork_scripture/spatial_gateway/scripture_effects() - var/portal_uses = 0 - var/duration = 0 - for(var/mob/living/L in range(1, invoker)) - if(!L.stat && is_servant_of_ratvar(L)) - portal_uses++ - duration += 40 //4 seconds - if(ratvar_awakens) - portal_uses = max(portal_uses, 100) //Very powerful if Ratvar has been summoned - duration = max(duration, 100) - return slab.procure_gateway(invoker, duration, portal_uses) - - - -/datum/clockwork_scripture/create_object/soul_vessel //Soul Vessel: Creates a soul vessel - descname = "Clockwork Posibrain" - name = "Soul Vessel" - desc = "Forms an ancient positronic brain with an overriding directive to serve Ratvar." - invocations = list("Herd the souls of...", "...the blasphemous damned!") - channel_time = 30 - required_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 2) - consumed_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 1) - whispered = TRUE - object_path = /obj/item/device/mmi/posibrain/soul_vessel - creator_message = "You form a soul vessel, which can be used in-hand to attract spirits, or used on an unconscious or dead human to extract their consciousness." - usage_tip = "The vessel can be used as a teleport target for Spatial Gateway, though it is generally better-used by placing it in a shell." - tier = SCRIPTURE_SCRIPT - space_allowed = TRUE - sort_priority = 16 - - - -/datum/clockwork_scripture/create_object/cogscarab //Cogscarab: Creates an empty cogscarab shell - descname = "Constructor Soul Vessel Shell" - name = "Cogscarab" - desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt proselytizer." - invocations = list("Call forth...", "...the workers of Armorer.") - channel_time = 60 - required_components = list("belligerent_eye" = 2, "hierophant_ansible" = 1) - consumed_components = list("belligerent_eye" = 1, "hierophant_ansible" = 1) - object_path = /obj/structure/destructible/clockwork/shell/cogscarab - creator_message = "You form a cogscarab, a constructor soul vessel receptable." - observer_message = "The slab disgorges a puddle of black metal that contracts and forms into a strange shell!" - usage_tip = "Useless without a soul vessel and should not be created without one." - tier = SCRIPTURE_SCRIPT - sort_priority = 12 - - - -/datum/clockwork_scripture/create_object/sigil_of_submission //Sigil of Submission: Creates a sigil of submission. - descname = "Conversion Trap" - name = "Sigil of Submission" - desc = "Places a luminous sigil that will enslave any valid beings standing on it after a time." - invocations = list("Divinity, enlighten...", "...those who trespass here!") - channel_time = 60 - required_components = list("belligerent_eye" = 1, "guvax_capacitor" = 2) - consumed_components = list("belligerent_eye" = 1, "guvax_capacitor" = 1) - whispered = TRUE - object_path = /obj/effect/clockwork/sigil/submission - creator_message = "A luminous sigil appears below you. The next non-servant to cross it will be enslaved after a brief time if they do not move." - usage_tip = "This is not a primary conversion method - use Guvax for that. It is advantageous as a trap, however, as it will transmit the name of the newly-converted." - tier = SCRIPTURE_SCRIPT - one_per_tile = TRUE - sort_priority = 15 - - -////////////////// -// APPLICATIONS // -////////////////// - -/datum/clockwork_scripture/create_object/anima_fragment //Anima Fragment: Creates an empty anima fragment - descname = "Fast Soul Vessel Shell" - name = "Anima Fragment" - desc = "Creates a large shell fitted for soul vessels. Adding an active soul vessel to it results in a powerful construct with decent health, notable melee power, \ - and exceptional speed, though taking damage will temporarily slow it down." - invocations = list("Call forth...", "...the soldiers of Armorer.") - channel_time = 80 - required_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "replicant_alloy" = 3) - consumed_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "replicant_alloy" = 2) - object_path = /obj/structure/destructible/clockwork/shell/fragment - creator_message = "You form an anima fragment, a powerful soul vessel receptable." - observer_message = "The slab disgorges a puddle of black metal that expands and forms into a strange shell!" - usage_tip = "Useless without a soul vessel and should not be created without one." - tier = SCRIPTURE_APPLICATION - sort_priority = 24 - - - -/datum/clockwork_scripture/create_object/sigil_of_accession //Sigil of Accession: Creates a sigil of accession. - descname = "Permenant Conversion Trap" - name = "Sigil of Accession" - desc = "Places a luminous sigil much like a Sigil of Submission, but it will remain even after successfully converting a non-implanted target. \ - It will penetrate mindshield implants once before disappearing." - invocations = list("Divinity, enslave...", "...all who trespass here!") - channel_time = 70 - required_components = list("belligerent_eye" = 3, "guvax_capacitor" = 1, "hierophant_ansible" = 1) - consumed_components = list("belligerent_eye" = 2, "guvax_capacitor" = 1, "hierophant_ansible" = 1) - whispered = TRUE - object_path = /obj/effect/clockwork/sigil/submission/accession - prevent_path = /obj/effect/clockwork/sigil/submission - creator_message = "A luminous sigil appears below you. All non-servants to cross it will be enslaved after a brief time if they do not move." - usage_tip = "It will remain after converting a target, unless that target has a mindshield implant, which it will break to convert them, but consume itself in the process." - tier = SCRIPTURE_APPLICATION - one_per_tile = TRUE - sort_priority = 21 - - - -/datum/clockwork_scripture/create_object/sigil_of_transmission - descname = "Structure Battery" - name = "Sigil of Transmission" - desc = "Scribes a sigil beneath the invoker which stores power to power clockwork structures." - invocations = list("Divinity...", "...power our creations!") - channel_time = 70 - required_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 1, "hierophant_ansible" = 3) - consumed_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 1, "hierophant_ansible" = 2) - whispered = TRUE - object_path = /obj/effect/clockwork/sigil/transmission - creator_message = "A sigil silently appears below you. It will automatically power clockwork structures adjecent to it." - usage_tip = "Can be recharged by using Volt Void while standing on it." - tier = SCRIPTURE_APPLICATION - one_per_tile = TRUE - sort_priority = 25 - - - -/datum/clockwork_scripture/create_object/vitality_matrix - descname = "Damage Trap" - name = "Vitality Matrix" - desc = "Scribes a sigil beneath the invoker which drains life from any living non-servants that cross it. Servants that cross it, however, will be healed based on how much it drained from non-servants. \ - Dead servants can be revived by this sigil if it has enough stored vitality." - invocations = list("Divinity...", "...steal their life...", "...for these shells!") - channel_time = 70 - required_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 3, "hierophant_ansible" = 1) - consumed_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 2, "hierophant_ansible" = 1) - whispered = TRUE - object_path = /obj/effect/clockwork/sigil/vitality - creator_message = "A vitality matrix appears below you. It will drain life from non-servants and heal servants that cross it." - usage_tip = "To revive a servant, the sigil must have 20 vitality plus the target servant's non-oxygen damage. It will still heal dead servants if it lacks the vitality to outright revive them." - tier = SCRIPTURE_APPLICATION - one_per_tile = TRUE - sort_priority = 22 - - -/datum/clockwork_scripture/memory_allocation //Memory Allocation: Finds a willing ghost and makes them into a clockwork marauders for the invoker. - descname = "Guardian" - name = "Memory Allocation" - desc = "Allocates part of your consciousness to a Clockwork Marauder, a vigilent fighter that lives within you, able to be \ - called forth by Speaking its True Name or if you become exceptionally low on health.
\ - It gains Fatigue as it is attacked, weakening it. Marauders cannot move too far from their hosts, \ - and will gain Fatigue at an increasing rate as they grow farther away. At maximum Fatigue, the marauder is forced to return to you and will be unable to manifest until its Fatigue is at zero." - invocations = list("Fright's will...", "...call forth...") - channel_time = 100 - required_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "guvax_capacitor" = 3) - consumed_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "guvax_capacitor" = 2) - usage_tip = "Marauders are useful as personal bodyguards and frontline warriors, although they do little damage." - tier = SCRIPTURE_APPLICATION - sort_priority = 23 - -/datum/clockwork_scripture/memory_allocation/check_special_requirements() - for(var/mob/living/simple_animal/hostile/clockwork/marauder/M in living_mob_list) - if(M.host == invoker) - invoker << "You can only house one marauder at a time!" - return 0 - return 1 - -/datum/clockwork_scripture/memory_allocation/scripture_effects() - return create_marauder() - -/datum/clockwork_scripture/memory_allocation/proc/create_marauder() - invoker.visible_message("A yellow 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 process" - 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.Stun(5) - invoker.Weaken(5) - invoker.apply_damage(10, BRUTE, "head") - slab.busy = null - return 0 - clockwork_say(invoker, text2ratvar("...the mind made...")) - invoker.notransform = FALSE - slab.busy = null - if(!check_special_requirements()) - return 0 - invoker << "The tendril shivers slightly as it selects a marauder..." - var/list/marauder_candidates = pollCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 100) - if(!check_special_requirements()) - return 0 - 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 0 - 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.host = invoker - M << M.playstyle_string - M << "Your true name is \"[M.true_name]\". You can change this once by using the Change True Name verb in your Marauder tab." - add_servant_of_ratvar(M, TRUE) - invoker.visible_message("The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!", \ - "The procedure was successful! [M.true_name], a clockwork marauder, has taken up residence in your mind. Communicate with it via the \"Linked Minds\" ability in the \ - Clockwork tab.") - invoker.verbs += /mob/living/proc/talk_with_marauder - return 1 - - - -/datum/clockwork_scripture/create_object/interdiction_lens //Interdiction Lens: Creates a powerful totem that disables radios and cameras and drains power into nearby sigils. - descname = "Structure, Disables Machinery" - name = "Interdiction Lens" - desc = "Creates a clockwork totem that sabotages nearby machinery and funnels drained power into nearby Sigils of Transmission." - invocations = list("May this totem...", "...shroud the false suns!") - channel_time = 80 - required_components = list("belligerent_eye" = 1, "replicant_alloy" = 4, "hierophant_ansible" = 1) - consumed_components = list("belligerent_eye" = 1, "replicant_alloy" = 3, "hierophant_ansible" = 1) - object_path = /obj/structure/destructible/clockwork/powered/interdiction_lens - creator_message = "You form an interdiction lens, which disrupts cameras and radios and drains power." - observer_message = "A brass totem rises from the ground, a purple gem appearing in its center!" - invokers_required = 2 - multiple_invokers_used = TRUE - usage_tip = "If it fails to funnel power into a nearby Sigil of Transmission and fails to disable even one thing, it will disable itself for two minutes." - tier = SCRIPTURE_APPLICATION - one_per_tile = TRUE - sort_priority = 26 - - - -/datum/clockwork_scripture/create_object/mending_motor //Mending Motor: Creates a prism that will quickly heal mechanical servants/clockwork structures and consume replicant alloy. - descname = "Structure, Repairs Other Structures" - name = "Mending Motor" - desc = "Creates a mechanized prism that will rapidly repair damage to clockwork creatures, converted cyborgs, and clockwork structures. Requires replicant alloy or power to function." - invocations = list("May this prism...", "...mend our dents and scratches!") - channel_time = 80 - required_components = list("vanguard_cogwheel" = 4, "guvax_capacitor" = 1, "replicant_alloy" = 1) - consumed_components = list("vanguard_cogwheel" = 3, "guvax_capacitor" = 1, "replicant_alloy" = 1) - object_path = /obj/structure/destructible/clockwork/powered/mending_motor/prefilled - creator_message = "You form a mending motor, which will consume power or replicant alloy to mend the wounds of mechanized servants." - observer_message = "An onyx prism forms in midair and sprouts tendrils to support itself!" - invokers_required = 2 - multiple_invokers_used = TRUE - usage_tip = "Powerful healing but power use is very inefficient, and its alloy use is little better." - tier = SCRIPTURE_APPLICATION - one_per_tile = TRUE - sort_priority = 27 - - - -/datum/clockwork_scripture/create_object/mania_motor //Mania Motor: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk. - descname = "Structure, Area Denial" - name = "Mania Motor" - desc = "Creates a mania motor which will cause brain damage and hallucinations in nearby non-servant humans. It will also try to convert humans directly adjecent to the motor." - invocations = list("May this transmitter...", "...break the will of all who oppose us!") - channel_time = 80 - required_components = list("guvax_capacitor" = 4, "replicant_alloy" = 1, "hierophant_ansible" = 1) - consumed_components = list("guvax_capacitor" = 3, "replicant_alloy" = 1, "hierophant_ansible" = 1) - object_path = /obj/structure/destructible/clockwork/powered/mania_motor - creator_message = "You form a mania motor which will cause brain damage and hallucinations in nearby humans while active." - observer_message = "A two-pronged machine rises from the ground!" - invokers_required = 2 - multiple_invokers_used = TRUE - usage_tip = "Eligible human servants next to the motor will be converted at an additional power cost. It will also cure hallucinations and brain damage in nearby servants." - tier = SCRIPTURE_APPLICATION - one_per_tile = TRUE - sort_priority = 28 - - - -/datum/clockwork_scripture/create_object/tinkerers_daemon //Tinkerer's Daemon: Creates an efficient machine that produces components at a power cost - descname = "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, is 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 - required_components = list("belligerent_eye" = 1, "guvax_capacitor" = 1, "replicant_alloy" = 4) - consumed_components = list("belligerent_eye" = 1, "guvax_capacitor" = 1, "replicant_alloy" = 3) - 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 - sort_priority = 29 - -/datum/clockwork_scripture/create_object/tinkerers_daemon/check_special_requirements() - var/servants = 0 - for(var/mob/living/L in living_mob_list) - if(is_servant_of_ratvar(L)) - servants++ - if(servants * 0.2 < clockwork_daemons) - invoker << "\"Daemons are already disabled, making more of them would be a waste.\"" - return 0 - if(servants * 0.2 < clockwork_daemons+1) - invoker << "\"This daemon would be useless, friend.\"" - return 0 - return ..() - - -/datum/clockwork_scripture/create_object/clockwork_obelisk //Clockwork Obelisk: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk. - descname = "Structure, Teleportation Hub" - name = "Clockwork Obelisk" - desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living servant or clockwork obelisk." - invocations = list("May this obelisk...", "...take us to all places!") - channel_time = 80 - required_components = list("vanguard_cogwheel" = 1, "replicant_alloy" = 1, "hierophant_ansible" = 4) - consumed_components = list("vanguard_cogwheel" = 1, "replicant_alloy" = 1, "hierophant_ansible" = 3) - object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk - creator_message = "You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways." - observer_message = "A brass obelisk appears handing in midair!" - invokers_required = 2 - multiple_invokers_used = TRUE - usage_tip = "Producing a gateway has a high power cost. Gateways to or between clockwork obelisks recieve double duration and uses." - tier = SCRIPTURE_APPLICATION - one_per_tile = TRUE - sort_priority = 30 - - - -////////////// -// REVENANT // -////////////// - -/datum/clockwork_scripture/invoke_nezbere //Invoke Nezbere, the Brass Eidolon: Invokes Nezbere, bolstering the strength of many clockwork items for one minute. - descname = "Structure Buff" - name = "Invoke Nezbere, the Brass Eidolon" - desc = "Taps the limitless power of Nezbere, one of Ratvar's four generals. The restless toil of the Eidolon will empower a wide variety of clockwork apparatus for a full minute - notably, \ - clockwork proselytizers will cost no replicant alloy to use." - invocations = list("I call upon you, Armorer!!", "Let your machinations reign on this miserable station!!", "Let your power flow through the tools of your master!!") - channel_time = 150 - required_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 6) - consumed_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 6) - usage_tip = "Ocular wardens will become empowered, clockwork proselytizers will require no alloy, tinkerer's daemons will produce twice as quickly, \ - and interdiction lenses, mending motors, mania motors, tinkerer's daemons, and clockwork obelisks will all require no power." - tier = SCRIPTURE_REVENANT - sort_priority = 33 - invokers_required = 3 - multiple_invokers_used = TRUE - -/datum/clockwork_scripture/invoke_nezbere/check_special_requirements() - if(!slab.no_cost && clockwork_generals_invoked["nezbere"] > world.time) - invoker << "\"[text2ratvar("Not just yet, friend. Patience is a virtue.")]\"\n\ - Nezbere has already been invoked recently! You must wait several minutes before calling upon the Brass Eidolon." - return 0 - if(!slab.no_cost && ratvar_awakens) - invoker << "\"[text2ratvar("Our master is here already. You do not require my help, friend.")]\"\n\ - Nezbere will not grant his power while Ratvar's dwarfs his own!" - return 0 - return 1 - -/datum/clockwork_scripture/invoke_nezbere/scripture_effects() - new/obj/effect/clockwork/general_marker/nezbere(get_turf(invoker)) - hierophant_message("[text2ratvar("Armorer: \"I heed your call, champions. May your artifacts bring ruin upon the heathens that oppose our master!")]\"", FALSE, invoker) - clockwork_generals_invoked["nezbere"] = world.time + CLOCKWORK_GENERAL_COOLDOWN - playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) - for(var/obj/structure/destructible/clockwork/ocular_warden/W in all_clockwork_objects) //Ocular wardens have increased damage and radius - W.damage_per_tick *= 1.5 - W.sight_range *= 2 - for(var/obj/item/clockwork/clockwork_proselytizer/P in all_clockwork_objects) //Proselytizers no longer require alloy - P.uses_alloy = FALSE - for(var/obj/structure/destructible/clockwork/powered/M in all_clockwork_objects) //Powered clockwork structures no longer need power - M.needs_power = FALSE - if(istype(M, /obj/structure/destructible/clockwork/powered/tinkerers_daemon)) //Daemons produce components twice as quickly - var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = M - D.production_time *= 0.5 - spawn(600) - for(var/obj/structure/destructible/clockwork/ocular_warden/W in all_clockwork_objects) - W.damage_per_tick = initial(W.damage_per_tick) - W.sight_range = initial(W.sight_range) - for(var/obj/item/clockwork/clockwork_proselytizer/P in all_clockwork_objects) - P.uses_alloy = initial(P.uses_alloy) - for(var/obj/structure/destructible/clockwork/powered/M in all_clockwork_objects) - M.needs_power = initial(M.needs_power) - if(istype(M, /obj/structure/destructible/clockwork/powered/tinkerers_daemon)) - var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = M - D.production_time = initial(D.production_time) - return 1 - - - -/datum/clockwork_scripture/invoke_sevtug //Invoke Sevtug, the Formless Pariah: Causes massive global hallucinations, braindamage, confusion, and dizziness to all humans on the same zlevel. - descname = "Global Hallucination" - name = "Invoke Sevtug, the Formless Pariah" - desc = "Taps the limitless power of Sevtug, one of Ratvar's four generals. The mental manipulation ability of the Pariah allows its wielder to cause mass hallucinations and confusion \ - for all non-servant humans on the same z-level as them. The power of this scripture falls off somewhat with distance, and certain things may reduce its effects." - invocations = list("I call upon you, Fright!!", "Let your power shatter the sanity of the weak-minded!!", "Let your tendrils hold sway over all!!") - channel_time = 150 - required_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 6, "hierophant_ansible" = 3) - consumed_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 6, "hierophant_ansible" = 3) - usage_tip = "Causes brain damage, hallucinations, confusion, and dizziness in massive amounts." - tier = SCRIPTURE_REVENANT - sort_priority = 32 - invokers_required = 3 - multiple_invokers_used = TRUE - var/list/mindbreaksayings = list("\"Oh, great. I get to shatter some minds.\"", "\"More minds to crush.\"", \ - "\"Really, this is almost boring.\"", "\"None of these minds have anything interesting in them.\"", "\"Maybe I can instill a little bit of terror in this one.\"", \ - "\"What a waste of my power.\"", "\"I'm sure I could just control these minds instead, but they never ask.\"") - -/datum/clockwork_scripture/invoke_sevtug/check_special_requirements() - if(!slab.no_cost && clockwork_generals_invoked["sevtug"] > world.time) - invoker << "\"[text2ratvar("Is it really so hard - even for a simpleton like you - to grasp the concept of waiting?")]\"\n\ - Sevtug has already been invoked recently! You must wait several minutes before calling upon the Formless Pariah." - return 0 - if(!slab.no_cost && ratvar_awakens) - invoker << "\"[text2ratvar("Do you really think anything I can do right now will compare to Engine's power?")]\"\n\ - Sevtug will not grant his power while Ratvar's dwarfs his own!" - return 0 - return ..() - -/datum/clockwork_scripture/invoke_sevtug/scripture_effects() - new/obj/effect/clockwork/general_marker/sevtug(get_turf(invoker)) - hierophant_message("[text2ratvar("Fright: \"I heed your call, idiots. Get going and use this chance while it lasts!")]\"", FALSE, invoker) - clockwork_generals_invoked["sevtug"] = world.time + CLOCKWORK_GENERAL_COOLDOWN - playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) - var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected - var/turf/T = get_turf(invoker) - for(var/mob/living/carbon/human/H in living_mob_list) - if(H.z == invoker.z && !is_servant_of_ratvar(H)) - var/distance = 0 - distance += get_dist(T, get_turf(H)) - var/messaged = FALSE - var/visualsdistance = max(150 - distance, 5) - var/minordistance = max(200 - distance*2, 5) - var/majordistance = max(150 - distance*3, 5) - if(H.null_rod_check()) - visualsdistance = round(visualsdistance * 0.25) - minordistance = round(minordistance * 0.25) - majordistance = round(majordistance * 0.25) - H << "[text2ratvar("Oh, a void weapon. How annoying, I may as well not bother.")]\n\ - Your holy weapon glows a faint orange in an attempt to defend your mind!" - messaged = TRUE - if(H.isloyal()) - visualsdistance = round(visualsdistance * 0.5) //half effect for shielded targets - minordistance = round(minordistance * 0.5) - majordistance = round(majordistance * 0.5) - if(!messaged) - H << "[text2ratvar("Oh, look, a mindshield. Cute, I suppose I'll humor it.")]" - messaged = TRUE - if(!messaged && prob(visualsdistance)) - H << "[text2ratvar(pick(mindbreaksayings))]" - H.playsound_local(T, hum, visualsdistance, 1) - flash_color(H, flash_color="#AF0AAF", flash_time=visualsdistance*10) - H.set_drugginess(visualsdistance + H.druggy) - H.dizziness = minordistance + H.dizziness - H.hallucination = minordistance + H.hallucination - H.confused = majordistance + H.confused - H.setBrainLoss(majordistance + H.getBrainLoss()) - return 1 - - - -/datum/clockwork_scripture/invoke_nzcrentr //Invoke Nzcrentr, the Eternal Thunderbolt: Imbues an immense amount of energy into the invoker. After several seconds, everyone nearby will be hit with a devastating chain lightning blast. - descname = "Lightning Blast" - name = "Invoke Nzcrentr, the Eternal Thunderbolt" - desc = "Taps the limitless power of Nzcrentr, one of Ratvar's four generals. The immense energy Nzcrentr wields will allow you to imbue a tiny fraction of it into your body. After several \ - seconds, anyone nearby will be struck by a devastating lightning bolt." - invocations = list("I call upon you, Amperage!!", "Let your energy flow through me!!", "Let your boundless power shatter stars!!") - channel_time = 150 - required_components = list("belligerent_eye" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 6) - consumed_components = list("belligerent_eye" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 6) - usage_tip = "Struck targets will also be knocked down for about sixteen seconds." - tier = SCRIPTURE_REVENANT - sort_priority = 34 - -/datum/clockwork_scripture/invoke_nzcrentr/check_special_requirements() - if(!slab.no_cost && clockwork_generals_invoked["nzcrentr"] > world.time) - invoker << "\"[text2ratvar("The boss says you have to wait. Hey, do you think he would mind if I killed you? ...He would? Ok.")]\"\n\ - Nzcrentr has already been invoked recently! You must wait several minutes before calling upon the Forgotten Arbiter." - return 0 - return 1 - -/datum/clockwork_scripture/invoke_nzcrentr/scripture_effects() - new/obj/effect/clockwork/general_marker/nzcrentr(get_turf(invoker)) - clockwork_generals_invoked["nzcrentr"] = world.time + CLOCKWORK_GENERAL_COOLDOWN - hierophant_message("[text2ratvar("Amperage: \"[invoker.real_name] has called forth my power. Hope they do not shatter under it!")]\"", FALSE, invoker) - invoker.visible_message("[invoker] begins to radiate a blinding light!", \ - "\"[text2ratvar("The boss says it's okay to do this. Don't blame me if you die from it.")]\"\n \ - You feel limitless power surging through you!") - playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) - playsound(invoker, 'sound/magic/lightning_chargeup.ogg', 100, 0) - animate(invoker, color = list(rgb(255, 255, 255), rgb(255, 255, 255), rgb(255, 255, 255), rgb(0,0,0)), time = 88) //Gradual advancement to extreme brightness - sleep(88) - if(invoker) - invoker.visible_message("Massive bolts of energy emerge from across [invoker]'s body!", \ - "\"[text2ratvar("I told you you wouldn't be able to handle it.")]\"\n \ - TOO... MUCH! CAN'T... TAKE IT!") - playsound(invoker, 'sound/magic/lightningbolt.ogg', 100, 0) - if(invoker.stat == CONSCIOUS) - animate(invoker, color = initial(invoker.color), time = 10) - for(var/mob/living/L in view(7, invoker)) - if(is_servant_of_ratvar(L)) - continue - invoker.Beam(L, icon_state = "nzcrentrs_power", time = 10) - var/randdamage = rand(40, 60) - if(iscarbon(L)) - L.electrocute_act(randdamage, "Nzcrentr's power", 1, randdamage) - else - L.adjustFireLoss(randdamage) - L.visible_message( - "[L] was shocked by Nzcrentr's power!", \ - "You feel a powerful shock coursing through your body!", \ - "You hear a heavy electrical crack." \ - ) - L.Weaken(8) - playsound(L, 'sound/magic/LightningShock.ogg', 50, 1) - else - playsound(invoker, 'sound/magic/Disintegrate.ogg', 50, 1) - invoker.gib() - return 1 - else - return 0 - - - -/datum/clockwork_scripture/invoke_inathneq //Invoke Inath-neq, the Resonant Cogwheel: Grants invulnerability and stun immunity for 15 seconds - descname = "Area Invuln" - name = "Invoke Inath-neq, the Resonant Cogwheel" - desc = "Taps the limitless power of Inath-neq, one of Ratvar's four generals. The benevolence of Inath-Neq will grant complete invulnerability to all servants in range for fifteen seconds." - invocations = list("I call upon you, Vanguard!!", "Let the Resonant Cogs turn once more!!", "Grant me and my allies the strength to vanquish our foes!!") - channel_time = 150 - required_components = list("vanguard_cogwheel" = 6, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 3) - consumed_components = list("vanguard_cogwheel" = 6, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 3) - usage_tip = "Those affected by this scripture are only weak to things that outright destroy bodies, such as bombs or the singularity." - tier = SCRIPTURE_REVENANT - sort_priority = 31 - var/total_duration = 150 - -/datum/clockwork_scripture/invoke_inathneq/check_special_requirements() - if(!slab.no_cost && clockwork_generals_invoked["inath-neq"] > world.time) - invoker << "\"[text2ratvar("I cannot lend you my aid yet, champion. Please be careful.")]\"\n\ - Inath-neq has already been invoked recently! You must wait several minutes before calling upon the Resonant Cogwheel." - return 0 - return 1 - -/datum/clockwork_scripture/invoke_inathneq/scripture_effects() - new/obj/effect/clockwork/general_marker/inathneq(get_turf(invoker)) - hierophant_message("[text2ratvar("Vanguard: \"I lend you my aid, champions! Let glory guide your blows!")]\"", FALSE, invoker) - clockwork_generals_invoked["inath-neq"] = world.time + CLOCKWORK_GENERAL_COOLDOWN - playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) - if(invoker.real_name == "Lucio") - clockwork_say(invoker, text2ratvar("Aww, let's break it DOWN!!")) - for(var/mob/living/L in range(7, invoker)) - if(!is_servant_of_ratvar(L) || L.stat == DEAD) - continue - L.apply_status_effect(STATUS_EFFECT_INATHNEQS_ENDOWMENT) - return 1 - - - -/datum/clockwork_scripture/ark_of_the_clockwork_justiciar //Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict. - descname = "Win Condition" - name = "Ark of the Clockwork Justiciar" - desc = "Pulls from the power of all of Ratvar's servants and generals to construct a massive machine used to tear apart a rift in spacetime to the Celestial Derelict. This gateway will \ - call forth Ratvar from his exile after some time." - 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 - required_components = list("belligerent_eye" = 10, "vanguard_cogwheel" = 10, "guvax_capacitor" = 10, "replicant_alloy" = 10, "hierophant_ansible" = 10) - consumed_components = list("belligerent_eye" = 10, "vanguard_cogwheel" = 10, "guvax_capacitor" = 10, "replicant_alloy" = 10, "hierophant_ansible" = 10) - invokers_required = 5 - multiple_invokers_used = TRUE - 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 = 35 - -/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/New() - if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY) - invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \ - "THIS STATION WILL BE A BEACON OF HOPE IN THE DARKNESS OF SPACE!!", \ - "HELP US MAKE THIS SHOW ENGINE'S GLORY!!") - ..() - -/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/check_special_requirements() - if(!slab.no_cost) - if(ratvar_awakens) - invoker << "\"I am already here, idiot.\"" - return 0 - for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in all_clockwork_objects) - var/area/gate_area = get_area(G) - invoker << "There is already a gateway at [gate_area.map_name]!" - return 0 - var/area/A = get_area(invoker) - var/turf/T = get_turf(invoker) - if(!T || T.z != ZLEVEL_STATION || istype(A, /area/shuttle)) - invoker << "You must be on the station to activate the Ark!" - return 0 - if(clockwork_gateway_activated) - if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY) - invoker << "\"Look upon his works. Is it not glorious?\"" - else - invoker << "Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!" - return 0 - return 1 - -/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/scripture_effects() - var/turf/T = get_turf(invoker) - new/obj/effect/clockwork/general_marker/inathneq(T) - if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY) - T.visible_message("\"[text2ratvar("Engine, come forth and show your servants your mercy!")]\"") - else - T.visible_message("\"[text2ratvar("We will show all the mercy of Engine!")]\"") - playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 30, 0) - sleep(10) - if(!check_special_requirements()) - return 0 - new/obj/effect/clockwork/general_marker/sevtug(T) - if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY) - T.visible_message("\"[text2ratvar("Engine, come forth and show this station your decorating skills!")]\"") - else - T.visible_message("\"[text2ratvar("We will show all Engine's decorating skills.")]\"") - playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 45, 0) - sleep(10) - if(!check_special_requirements()) - return 0 - new/obj/effect/clockwork/general_marker/nezbere(T) - if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY) - T.visible_message("\"[text2ratvar("Engine, come forth and shine your light across this realm!!")]\"") - else - T.visible_message("\"[text2ratvar("We will show all Engine's light!!")]\"") - playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 60, 0) - sleep(10) - if(!check_special_requirements()) - return 0 - new/obj/effect/clockwork/general_marker/nzcrentr(T) - if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY) - T.visible_message("\"[text2ratvar("Engine, come forth.")]\"") - else - T.visible_message("\"[text2ratvar("We will show all Engine's power!")]\"") - playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 75, 0) - sleep(10) - if(check_special_requirements()) - var/obj/structure/destructible/clockwork/massive/celestial_gateway/CG = new/obj/structure/destructible/clockwork/massive/celestial_gateway(T) - if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY) - CG.ratvar_portal = FALSE - hierophant_message("This newly constructed gateway will not free Ratvar, \ - and will instead simply proselytize and convert everything and everyone on the station.", TRUE) - playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 100, 0) - var/list/open_turfs = list() - for(var/turf/open/OT in orange(1, T)) - var/list/dense_objects = list() - for(var/obj/O in OT) - if(O.density && !O.CanPass(invoker, OT, 5)) - dense_objects |= O - if(!dense_objects.len) - open_turfs |= OT - if(open_turfs.len) - for(var/mob/living/L in T) - L.forceMove(pick(open_turfs)) //shove living mobs off of the gate's new location - return 1 - return 0 + return TRUE diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm new file mode 100644 index 00000000000..42d3572a644 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm @@ -0,0 +1,257 @@ +////////////////// +// APPLICATIONS // +////////////////// + +//Sigil of Accession: Creates a sigil of accession, which is like a sigil of submission, but can convert any number of non-implanted targets and up to one implanted target. +/datum/clockwork_scripture/create_object/sigil_of_accession + descname = "Permenant Conversion Trap" + name = "Sigil of Accession" + desc = "Places a luminous sigil much like a Sigil of Submission, but it will remain even after successfully converting a non-implanted target. \ + It will penetrate mindshield implants once before disappearing." + invocations = list("Divinity, enslave...", "...all who trespass here!") + channel_time = 70 + required_components = list("belligerent_eye" = 3, "guvax_capacitor" = 1, "hierophant_ansible" = 1) + consumed_components = list("belligerent_eye" = 2, "guvax_capacitor" = 1, "hierophant_ansible" = 1) + whispered = TRUE + object_path = /obj/effect/clockwork/sigil/submission/accession + prevent_path = /obj/effect/clockwork/sigil/submission + creator_message = "A luminous sigil appears below you. All non-servants to cross it will be enslaved after a brief time if they do not move." + usage_tip = "It will remain after converting a target, unless that target has a mindshield implant, which it will break to convert them, but consume itself in the process." + tier = SCRIPTURE_APPLICATION + one_per_tile = TRUE + sort_priority = 1 + + +//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants. +/datum/clockwork_scripture/create_object/vitality_matrix + descname = "Damage Trap" + name = "Vitality Matrix" + desc = "Scribes a sigil beneath the invoker which drains life from any living non-servants that cross it. Servants that cross it, however, will be healed based on how much it drained from non-servants. \ + Dead servants can be revived by this sigil if it has enough stored vitality." + invocations = list("Divinity...", "...steal their life...", "...for these shells!") + channel_time = 70 + required_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 3, "hierophant_ansible" = 1) + consumed_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 2, "hierophant_ansible" = 1) + whispered = TRUE + object_path = /obj/effect/clockwork/sigil/vitality + creator_message = "A vitality matrix appears below you. It will drain life from non-servants and heal servants that cross it." + usage_tip = "To revive a servant, the sigil must have 20 vitality plus the target servant's non-oxygen damage. It will still heal dead servants if it lacks the vitality to outright revive them." + tier = SCRIPTURE_APPLICATION + one_per_tile = TRUE + sort_priority = 2 + + +//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 vigilent fighter that lives within you, able to be \ + called forth by Speaking its True Name or if you become exceptionally low on health.
\ + It gains Fatigue as it is attacked, weakening it. Marauders cannot move too far from their hosts, \ + and will gain Fatigue at an increasing rate as they grow farther away. At maximum Fatigue, the marauder is forced to return to you and will be unable to manifest until its Fatigue is at zero." + invocations = list("Fright's will...", "...call forth...") + channel_time = 100 + required_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "guvax_capacitor" = 3) + consumed_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "guvax_capacitor" = 2) + usage_tip = "Marauders are useful as personal bodyguards and frontline warriors, although they do little damage." + tier = SCRIPTURE_APPLICATION + sort_priority = 3 + +/datum/clockwork_scripture/memory_allocation/check_special_requirements() + for(var/mob/living/simple_animal/hostile/clockwork/marauder/M in living_mob_list) + if(M.host == invoker) + 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 yellow 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 process" + 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.Stun(5) + invoker.Weaken(5) + invoker.apply_damage(10, BRUTE, "head") + slab.busy = null + return FALSE + clockwork_say(invoker, text2ratvar("...the mind made...")) + invoker.notransform = FALSE + slab.busy = null + if(!check_special_requirements()) + return FALSE + invoker << "The tendril shivers slightly as it selects a marauder..." + var/list/marauder_candidates = pollCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 100) + 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.host = invoker + M << M.playstyle_string + M << "Your true name is \"[M.true_name]\". You can change this once by using the Change True Name verb in your Marauder tab." + add_servant_of_ratvar(M, TRUE) + invoker.visible_message("The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!", \ + "The procedure was successful! [M.true_name], a clockwork marauder, has taken up residence in your mind. Communicate with it via the \"Linked Minds\" ability in the \ + Clockwork tab.") + invoker.verbs += /mob/living/proc/talk_with_marauder + return TRUE + + +//Anima Fragment: Creates an empty anima fragment, which produces an anima fragment that moves at extreme speed and does high damage. +/datum/clockwork_scripture/create_object/anima_fragment + descname = "Fast Soul Vessel Shell" + name = "Anima Fragment" + desc = "Creates a large shell fitted for soul vessels. Adding an active soul vessel to it results in a powerful construct with decent health, notable melee power, \ + and exceptional speed, though taking damage will temporarily slow it down." + invocations = list("Call forth...", "...the soldiers of Armorer.") + channel_time = 80 + required_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "replicant_alloy" = 3) + consumed_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "replicant_alloy" = 2) + object_path = /obj/structure/destructible/clockwork/shell/fragment + creator_message = "You form an anima fragment, a powerful soul vessel receptable." + observer_message = "The slab disgorges a puddle of black metal that expands and forms into a strange shell!" + usage_tip = "Useless without a soul vessel and should not be created without one." + tier = SCRIPTURE_APPLICATION + sort_priority = 4 + + +//Sigil of Transmission: Creates a sigil of transmission that can store power for clockwork structures. +/datum/clockwork_scripture/create_object/sigil_of_transmission + descname = "Structure Battery" + name = "Sigil of Transmission" + desc = "Scribes a sigil beneath the invoker which stores power to power clockwork structures." + invocations = list("Divinity...", "...power our creations!") + channel_time = 70 + required_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 1, "hierophant_ansible" = 3) + consumed_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 1, "hierophant_ansible" = 2) + whispered = TRUE + object_path = /obj/effect/clockwork/sigil/transmission + creator_message = "A sigil silently appears below you. It will automatically power clockwork structures adjecent to it." + usage_tip = "Can be recharged by using Volt Void while standing on it." + tier = SCRIPTURE_APPLICATION + one_per_tile = TRUE + sort_priority = 5 + + +//Interdiction Lens: Creates a powerful totem that disables radios and cameras and drains power into nearby sigils of transmission. +/datum/clockwork_scripture/create_object/interdiction_lens + descname = "Structure, Disables Machinery" + name = "Interdiction Lens" + desc = "Creates a clockwork totem that sabotages nearby machinery and funnels drained power into nearby Sigils of Transmission." + invocations = list("May this totem...", "...shroud the false suns!") + channel_time = 80 + required_components = list("belligerent_eye" = 4, "replicant_alloy" = 1, "hierophant_ansible" = 1) + consumed_components = list("belligerent_eye" = 3, "replicant_alloy" = 1, "hierophant_ansible" = 1) + object_path = /obj/structure/destructible/clockwork/powered/interdiction_lens + creator_message = "You form an interdiction lens, which disrupts cameras and radios and drains power." + observer_message = "A brass totem rises from the ground, a purple gem appearing in its center!" + invokers_required = 2 + multiple_invokers_used = TRUE + usage_tip = "If it fails to funnel power into a nearby Sigil of Transmission and fails to disable even one thing, it will disable itself for two minutes." + tier = SCRIPTURE_APPLICATION + one_per_tile = TRUE + sort_priority = 6 + + +//Mending Motor: Creates a prism that will quickly heal mechanical servants/clockwork structures and consume power or replicant alloy. +/datum/clockwork_scripture/create_object/mending_motor + descname = "Structure, Repairs Other Structures" + name = "Mending Motor" + desc = "Creates a mechanized prism that will rapidly repair damage to clockwork creatures, converted cyborgs, and clockwork structures. Requires replicant alloy or power to function." + invocations = list("May this prism...", "...mend our dents and scratches!") + channel_time = 80 + required_components = list("vanguard_cogwheel" = 4, "guvax_capacitor" = 1, "replicant_alloy" = 1) + consumed_components = list("vanguard_cogwheel" = 3, "guvax_capacitor" = 1, "replicant_alloy" = 1) + object_path = /obj/structure/destructible/clockwork/powered/mending_motor/prefilled + creator_message = "You form a mending motor, which will consume power or replicant alloy to mend the wounds of mechanized servants." + observer_message = "An onyx prism forms in midair and sprouts tendrils to support itself!" + invokers_required = 2 + multiple_invokers_used = TRUE + usage_tip = "Powerful healing but power use is very inefficient, and its alloy use is little better." + tier = SCRIPTURE_APPLICATION + one_per_tile = TRUE + sort_priority = 7 + + +//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 + descname = "Structure, Area Denial" + name = "Mania Motor" + desc = "Creates a mania motor which will cause brain damage and hallucinations in nearby non-servant humans. It will also try to convert humans directly adjecent to the motor." + invocations = list("May this transmitter...", "...break the will of all who oppose us!") + channel_time = 80 + required_components = list("guvax_capacitor" = 4, "replicant_alloy" = 1, "hierophant_ansible" = 1) + consumed_components = list("guvax_capacitor" = 3, "replicant_alloy" = 1, "hierophant_ansible" = 1) + object_path = /obj/structure/destructible/clockwork/powered/mania_motor + creator_message = "You form a mania motor which will cause brain damage and hallucinations in nearby humans while active." + observer_message = "A two-pronged machine rises from the ground!" + invokers_required = 2 + multiple_invokers_used = TRUE + usage_tip = "Eligible human servants next to the motor will be converted at an additional power cost. It will also cure hallucinations and brain damage in nearby servants." + tier = SCRIPTURE_APPLICATION + one_per_tile = TRUE + sort_priority = 8 + + +//Tinkerer's Daemon: Creates an efficient machine that rapidly produces components at a power cost. +/datum/clockwork_scripture/create_object/tinkerers_daemon + descname = "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, is 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 + required_components = list("belligerent_eye" = 1, "guvax_capacitor" = 1, "replicant_alloy" = 4) + consumed_components = list("belligerent_eye" = 1, "guvax_capacitor" = 1, "replicant_alloy" = 3) + 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 + sort_priority = 9 + +/datum/clockwork_scripture/create_object/tinkerers_daemon/check_special_requirements() + var/servants = 0 + for(var/mob/living/L in living_mob_list) + if(is_servant_of_ratvar(L)) + servants++ + if(servants * 0.2 < clockwork_daemons) + invoker << "\"Daemons are already disabled, making more of them would be a waste.\"" + return FALSE + if(servants * 0.2 < clockwork_daemons+1) + invoker << "\"This daemon would be useless, friend.\"" + return FALSE + return ..() + + +//Clockwork Obelisk: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk at a power cost. +/datum/clockwork_scripture/create_object/clockwork_obelisk + descname = "Structure, Teleportation Hub" + name = "Clockwork Obelisk" + desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living servant or clockwork obelisk." + invocations = list("May this obelisk...", "...take us to all places!") + channel_time = 80 + required_components = list("vanguard_cogwheel" = 1, "replicant_alloy" = 1, "hierophant_ansible" = 4) + consumed_components = list("vanguard_cogwheel" = 1, "replicant_alloy" = 1, "hierophant_ansible" = 3) + object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk + creator_message = "You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways." + observer_message = "A brass obelisk appears handing in midair!" + invokers_required = 2 + multiple_invokers_used = TRUE + usage_tip = "Producing a gateway has a high power cost. Gateways to or between clockwork obelisks recieve double duration and uses." + tier = SCRIPTURE_APPLICATION + one_per_tile = TRUE + sort_priority = 10 diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_drivers.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_drivers.dm new file mode 100644 index 00000000000..18bfef9612b --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_drivers.dm @@ -0,0 +1,279 @@ +///////////// +// DRIVERS // +///////////// + +//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 + required_components = list("belligerent_eye" = 1) + usage_tip = "Useful for crowd control in a populated area and disrupting mass movement." + tier = SCRIPTURE_DRIVER + sort_priority = 1 + var/noncultist_damage = 2 //damage per chant to noncultists + var/cultist_damage = 8 //damage per chant to non-walking cultists + +/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number) + for(var/mob/living/carbon/C in hearers(7, invoker)) + var/number_legs = C.get_num_legs() + if(!is_servant_of_ratvar(C) && !C.null_rod_check() && number_legs) //you have legs right + C.apply_damage(noncultist_damage * 0.5, BURN, "l_leg") + C.apply_damage(noncultist_damage * 0.5, BURN, "r_leg") + if(C.m_intent != "walk") + if(!iscultist(C)) + C << "Your leg[number_legs > 1 ? "s shiver":" shivers"] with pain!" + else //Cultists take extra burn damage + C << "Your leg[number_legs > 1 ? "s burn":" burns"] with pain!" + C.apply_damage(cultist_damage * 0.5, BURN, "l_leg") + C.apply_damage(cultist_damage * 0.5, BURN, "r_leg") + C.m_intent = "walk" + + +//Judicial Visor: Creates a judicial visor, which can smite an area. +/datum/clockwork_scripture/create_object/judicial_visor + descname = "Delayed Area Stun Glasses" + name = "Judicial Visor" + desc = "Forms a visor that, when worn, will grant the ability to smite an area, stunning, muting, and damaging the nonfaithful. \ + Cultists of Nar-Sie will be set on fire, though they will be stunned for half the time." + invocations = list("Grant me the flames of Engine!") + channel_time = 10 + required_components = list("belligerent_eye" = 2) + consumed_components = list("belligerent_eye" = 1) + whispered = TRUE + object_path = /obj/item/clothing/glasses/judicial_visor + creator_message = "You form a judicial visor, which is capable of smiting the unworthy." + usage_tip = "The visor has a thirty-second cooldown once used, and the marker it creates has a delay of 3 seconds before exploding." + tier = SCRIPTURE_DRIVER + space_allowed = TRUE + sort_priority = 2 + + +//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker. +/datum/clockwork_scripture/vanguard + descname = "Self Stun Immunity" + name = "Vanguard" + desc = "Provides twenty seconds of stun immunity. At the end of the twenty seconds, the invoker is stunned for the equivalent of 25% of all stuns they absorbed. \ + Excessive absorption will cause unconsciousness." + invocations = list("Shield me...", "...from darkness!") + channel_time = 30 + required_components = list("vanguard_cogwheel" = 1) + usage_tip = "You cannot reactivate Vanguard while still shielded by it." + tier = SCRIPTURE_DRIVER + sort_priority = 3 + +/datum/clockwork_scripture/vanguard/check_special_requirements() + if(islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time) + invoker << "You are already shielded by a Vanguard!" + return FALSE + return TRUE + +/datum/clockwork_scripture/vanguard/scripture_effects() + invoker.apply_status_effect(STATUS_EFFECT_VANGUARD) + return TRUE + + +//Sentinel's Compromise: Allows the invoker to select a nearby servant convert their brute and burn damage into half as much toxin damage. +/datum/clockwork_scripture/sentinels_compromise + descname = "Convert Brute/Burn to Half Toxin" + name = "Sentinel's Compromise" + desc = "Heals all brute and burn damage on a nearby living, friendly servant, but deals 50% of the damage they had as toxin damage." + invocations = list("Mend the wounds of...", "...my inferior flesh.") + channel_time = 30 + required_components = list("vanguard_cogwheel" = 2) + consumed_components = list("vanguard_cogwheel" = 1) + usage_tip = "The Compromise is very fast to invoke." + tier = SCRIPTURE_DRIVER + sort_priority = 4 + +/datum/clockwork_scripture/sentinels_compromise/scripture_effects() + var/list/nearby_cultists = list() + for(var/mob/living/C in range(7, invoker)) + if(C.stat != DEAD && is_servant_of_ratvar(C) && (C.getBruteLoss() || C.getFireLoss())) + nearby_cultists += C + if(!nearby_cultists.len) + invoker << "There are no eligible servants nearby!" + return FALSE + var/mob/living/L = input(invoker, "Choose a fellow servant to heal.", name) as null|anything in nearby_cultists + if(!L || !invoker || !slab || qdeleted(slab) || !invoker.canUseTopic(slab) || !invoker.get_active_held_item() != slab || L.stat == DEAD) + return FALSE + var/brutedamage = L.getBruteLoss() + var/burndamage = L.getFireLoss() + var/totaldamage = brutedamage + burndamage + if(!totaldamage) + invoker << "[L] is not burned or bruised!" + return FALSE + L.adjustToxLoss(totaldamage * 0.5) + L.adjustBruteLoss(-brutedamage) + L.adjustFireLoss(-burndamage) + var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20 + var/targetturf = get_turf(L) + for(var/i in 1 to healseverity) + PoolOrNew(/obj/effect/overlay/temp/heal, list(targetturf, "#1E8CE1")) + invoker << "You bathe [L] in Inath-neq's power!" + L.visible_message("A blue light washes over [L], mending [L.p_their()] bruises and burns!", \ + "You feel Inath-neq's power healing your wounds, but a deep nausea overcomes you!") + playsound(targetturf, 'sound/magic/Staff_Healing.ogg', 50, 1) + return TRUE + + +//Guvax: Converts anyone adjacent to the invoker after completion, but gets gradually slower as the cult gets more dominant. +/datum/clockwork_scripture/guvax + descname = "Melee Area Convert" + name = "Guvax" + desc = "Enlists all nearby living unshielded creatures into servitude to Ratvar. Also purges holy water from nearby Servants." + invocations = list("Enlighten this heathen!", "All are insects before Engine!", "Purge all untruths and honor Engine.") + channel_time = 50 + required_components = list("guvax_capacitor" = 1) + usage_tip = "Only works on those in melee range and does not penetrate mindshield implants. Much more efficient than a Sigil of Submission at low Servant amounts." + tier = SCRIPTURE_DRIVER + sort_priority = 5 + +/datum/clockwork_scripture/guvax/run_scripture() + var/servants = 0 + for(var/mob/living/M in living_mob_list) + if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M))) + servants++ + if(servants > 5) + servants -= 5 + channel_time = min(channel_time + servants*10, 200) //if above 5 servants, is much slower + return ..() + +/datum/clockwork_scripture/guvax/scripture_effects() + for(var/mob/living/L in hearers(1, get_turf(invoker))) //Affects silicons + if(!is_servant_of_ratvar(L)) + if(L.stat != DEAD) + add_servant_of_ratvar(L) + else + if(L.reagents && L.reagents.has_reagent("holywater")) + L.reagents.remove_reagent("holywater", 1000) + L << "Ratvar's light flares, banishing the darkness. Your devotion remains intact!" + return TRUE + + +//Taunting Tirade: Channeled for up to five times over thirty seconds. Confuses non-servants that can hear it and allows movement for a brief time after each chant. +/datum/clockwork_scripture/channeled/taunting_tirade + descname = "Channeled, Mobile Area Confusion" + name = "Taunting Tirade" + desc = "Weakens, confuses and dizzies all nearby non-servants with a short invocation, then allows movement for five seconds. Chanted every second for up to thirty seconds." + chant_invocations = list("Hostiles on my back!", "Enemies on my trail!", "Gonna try and shake my tail.", "Bogeys on my six!") + chant_amount = 5 + chant_interval = 10 + required_components = list("guvax_capacitor" = 2) + consumed_components = list("guvax_capacitor" = 1) + usage_tip = "Useful for fleeing attackers, as few will be able to follow someone using this scripture." + tier = SCRIPTURE_DRIVER + sort_priority = 6 + var/flee_time = 47 //allow fleeing for 5 seconds + var/grace_period = 3 //very short grace period so you don't have to stop immediately + var/datum/progressbar/progbar + +/datum/clockwork_scripture/channeled/taunting_tirade/chant_effects(chant_number) + for(var/mob/living/L in hearers(7, invoker)) + if(!is_servant_of_ratvar(L) && !L.null_rod_check()) + L.confused = min(L.confused + 20, 100) + L.dizziness = min(L.dizziness + 20, 100) + L.Weaken(1) + invoker.visible_message("[invoker] is suddenly covered with a thin layer of dark purple smoke!") + invoker.color = "#AF0AAF" + animate(invoker, color = initial(invoker.color), time = flee_time+grace_period) + if(chant_number != chant_amount) //if this is the last chant, we don't have a movement period because the chant is over + var/endtime = world.time + flee_time + var/starttime = world.time + progbar = new(invoker, flee_time, invoker) + progbar.bar.color = "#AF0AAF" + animate(progbar.bar, color = initial(progbar.bar.color), time = flee_time+grace_period) + while(world.time < endtime) + sleep(1) + progbar.update(world.time - starttime) + qdel(progbar) + sleep(grace_period) + +/datum/clockwork_scripture/channeled/taunting_tirade/chant_end_effects() + qdel(progbar) + + +//Replicant: Creates a new clockwork slab. Doesn't use create_object because of its unique behavior. +/datum/clockwork_scripture/replicant + descname = "New Clockwork Slab" + name = "Replicant" + desc = "Creates a new clockwork slab." + invocations = list("Metal, become greater!") + channel_time = 10 + required_components = list("replicant_alloy" = 1) + whispered = TRUE + usage_tip = "This is inefficient as a way to produce components, as the slab produced must be held by someone with no other slabs to produce components." + tier = SCRIPTURE_DRIVER + sort_priority = 7 + +/datum/clockwork_scripture/replicant/scripture_effects() + invoker << "You copy a piece of replicant alloy and command it into a new slab." //No visible message, for stealth purposes + var/obj/item/clockwork/slab/S = new(get_turf(invoker)) + invoker.put_in_hands(S) //Put it in your hands if possible + return TRUE + + +//Tinkerer's Cache: Creates a tinkerer's cache, allowing global component storage. +/datum/clockwork_scripture/create_object/tinkerers_cache + descname = "Necessary, 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." + invocations = list("Constructing...", "...a cache!") + channel_time = 50 + required_components = list("belligerent_eye" = 0, "vanguard_cogwheel" = 0, "guvax_capacitor" = 0, "replicant_alloy" = 2, "hierophant_ansible" = 0) + consumed_components = list("belligerent_eye" = 0, "vanguard_cogwheel" = 0, "guvax_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 very efficient." + tier = SCRIPTURE_DRIVER + one_per_tile = TRUE + sort_priority = 8 + +/datum/clockwork_scripture/create_object/tinkerers_cache/New() + var/cache_cost_increase = min(round(clockwork_caches*0.2), 5) + for(var/i in required_components) + if(i != "replicant_alloy") + required_components[i] += cache_cost_increase + for(var/i in consumed_components) + if(i != "replicant_alloy") + consumed_components[i] += cache_cost_increase + return ..() + + +//Wraith Spectacles: Creates a pair of wraith spectacles, which grant xray vision but damage vision slowly. +/datum/clockwork_scripture/create_object/wraith_spectacles + descname = "Xray Vision Glasses" + name = "Wraith Spectacles" + desc = "Fabricates a pair of glasses that provides true sight but quickly damage vision, eventually causing blindness if worn for too long." + invocations = list("Show the truth of this world to me!") + channel_time = 10 + required_components = list("hierophant_ansible" = 1) + whispered = TRUE + object_path = /obj/item/clothing/glasses/wraith_spectacles + creator_message = "You form a pair of wraith spectacles, which will grant true sight when worn." + usage_tip = "\"True sight\" means that you are able to see through walls and in darkness." + tier = SCRIPTURE_DRIVER + space_allowed = TRUE + sort_priority = 9 + + +//Sigil of Transgression: Creates a sigil of transgression, which stuns the first nonservant to cross it. +/datum/clockwork_scripture/create_object/sigil_of_transgression + descname = "Stun Trap" + name = "Sigil of Transgression" + desc = "Wards a tile with a sigil. The next person to cross the sigil will be smitten and unable to move. Nar-Sian cultists are stunned altogether." + invocations = list("Divinity, dazzle...", "...those who tresspass here!") + channel_time = 50 + required_components = list("hierophant_ansible" = 2) + consumed_components = list("hierophant_ansible" = 1) + whispered = TRUE + object_path = /obj/effect/clockwork/sigil/transgression + creator_message = "A sigil silently appears below you. The next non-servant to cross it will be immobilized." + usage_tip = "The sigil, while fairly powerful in its stun, does not induce muteness in its victim." + tier = SCRIPTURE_DRIVER + one_per_tile = TRUE + sort_priority = 10 diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm new file mode 100644 index 00000000000..eca17084448 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm @@ -0,0 +1,108 @@ +/////////////// +// JUDGEMENT // +/////////////// + +//Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict, either summoning ratvar or proselytizing everything. +/datum/clockwork_scripture/ark_of_the_clockwork_justiciar + descname = "Win Condition" + name = "Ark of the Clockwork Justiciar" + desc = "Pulls from the power of all of Ratvar's servants and generals to construct a massive machine used to tear apart a rift in spacetime to the Celestial Derelict. This gateway will \ + call forth Ratvar from his exile after some time." + 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 + required_components = list("belligerent_eye" = 10, "vanguard_cogwheel" = 10, "guvax_capacitor" = 10, "replicant_alloy" = 10, "hierophant_ansible" = 10) + consumed_components = list("belligerent_eye" = 10, "vanguard_cogwheel" = 10, "guvax_capacitor" = 10, "replicant_alloy" = 10, "hierophant_ansible" = 10) + invokers_required = 5 + multiple_invokers_used = TRUE + 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/ark_of_the_clockwork_justiciar/New() + if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY) + invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \ + "THIS STATION WILL BE A BEACON OF HOPE IN THE DARKNESS OF SPACE!!", \ + "HELP US MAKE THIS SHOW ENGINE'S GLORY!!") + ..() + +/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/check_special_requirements() + if(!slab.no_cost) + if(ratvar_awakens) + invoker << "\"I am already here, idiot.\"" + return FALSE + for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in all_clockwork_objects) + var/area/gate_area = get_area(G) + invoker << "There is already a gateway at [gate_area.map_name]!" + return FALSE + var/area/A = get_area(invoker) + var/turf/T = get_turf(invoker) + if(!T || T.z != ZLEVEL_STATION || istype(A, /area/shuttle)) + invoker << "You must be on the station to activate the Ark!" + return FALSE + if(clockwork_gateway_activated) + if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY) + invoker << "\"Look upon his works. Is it not glorious?\"" + else + invoker << "Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!" + return FALSE + return TRUE + +/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/scripture_effects() + var/turf/T = get_turf(invoker) + new/obj/effect/clockwork/general_marker/inathneq(T) + if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY) + T.visible_message("\"[text2ratvar("Engine, come forth and show your servants your mercy!")]\"") + else + T.visible_message("\"[text2ratvar("We will show all the mercy of Engine!")]\"") + playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 30, 0) + sleep(10) + if(!check_special_requirements()) + return FALSE + new/obj/effect/clockwork/general_marker/sevtug(T) + if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY) + T.visible_message("\"[text2ratvar("Engine, come forth and show this station your decorating skills!")]\"") + else + T.visible_message("\"[text2ratvar("We will show all Engine's decorating skills.")]\"") + playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 45, 0) + sleep(10) + if(!check_special_requirements()) + return FALSE + new/obj/effect/clockwork/general_marker/nezbere(T) + if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY) + T.visible_message("\"[text2ratvar("Engine, come forth and shine your light across this realm!!")]\"") + else + T.visible_message("\"[text2ratvar("We will show all Engine's light!!")]\"") + playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 60, 0) + sleep(10) + if(!check_special_requirements()) + return FALSE + new/obj/effect/clockwork/general_marker/nzcrentr(T) + if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY) + T.visible_message("\"[text2ratvar("Engine, come forth.")]\"") + else + T.visible_message("\"[text2ratvar("We will show all Engine's power!")]\"") + playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 75, 0) + sleep(10) + if(check_special_requirements()) + var/obj/structure/destructible/clockwork/massive/celestial_gateway/CG = new/obj/structure/destructible/clockwork/massive/celestial_gateway(T) + if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY) + CG.ratvar_portal = FALSE + hierophant_message("This newly constructed gateway will not free Ratvar, \ + and will instead simply proselytize and convert everything and everyone on the station.", TRUE) + playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 100, 0) + var/list/open_turfs = list() + for(var/turf/open/OT in orange(1, T)) + var/list/dense_objects = list() + for(var/obj/O in OT) + if(O.density && !O.CanPass(invoker, OT, 5)) + dense_objects |= O + if(!dense_objects.len) + open_turfs |= OT + if(open_turfs.len) + for(var/mob/living/L in T) + L.forceMove(pick(open_turfs)) //shove living mobs off of the gate's new location + return TRUE + return FALSE diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm new file mode 100644 index 00000000000..79d69ef73c7 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm @@ -0,0 +1,228 @@ +////////////// +// REVENANT // +////////////// + +//Invoke Inath-neq, the Resonant Cogwheel: Grants invulnerability and stun immunity to everyone nearby for 15 seconds. +/datum/clockwork_scripture/invoke_inathneq + descname = "Area Invuln" + name = "Invoke Inath-neq, the Resonant Cogwheel" + desc = "Taps the limitless power of Inath-neq, one of Ratvar's four generals. The benevolence of Inath-Neq will grant complete invulnerability to all servants in range for fifteen seconds." + invocations = list("I call upon you, Vanguard!!", "Let the Resonant Cogs turn once more!!", "Grant me and my allies the strength to vanquish our foes!!") + channel_time = 150 + required_components = list("vanguard_cogwheel" = 6, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 3) + consumed_components = list("vanguard_cogwheel" = 6, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 3) + usage_tip = "Those affected by this scripture are only weak to things that outright destroy bodies, such as bombs or the singularity." + tier = SCRIPTURE_REVENANT + sort_priority = 2 + var/total_duration = 150 + +/datum/clockwork_scripture/invoke_inathneq/check_special_requirements() + if(!slab.no_cost && clockwork_generals_invoked["inath-neq"] > world.time) + invoker << "\"[text2ratvar("I cannot lend you my aid yet, champion. Please be careful.")]\"\n\ + Inath-neq has already been invoked recently! You must wait several minutes before calling upon the Resonant Cogwheel." + return FALSE + return TRUE + +/datum/clockwork_scripture/invoke_inathneq/scripture_effects() + new/obj/effect/clockwork/general_marker/inathneq(get_turf(invoker)) + hierophant_message("[text2ratvar("Vanguard: \"I lend you my aid, champions! Let glory guide your blows!")]\"", FALSE, invoker) + clockwork_generals_invoked["inath-neq"] = world.time + CLOCKWORK_GENERAL_COOLDOWN + playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) + if(invoker.real_name == "Lucio") + clockwork_say(invoker, text2ratvar("Aww, let's break it DOWN!!")) + for(var/mob/living/L in range(7, invoker)) + if(!is_servant_of_ratvar(L) || L.stat == DEAD) + continue + L.apply_status_effect(STATUS_EFFECT_INATHNEQS_ENDOWMENT) + return TRUE + + +//Invoke Nezbere, the Brass Eidolon: Invokes Nezbere, bolstering the strength of many clockwork items for one minute. +/datum/clockwork_scripture/invoke_nezbere + descname = "Structure Buff" + name = "Invoke Nezbere, the Brass Eidolon" + desc = "Taps the limitless power of Nezbere, one of Ratvar's four generals. The restless toil of the Eidolon will empower a wide variety of clockwork apparatus for a full minute - notably, \ + clockwork proselytizers will cost no replicant alloy to use." + invocations = list("I call upon you, Armorer!!", "Let your machinations reign on this miserable station!!", "Let your power flow through the tools of your master!!") + channel_time = 150 + required_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 6) + consumed_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 6) + usage_tip = "Ocular wardens will become empowered, clockwork proselytizers will require no alloy, tinkerer's daemons will produce twice as quickly, \ + and interdiction lenses, mending motors, mania motors, tinkerer's daemons, and clockwork obelisks will all require no power." + tier = SCRIPTURE_REVENANT + sort_priority = 3 + invokers_required = 3 + multiple_invokers_used = TRUE + +/datum/clockwork_scripture/invoke_nezbere/check_special_requirements() + if(!slab.no_cost && clockwork_generals_invoked["nezbere"] > world.time) + invoker << "\"[text2ratvar("Not just yet, friend. Patience is a virtue.")]\"\n\ + Nezbere has already been invoked recently! You must wait several minutes before calling upon the Brass Eidolon." + return FALSE + if(!slab.no_cost && ratvar_awakens) + invoker << "\"[text2ratvar("Our master is here already. You do not require my help, friend.")]\"\n\ + Nezbere will not grant his power while Ratvar's dwarfs his own!" + return FALSE + return TRUE + +/datum/clockwork_scripture/invoke_nezbere/scripture_effects() + new/obj/effect/clockwork/general_marker/nezbere(get_turf(invoker)) + hierophant_message("[text2ratvar("Armorer: \"I heed your call, champions. May your artifacts bring ruin upon the heathens that oppose our master!")]\"", FALSE, invoker) + clockwork_generals_invoked["nezbere"] = world.time + CLOCKWORK_GENERAL_COOLDOWN + playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) + for(var/obj/structure/destructible/clockwork/ocular_warden/W in all_clockwork_objects) //Ocular wardens have increased damage and radius + W.damage_per_tick *= 1.5 + W.sight_range *= 2 + for(var/obj/item/clockwork/clockwork_proselytizer/P in all_clockwork_objects) //Proselytizers no longer require alloy + P.uses_alloy = FALSE + for(var/obj/structure/destructible/clockwork/powered/M in all_clockwork_objects) //Powered clockwork structures no longer need power + M.needs_power = FALSE + if(istype(M, /obj/structure/destructible/clockwork/powered/tinkerers_daemon)) //Daemons produce components twice as quickly + var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = M + D.production_time *= 0.5 + spawn(600) + for(var/obj/structure/destructible/clockwork/ocular_warden/W in all_clockwork_objects) + W.damage_per_tick = initial(W.damage_per_tick) + W.sight_range = initial(W.sight_range) + for(var/obj/item/clockwork/clockwork_proselytizer/P in all_clockwork_objects) + P.uses_alloy = initial(P.uses_alloy) + for(var/obj/structure/destructible/clockwork/powered/M in all_clockwork_objects) + M.needs_power = initial(M.needs_power) + if(istype(M, /obj/structure/destructible/clockwork/powered/tinkerers_daemon)) + var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = M + D.production_time = initial(D.production_time) + return TRUE + + +//Invoke Sevtug, the Formless Pariah: Causes massive global hallucinations, braindamage, confusion, and dizziness to all humans on the same zlevel. +/datum/clockwork_scripture/invoke_sevtug + descname = "Global Hallucination" + name = "Invoke Sevtug, the Formless Pariah" + desc = "Taps the limitless power of Sevtug, one of Ratvar's four generals. The mental manipulation ability of the Pariah allows its wielder to cause mass hallucinations and confusion \ + for all non-servant humans on the same z-level as them. The power of this scripture falls off somewhat with distance, and certain things may reduce its effects." + invocations = list("I call upon you, Fright!!", "Let your power shatter the sanity of the weak-minded!!", "Let your tendrils hold sway over all!!") + channel_time = 150 + required_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 6, "hierophant_ansible" = 3) + consumed_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 6, "hierophant_ansible" = 3) + usage_tip = "Causes brain damage, hallucinations, confusion, and dizziness in massive amounts." + tier = SCRIPTURE_REVENANT + sort_priority = 4 + invokers_required = 3 + multiple_invokers_used = TRUE + var/list/mindbreaksayings = list("\"Oh, great. I get to shatter some minds.\"", "\"More minds to crush.\"", \ + "\"Really, this is almost boring.\"", "\"None of these minds have anything interesting in them.\"", "\"Maybe I can instill a little bit of terror in this one.\"", \ + "\"What a waste of my power.\"", "\"I'm sure I could just control these minds instead, but they never ask.\"") + +/datum/clockwork_scripture/invoke_sevtug/check_special_requirements() + if(!slab.no_cost && clockwork_generals_invoked["sevtug"] > world.time) + invoker << "\"[text2ratvar("Is it really so hard - even for a simpleton like you - to grasp the concept of waiting?")]\"\n\ + Sevtug has already been invoked recently! You must wait several minutes before calling upon the Formless Pariah." + return FALSE + if(!slab.no_cost && ratvar_awakens) + invoker << "\"[text2ratvar("Do you really think anything I can do right now will compare to Engine's power?")]\"\n\ + Sevtug will not grant his power while Ratvar's dwarfs his own!" + return FALSE + return TRUE + +/datum/clockwork_scripture/invoke_sevtug/scripture_effects() + new/obj/effect/clockwork/general_marker/sevtug(get_turf(invoker)) + hierophant_message("[text2ratvar("Fright: \"I heed your call, idiots. Get going and use this chance while it lasts!")]\"", FALSE, invoker) + clockwork_generals_invoked["sevtug"] = world.time + CLOCKWORK_GENERAL_COOLDOWN + playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) + var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected + var/turf/T = get_turf(invoker) + for(var/mob/living/carbon/human/H in living_mob_list) + if(H.z == invoker.z && !is_servant_of_ratvar(H)) + var/distance = 0 + distance += get_dist(T, get_turf(H)) + var/messaged = FALSE + var/visualsdistance = max(150 - distance, 5) + var/minordistance = max(200 - distance*2, 5) + var/majordistance = max(150 - distance*3, 5) + if(H.null_rod_check()) + visualsdistance = round(visualsdistance * 0.25) + minordistance = round(minordistance * 0.25) + majordistance = round(majordistance * 0.25) + H << "[text2ratvar("Oh, a void weapon. How annoying, I may as well not bother.")]\n\ + Your holy weapon glows a faint orange in an attempt to defend your mind!" + messaged = TRUE + if(H.isloyal()) + visualsdistance = round(visualsdistance * 0.5) //half effect for shielded targets + minordistance = round(minordistance * 0.5) + majordistance = round(majordistance * 0.5) + if(!messaged) + H << "[text2ratvar("Oh, look, a mindshield. Cute, I suppose I'll humor it.")]" + messaged = TRUE + if(!messaged && prob(visualsdistance)) + H << "[text2ratvar(pick(mindbreaksayings))]" + H.playsound_local(T, hum, visualsdistance, 1) + flash_color(H, flash_color="#AF0AAF", flash_time=visualsdistance*10) + H.set_drugginess(visualsdistance + H.druggy) + H.dizziness = minordistance + H.dizziness + H.hallucination = minordistance + H.hallucination + H.confused = majordistance + H.confused + H.setBrainLoss(majordistance + H.getBrainLoss()) + return TRUE + + +//Invoke Nzcrentr, the Eternal Thunderbolt: Imbues an immense amount of energy into the invoker. After several seconds, everyone near the invoker will be hit with a devastating lightning blast. +/datum/clockwork_scripture/invoke_nzcrentr + descname = "Lightning Blast" + name = "Invoke Nzcrentr, the Eternal Thunderbolt" + desc = "Taps the limitless power of Nzcrentr, one of Ratvar's four generals. The immense energy Nzcrentr wields will allow you to imbue a tiny fraction of it into your body. After several \ + seconds, anyone near you will be struck by a devastating lightning bolt." + invocations = list("I call upon you, Amperage!!", "Let your energy flow through me!!", "Let your boundless power shatter stars!!") + channel_time = 150 + required_components = list("belligerent_eye" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 6) + consumed_components = list("belligerent_eye" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 6) + usage_tip = "Struck targets will also be knocked down for about sixteen seconds." + tier = SCRIPTURE_REVENANT + sort_priority = 5 + +/datum/clockwork_scripture/invoke_nzcrentr/check_special_requirements() + if(!slab.no_cost && clockwork_generals_invoked["nzcrentr"] > world.time) + invoker << "\"[text2ratvar("The boss says you have to wait. Hey, do you think he would mind if I killed you? ...He would? Ok.")]\"\n\ + Nzcrentr has already been invoked recently! You must wait several minutes before calling upon the Forgotten Arbiter." + return FALSE + return TRUE + +/datum/clockwork_scripture/invoke_nzcrentr/scripture_effects() + new/obj/effect/clockwork/general_marker/nzcrentr(get_turf(invoker)) + clockwork_generals_invoked["nzcrentr"] = world.time + CLOCKWORK_GENERAL_COOLDOWN + hierophant_message("[text2ratvar("Amperage: \"[invoker.real_name] has called forth my power. Hope they do not shatter under it!")]\"", FALSE, invoker) + invoker.visible_message("[invoker] begins to radiate a blinding light!", \ + "\"[text2ratvar("The boss says it's okay to do this. Don't blame me if you die from it.")]\"\n \ + You feel limitless power surging through you!") + playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0) + playsound(invoker, 'sound/magic/lightning_chargeup.ogg', 100, 0) + animate(invoker, color = list(rgb(255, 255, 255), rgb(255, 255, 255), rgb(255, 255, 255), rgb(0,0,0)), time = 88) //Gradual advancement to extreme brightness + sleep(88) + if(invoker) + invoker.visible_message("Massive bolts of energy emerge from across [invoker]'s body!", \ + "\"[text2ratvar("I told you you wouldn't be able to handle it.")]\"\n \ + TOO... MUCH! CAN'T... TAKE IT!") + playsound(invoker, 'sound/magic/lightningbolt.ogg', 100, 0) + if(invoker.stat == CONSCIOUS) + animate(invoker, color = initial(invoker.color), time = 10) + for(var/mob/living/L in view(7, invoker)) + if(is_servant_of_ratvar(L)) + continue + invoker.Beam(L, icon_state = "nzcrentrs_power", time = 10) + var/randdamage = rand(40, 60) + if(iscarbon(L)) + L.electrocute_act(randdamage, "Nzcrentr's power", 1, randdamage) + else + L.adjustFireLoss(randdamage) + L.visible_message( + "[L] was shocked by Nzcrentr's power!", \ + "You feel a powerful shock coursing through your body!", \ + "You hear a heavy electrical crack." \ + ) + L.Weaken(8) + playsound(L, 'sound/magic/LightningShock.ogg', 50, 1) + else + playsound(invoker, 'sound/magic/Disintegrate.ogg', 50, 1) + invoker.gib() + return TRUE + else + return FALSE diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm new file mode 100644 index 00000000000..21a198739d5 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm @@ -0,0 +1,292 @@ +///////////// +// SCRIPTS // +///////////// + +//Ocular Warden: Creates an ocular warden, which defends a small area near it. +/datum/clockwork_scripture/create_object/ocular_warden + descname = "Turret" + name = "Ocular Warden" + desc = "Forms an automatic short-range turret that deals low sustained damage to the unenlightened in its range." + invocations = list("Guardians...", "...of the Engine...", "...defend us!") + channel_time = 120 + required_components = list("belligerent_eye" = 2, "replicant_alloy" = 1) + consumed_components = list("belligerent_eye" = 1, "replicant_alloy" = 1) + object_path = /obj/structure/destructible/clockwork/ocular_warden + creator_message = "You form an ocular warden, which will focus its searing gaze upon nearby unenlightened." + observer_message = "A brass eye takes shape and slowly rises into the air, its red iris glaring!" + usage_tip = "Although powerful, the warden is very weak and should optimally be placed behind barricades." + tier = SCRIPTURE_SCRIPT + one_per_tile = TRUE + space_allowed = TRUE + sort_priority = 1 + +/datum/clockwork_scripture/create_object/ocular_warden/check_special_requirements() + for(var/obj/structure/destructible/clockwork/ocular_warden/W in range(3, invoker)) + invoker << "You sense another ocular warden too near this location. Placing another this close would cause them to fight." //fluff message + return FALSE + return ..() + + +//Cogscarab: Creates an empty cogscarab shell, which produces a cogscarab dedicated to maintaining and defending the cult. +/datum/clockwork_scripture/create_object/cogscarab + descname = "Constructor Soul Vessel Shell" + name = "Cogscarab" + desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt proselytizer." + invocations = list("Call forth...", "...the workers of Armorer.") + channel_time = 60 + required_components = list("belligerent_eye" = 2, "hierophant_ansible" = 1) + consumed_components = list("belligerent_eye" = 1, "hierophant_ansible" = 1) + object_path = /obj/structure/destructible/clockwork/shell/cogscarab + creator_message = "You form a cogscarab, a constructor soul vessel receptable." + observer_message = "The slab disgorges a puddle of black metal that contracts and forms into a strange shell!" + usage_tip = "Useless without a soul vessel and should not be created without one." + tier = SCRIPTURE_SCRIPT + sort_priority = 2 + + +//Fellowship Armory: Arms the invoker and nearby servants with Ratvarian armor. +/datum/clockwork_scripture/fellowship_armory + descname = "Area Servant Armor" + name = "Fellowship Armory" + desc = "Equips the invoker and any nearby servants with Ratvarian armor. This armor provides high melee resistance but a weakness to lasers. \ + It grows faster to invoke with more nearby servants." + invocations = list("Shield me...", "...with the...", "... fragments of Engine!") + channel_time = 110 //effectively 100 because it counts the invoker + required_components = list("vanguard_cogwheel" = 2, "replicant_alloy" = 1) + consumed_components = list("vanguard_cogwheel" = 1, "replicant_alloy" = 1) + usage_tip = "Before using, advise adjacent allies to remove their helmets, external suits, gloves, and shoes." + tier = SCRIPTURE_SCRIPT + multiple_invokers_used = TRUE + multiple_invokers_optional = TRUE + sort_priority = 4 + +/datum/clockwork_scripture/fellowship_armory/run_scripture() + for(var/mob/living/L in range(1, invoker)) + if(is_servant_of_ratvar(L) && L.can_speak_vocal()) + channel_time = max(channel_time - 10, 0) + return ..() + +/datum/clockwork_scripture/fellowship_armory/scripture_effects() + for(var/mob/living/L in range(1, invoker)) + if(!is_servant_of_ratvar(L)) + continue + L.visible_message("Strange armor appears on [L]!", "A bright shimmer runs down your body, equipping you with Ratvarian armor.") + playsound(L, 'sound/magic/clockwork/fellowship_armory.ogg', 50, 1) + L.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head) + L.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit) + L.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves) + L.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes) + return TRUE + + +//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay. +/datum/clockwork_scripture/create_object/sigil_of_submission + descname = "Conversion Trap" + name = "Sigil of Submission" + desc = "Places a luminous sigil that will enslave any valid beings standing on it after a time." + invocations = list("Divinity, enlighten...", "...those who trespass here!") + channel_time = 60 + required_components = list("belligerent_eye" = 1, "guvax_capacitor" = 2) + consumed_components = list("belligerent_eye" = 1, "guvax_capacitor" = 1) + whispered = TRUE + object_path = /obj/effect/clockwork/sigil/submission + creator_message = "A luminous sigil appears below you. The next non-servant to cross it will be enslaved after a brief time if they do not move." + usage_tip = "This is not a primary conversion method - use Guvax for that. It is advantageous as a trap, however, as it will transmit the name of the newly-converted." + tier = SCRIPTURE_SCRIPT + one_per_tile = TRUE + sort_priority = 5 + + +//Soul Vessel: Creates a soul vessel, which can seek a ghost or be used on the uncovered head of a dead or dying human to take their brain. +/datum/clockwork_scripture/create_object/soul_vessel + descname = "Clockwork Posibrain" + name = "Soul Vessel" + desc = "Forms an ancient positronic brain with an overriding directive to serve Ratvar." + invocations = list("Herd the souls of...", "...the blasphemous damned!") + channel_time = 30 + required_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 2) + consumed_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 1) + whispered = TRUE + object_path = /obj/item/device/mmi/posibrain/soul_vessel + creator_message = "You form a soul vessel, which can be used in-hand to attract spirits, or used on an unconscious or dead human to extract their consciousness." + usage_tip = "The vessel can be used as a teleport target for Spatial Gateway, though it is generally better-used by placing it in a shell." + tier = SCRIPTURE_SCRIPT + space_allowed = TRUE + sort_priority = 6 + + +//Clockwork Proselytizer: Creates a clockwork proselytizer, used to convert objects and repair clockwork structures. +/datum/clockwork_scripture/create_object/clockwork_proselytizer + descname = "Necessary, Converts Objects" + name = "Clockwork Proselytizer" + desc = "Forms a device that, when used on certain objects, converts them into their Ratvarian equivalents. It requires replicant alloys to function." + invocations = list("With this device...", "...his presence shall be made known.") + channel_time = 20 + required_components = list("guvax_capacitor" = 1, "replicant_alloy" = 2) + consumed_components = list("guvax_capacitor" = 1, "replicant_alloy" = 1) + whispered = TRUE + object_path = /obj/item/clockwork/clockwork_proselytizer/preloaded + creator_message = "You form a clockwork proselytizer, which is already pre-loaded with a small amount of replicant alloy." + usage_tip = "Clockwork walls cause adjacent tinkerer's caches to generate components passively, making them a vital tool. Clockwork floors heal servants standing on them." + tier = SCRIPTURE_SCRIPT + space_allowed = TRUE + sort_priority = 7 + + +//Function Call: Grants the invoker the ability to call forth a Ratvarian spear that deals significant damage to silicons. +/datum/clockwork_scripture/function_call + descname = "Summonable Spear" + name = "Function Call" + desc = "Grants the invoker the ability to call forth a powerful Ratvarian spear every three minutes. The spear will deal significant damage to Nar-Sie's dogs and silicon lifeforms, but will \ + vanish three minutes after being summoned." + invocations = list("Grant me...", "...the might of brass!") + channel_time = 20 + required_components = list("replicant_alloy" = 2, "hierophant_ansible" = 1) + consumed_components = list("replicant_alloy" = 1, "hierophant_ansible" = 1) + whispered = TRUE + usage_tip = "You can impale human targets with the spear by pulling them, then attacking. Throwing the spear at a mob will do massive damage and stun them, but break the spear." + tier = SCRIPTURE_SCRIPT + sort_priority = 8 + +/datum/clockwork_scripture/function_call/check_special_requirements() + for(var/datum/action/innate/function_call/F in invoker.actions) + invoker << "You have already bound a Ratvarian spear to yourself!" + return FALSE + return invoker.can_hold_items() + +/datum/clockwork_scripture/function_call/scripture_effects() + invoker.visible_message("A shimmer of yellow light infuses [invoker]!", \ + "You bind a Ratvarian spear to yourself. Use the \"Function Call\" action button to call it forth.") + var/datum/action/innate/function_call/F = new() + F.Grant(invoker) + return TRUE + +//Function Call action: Calls forth a Ratvarian spear once every 3 minutes. +/datum/action/innate/function_call + name = "Function Call" + desc = "Allows you to summon a Ratvarian spear to fight enemies." + button_icon_state = "ratvarian_spear" + background_icon_state = "bg_clock" + check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS + buttontooltipstyle = "clockcult" + var/cooldown = 0 + var/base_cooldown = 1800 + +/datum/action/innate/function_call/IsAvailable() + if(!is_servant_of_ratvar(owner) || cooldown > world.time) + return FALSE + return ..() + +/datum/action/innate/function_call/Activate() + if(!owner.get_empty_held_indexes()) + usr << "You need an empty to hand to call forth your spear!" + return FALSE + owner.visible_message("A strange spear materializes in [owner]'s hands!", "You call forth your spear!") + var/obj/item/clockwork/ratvarian_spear/R = new(get_turf(usr)) + owner.put_in_hands(R) + if(!ratvar_awakens) + owner << "Your spear begins to break down in this plane of existence. You can't use it for long!" + addtimer(R, "break_spear", base_cooldown, FALSE) + cooldown = base_cooldown + world.time + owner.update_action_buttons_icon() + addtimer(src, "update_actions", base_cooldown, FALSE) + return TRUE + +/datum/action/innate/function_call/proc/update_actions() + if(owner) + owner.update_action_buttons_icon() + + +//Spatial Gateway: Allows the invoker to teleport themselves and any nearby allies to a conscious servant or clockwork obelisk. +/datum/clockwork_scripture/spatial_gateway + descname = "Teleport Gate" + name = "Spatial Gateway" + desc = "Tears open a miniaturized gateway in spacetime to any conscious servant that can transport objects or creatures to its destination. \ + Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration." + invocations = list("Spatial Gateway...", "...activate!") + channel_time = 80 + required_components = list("vanguard_cogwheel" = 1, "hierophant_ansible" = 2) + consumed_components = list("vanguard_cogwheel" = 1, "hierophant_ansible" = 1) + multiple_invokers_used = TRUE + multiple_invokers_optional = TRUE + usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal." + tier = SCRIPTURE_SCRIPT + sort_priority = 9 + +/datum/clockwork_scripture/spatial_gateway/check_special_requirements() + if(!isturf(invoker.loc)) + invoker << "You must not be inside an object to use this scripture!" + return FALSE + var/other_servants = 0 + for(var/mob/living/L in living_mob_list) + if(is_servant_of_ratvar(L) && !L.stat != DEAD) + other_servants++ + for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects) + other_servants++ + if(!other_servants) + invoker << "There are no other servants or clockwork obelisks!" + return FALSE + return TRUE + +/datum/clockwork_scripture/spatial_gateway/scripture_effects() + var/portal_uses = 0 + var/duration = 0 + for(var/mob/living/L in range(1, invoker)) + if(!L.stat && is_servant_of_ratvar(L)) + portal_uses++ + duration += 40 //4 seconds + if(ratvar_awakens) + portal_uses = max(portal_uses, 100) //Very powerful if Ratvar has been summoned + duration = max(duration, 100) + return slab.procure_gateway(invoker, duration, portal_uses) + + +//Volt Void: Channeled for up to thirty times over thirty seconds. Consumes power from most power storages and deals slight burn damage to the invoker. +/datum/clockwork_scripture/channeled/volt_void + descname = "Channeled, Area Power Drain" + name = "Volt Void" //Alternative name: "On all levels but physical, I am a power sink" + desc = "Drains energy from nearby power sources, dealing burn damage if the total power consumed is above a threshhold. Channeled every second for a maximum of thirty seconds." + chant_invocations = list("Draw charge to this shell!") + chant_amount = 30 + chant_interval = 10 + required_components = list("guvax_capacitor" = 1, "hierophant_ansible" = 2) + consumed_components = list("guvax_capacitor" = 1, "hierophant_ansible" = 1) + usage_tip = "If standing on a Sigil of Transmission, will transfer power to it. Augumented limbs will also be healed unless above a very high threshhold." + tier = SCRIPTURE_SCRIPT + sort_priority = 10 + var/total_power_drained = 0 + var/power_damage_threshhold = 3000 + var/augument_damage_threshhold = 6000 + +/datum/clockwork_scripture/channeled/volt_void/chant_effects(chant_number) + playsound(invoker, 'sound/effects/EMPulse.ogg', 50, 1) + var/power_drained = 0 + for(var/atom/movable/A in view(7, invoker)) + power_drained += A.power_drain(TRUE) + var/obj/effect/clockwork/sigil/transmission/ST = locate(/obj/effect/clockwork/sigil/transmission) in get_turf(invoker) + if(ST && power_drained >= 50) + var/sigil_drain = 0 + while(power_drained >= 50) + ST.modify_charge(-50) + power_drained -= 50 + sigil_drain += 10 + power_drained += sigil_drain //readd part of the power given to the sigil to the power drained this cycle + ST.visible_message("[ST] flares a brilliant orange!") + total_power_drained += power_drained + if(power_drained >= 100 && total_power_drained >= power_damage_threshhold) + var/power_damage = power_drained * 0.01 + invoker.visible_message("[invoker] flares a brilliant orange!", "You feel the warmth of electricity running into your body.") + if(ishuman(invoker)) + var/mob/living/carbon/human/H = invoker + for(var/X in H.bodyparts) + var/obj/item/bodypart/BP = X + if(ratvar_awakens || (BP.status == BODYPART_ROBOTIC && total_power_drained < augument_damage_threshhold)) //if ratvar is alive, it won't damage and will always heal augumented limbs + if(BP.heal_damage(power_damage, power_damage, 1, 0)) //heals one point of burn and brute for every ~100W drained on augumented limbs + H.update_damage_overlays() + else + if(BP.receive_damage(0, power_damage)) + H.update_damage_overlays() + else if(isanimal(invoker)) + var/mob/living/simple_animal/A = invoker + A.adjustHealth(-power_damage) //if a simple animal is using volt void, just heal it + return TRUE diff --git a/code/game/gamemodes/clock_cult/clock_structure.dm b/code/game/gamemodes/clock_cult/clock_structure.dm new file mode 100644 index 00000000000..0b9cd398447 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structure.dm @@ -0,0 +1,200 @@ +//The base clockwork structure. Can have an alternate desc and will show up in the list of clockwork objects. +/obj/structure/destructible/clockwork + name = "meme structure" + desc = "Some frog or something, the fuck?" + var/clockwork_desc //Shown to servants when they examine + icon = 'icons/obj/clockwork_objects.dmi' + icon_state = "rare_pepe" + anchored = 1 + density = 1 + resistance_flags = FIRE_PROOF | ACID_PROOF + var/repair_amount = 5 //how much a proselytizer can repair each cycle + var/can_be_repaired = TRUE //if a proselytizer can repair it at all + break_message = "The frog isn't a meme after all!" //The message shown when a structure breaks + break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks + debris = list(/obj/item/clockwork/alloy_shards/large = 1, \ + /obj/item/clockwork/alloy_shards/medium = 2, \ + /obj/item/clockwork/alloy_shards/small = 3) //Parts left behind when a structure breaks + var/construction_value = 0 //How much value the structure contributes to the overall "power" of the structures on the station + +/obj/structure/destructible/clockwork/New() + ..() + change_construction_value(construction_value) + all_clockwork_objects += src + +/obj/structure/destructible/clockwork/Destroy() + change_construction_value(-construction_value) + all_clockwork_objects -= src + return ..() + +/obj/structure/destructible/clockwork/narsie_act() + if(take_damage(rand(25, 50), BRUTE) && src) //if we still exist + var/previouscolor = color + color = "#960000" + animate(src, color = previouscolor, time = 8) + +/obj/structure/destructible/clockwork/examine(mob/user) + var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user) + if(can_see_clockwork && clockwork_desc) + desc = clockwork_desc + ..() + desc = initial(desc) + if(!(resistance_flags & INDESTRUCTIBLE)) + var/t_It = p_they(TRUE) + var/t_is = p_are() + var/servant_message = "[t_It] [t_is] at [obj_integrity]/[max_integrity] integrity" + var/heavily_damaged = FALSE + var/healthpercent = (obj_integrity/max_integrity) * 100 + if(healthpercent < 50) + heavily_damaged = TRUE + if(can_see_clockwork) + user << "[servant_message][heavily_damaged ? "!":"."]" + + +//for the ark and Ratvar +/obj/structure/destructible/clockwork/massive + name = "massive construct" + desc = "A very large construction." + layer = MASSIVE_OBJ_LAYER + density = FALSE + resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF + +/obj/structure/destructible/clockwork/massive/New() + ..() + poi_list += src + +/obj/structure/destructible/clockwork/massive/Destroy() + poi_list -= src + return ..() + +/obj/structure/destructible/clockwork/massive/singularity_pull(S, current_size) + return + + +//the base clockwork machinery, which is not actually machines, but happens to use power +/obj/structure/destructible/clockwork/powered + var/obj/machinery/power/apc/target_apc + var/active = FALSE + var/needs_power = TRUE + var/active_icon = null //icon_state while process() is being called + var/inactive_icon = null //icon_state while process() isn't being called + +/obj/structure/destructible/clockwork/powered/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + var/powered = total_accessable_power() + user << "It has access to [powered == INFINITY ? "INFINITY":"[powered]"]W of power." + +/obj/structure/destructible/clockwork/powered/Destroy() + SSfastprocess.processing -= src + SSobj.processing -= src + return ..() + +/obj/structure/destructible/clockwork/powered/process() + var/powered = total_accessable_power() + return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define + +/obj/structure/destructible/clockwork/powered/proc/toggle(fast_process, mob/living/user) + if(user) + if(!is_servant_of_ratvar(user)) + return FALSE + user.visible_message("[user] [active ? "dis" : "en"]ables [src].", "You [active ? "dis" : "en"]able [src].") + active = !active + if(active) + icon_state = active_icon + if(fast_process) + START_PROCESSING(SSfastprocess, src) + else + START_PROCESSING(SSobj, src) + else + icon_state = inactive_icon + if(fast_process) + STOP_PROCESSING(SSfastprocess, src) + else + STOP_PROCESSING(SSobj, src) + return TRUE + + +/obj/structure/destructible/clockwork/powered/proc/total_accessable_power() //how much power we have and can use + if(!needs_power || ratvar_awakens) + return INFINITY //oh yeah we've got power why'd you ask + + var/power = 0 + power += accessable_apc_power() + power += accessable_sigil_power() + return power + +/obj/structure/destructible/clockwork/powered/proc/accessable_apc_power() + var/power = 0 + var/area/A = get_area(src) + var/area/targetAPCA + for(var/obj/machinery/power/apc/APC in apcs_list) + var/area/APCA = get_area(APC) + if(APCA == A) + target_apc = APC + if(target_apc) + targetAPCA = get_area(target_apc) + if(targetAPCA != A) + target_apc = null + else if(target_apc.cell) + var/apccharge = target_apc.cell.charge + if(apccharge >= MIN_CLOCKCULT_POWER) + power += apccharge + return power + +/obj/structure/destructible/clockwork/powered/proc/accessable_sigil_power() + var/power = 0 + for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src)) + power += T.power_charge + return power + + +/obj/structure/destructible/clockwork/powered/proc/try_use_power(amount) //try to use an amount of power + if(!needs_power || ratvar_awakens) + return 1 + if(amount <= 0) + return FALSE + var/power = total_accessable_power() + if(!power || power < amount) + return FALSE + return use_power(amount) + +/obj/structure/destructible/clockwork/powered/proc/use_power(amount) //we've made sure we had power, so now we use it + var/sigilpower = accessable_sigil_power() + var/list/sigils_in_range = list() + for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src)) + sigils_in_range |= T + while(sigilpower && amount >= MIN_CLOCKCULT_POWER) + for(var/S in sigils_in_range) + var/obj/effect/clockwork/sigil/transmission/T = S + if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(MIN_CLOCKCULT_POWER)) + sigilpower -= MIN_CLOCKCULT_POWER + amount -= MIN_CLOCKCULT_POWER + var/apcpower = accessable_apc_power() + while(apcpower >= MIN_CLOCKCULT_POWER && amount >= MIN_CLOCKCULT_POWER) + if(target_apc.cell.use(MIN_CLOCKCULT_POWER)) + apcpower -= MIN_CLOCKCULT_POWER + amount -= MIN_CLOCKCULT_POWER + target_apc.update() + target_apc.update_icon() + else + apcpower = 0 + if(amount) + return FALSE + else + return TRUE + +/obj/structure/destructible/clockwork/powered/proc/return_power(amount) //returns a given amount of power to all nearby sigils + if(amount <= 0) + return FALSE + var/list/sigils_in_range = list() + for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src)) + sigils_in_range |= T + if(!sigils_in_range.len) + return FALSE + while(amount >= MIN_CLOCKCULT_POWER) + for(var/S in sigils_in_range) + var/obj/effect/clockwork/sigil/transmission/T = S + if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(-MIN_CLOCKCULT_POWER)) + amount -= MIN_CLOCKCULT_POWER + return TRUE diff --git a/code/game/gamemodes/clock_cult/clock_structures.dm b/code/game/gamemodes/clock_cult/clock_structures.dm deleted file mode 100644 index f73614f4c21..00000000000 --- a/code/game/gamemodes/clock_cult/clock_structures.dm +++ /dev/null @@ -1,928 +0,0 @@ -////////////////////////// -// CLOCKWORK STRUCTURES // -////////////////////////// - -/obj/structure/destructible/clockwork - name = "meme structure" - desc = "Some frog or something, the fuck?" - var/clockwork_desc //Shown to servants when they examine - icon = 'icons/obj/clockwork_objects.dmi' - icon_state = "rare_pepe" - anchored = 1 - density = 1 - resistance_flags = FIRE_PROOF | ACID_PROOF - var/repair_amount = 5 //how much a proselytizer can repair each cycle - var/can_be_repaired = TRUE //if a proselytizer can repair it at all - break_message = "The frog isn't a meme after all!" //The message shown when a structure breaks - break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks - debris = list(/obj/item/clockwork/alloy_shards/large = 1, \ - /obj/item/clockwork/alloy_shards/medium = 2, \ - /obj/item/clockwork/alloy_shards/small = 3) //Parts left behind when a structure breaks - var/construction_value = 0 //How much value the structure contributes to the overall "power" of the structures on the station - -/obj/structure/destructible/clockwork/New() - ..() - change_construction_value(construction_value) - all_clockwork_objects += src - -/obj/structure/destructible/clockwork/Destroy() - change_construction_value(-construction_value) - all_clockwork_objects -= src - return ..() - -/obj/structure/destructible/clockwork/narsie_act() - if(take_damage(rand(25, 50), BRUTE) && src) //if we still exist - var/previouscolor = color - color = "#960000" - animate(src, color = previouscolor, time = 8) - -/obj/structure/destructible/clockwork/examine(mob/user) - var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user) - if(can_see_clockwork && clockwork_desc) - desc = clockwork_desc - ..() - desc = initial(desc) - if(!(resistance_flags & INDESTRUCTIBLE)) - var/t_It = p_they(TRUE) - var/t_is = p_are() - var/servant_message = "[t_It] [t_is] at [obj_integrity]/[max_integrity] integrity" - var/heavily_damaged = FALSE - var/healthpercent = (obj_integrity/max_integrity) * 100 - if(healthpercent < 50) - heavily_damaged = TRUE - if(can_see_clockwork) - user << "[servant_message][heavily_damaged ? "!":"."]" - -/obj/structure/destructible/clockwork/cache //Tinkerer's cache: Stores components for later use. - 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" - construction_value = 10 - break_message = "The cache's fire winks out before it falls in on itself!" - max_integrity = 80 - obj_integrity = 80 - var/wall_generation_cooldown - var/turf/closed/wall/clockwork/linkedwall //if we've got a linked wall and are producing - -/obj/structure/destructible/clockwork/cache/New() - ..() - START_PROCESSING(SSobj, src) - clockwork_caches++ - SetLuminosity(2,1) - for(var/i in all_clockwork_mobs) - cache_check(i) - -/obj/structure/destructible/clockwork/cache/Destroy() - clockwork_caches-- - STOP_PROCESSING(SSobj, src) - if(linkedwall) - linkedwall.linkedcache = null - linkedwall = null - for(var/i in all_clockwork_mobs) - cache_check(i) - return ..() - -/obj/structure/destructible/clockwork/cache/deconstruct(disassembled = TRUE) - if(!(flags & NODECONSTRUCT)) - for(var/I in src) - var/atom/movable/A = I - A.forceMove(get_turf(src)) //drop any daemons we have - return ..() - -/obj/structure/destructible/clockwork/cache/process() - for(var/turf/closed/wall/clockwork/C in view(4, src)) - if(!C.linkedcache && !linkedwall) - C.linkedcache = src - linkedwall = C - wall_generation_cooldown = world.time + CACHE_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 + CACHE_PRODUCTION_TIME - var/component_to_generate = get_weighted_component_id() - PoolOrNew(get_component_animation_type(component_to_generate), get_turf(src)) - clockwork_component_cache[component_to_generate]++ - playsound(C, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1) - visible_message("Something clunks around inside of [src]...") - break - -/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 - clockwork_component_cache[C.component_id]++ - 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 - for(var/i in S.stored_components) - clockwork_component_cache[i] += S.stored_components[i] - S.stored_components[i] = 0 - 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/attack_hand(mob/user) - if(!is_servant_of_ratvar(user)) - return 0 - if(!clockwork_component_cache["replicant_alloy"]) - user << "There is no Replicant Alloy in the global component cache!" - return 0 - clockwork_component_cache["replicant_alloy"]-- - var/obj/item/clockwork/component/replicant_alloy/A = new(get_turf(src)) - user.visible_message("[user] withdraws [A] from [src].", "You withdraw [A] from [src].") - user.put_in_hands(A) - return 1 - -/obj/structure/destructible/clockwork/cache/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - if(linkedwall) - user << "It is linked and will generate components!" - user << "Stored components:" - for(var/i in clockwork_component_cache) - user << "[get_component_name(i)][i != "replicant_alloy" ? "s":""]: [clockwork_component_cache[i]]" - - -/obj/structure/destructible/clockwork/ocular_warden //Ocular warden: Low-damage, low-range turret. Deals constant damage to whoever it makes eye contact with. - name = "ocular warden" - desc = "A large brass eye with tendrils trailing below it and a wide red iris." - clockwork_desc = "A fragile turret that will deal sustained damage to any non-faithful it sees." - icon_state = "ocular_warden" - obj_integrity = 25 - max_integrity = 25 - construction_value = 15 - layer = HIGH_OBJ_LAYER - break_message = "The warden's eye gives a glare of utter hate before falling dark!" - debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye = 1) - resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - var/damage_per_tick = 2.5 - var/sight_range = 3 - var/atom/movable/target - var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.") - -/obj/structure/destructible/clockwork/ocular_warden/New() - ..() - START_PROCESSING(SSfastprocess, src) - -/obj/structure/destructible/clockwork/ocular_warden/Destroy() - STOP_PROCESSING(SSfastprocess, src) - return ..() - -/obj/structure/destructible/clockwork/ocular_warden/examine(mob/user) - ..() - user << "[target ? "It's fixated on [target]!" : "Its gaze is wandering aimlessly."]" - -/obj/structure/destructible/clockwork/ocular_warden/process() - var/list/validtargets = acquire_nearby_targets() - if(ratvar_awakens && (damage_per_tick == initial(damage_per_tick) || sight_range == initial(sight_range))) //Massive buff if Ratvar has returned - damage_per_tick = 10 - sight_range = 5 - if(target) - if(!(target in validtargets)) - lose_target() - else - if(isliving(target)) - var/mob/living/L = target - if(!L.null_rod_check()) - L.adjustFireLoss(!iscultist(L) ? damage_per_tick : damage_per_tick * 2) //Nar-Sian cultists take additional damage - if(ratvar_awakens && L) - L.adjust_fire_stacks(damage_per_tick) - L.IgniteMob() - else if(istype(target,/obj/mecha)) - var/obj/mecha/M = target - M.take_damage(damage_per_tick, BURN, "melee", 1, get_dir(src, M)) //does about half of standard damage to mechs * whatever their fire armor is - - setDir(get_dir(get_turf(src), get_turf(target))) - if(!target) - if(validtargets.len) - target = pick(validtargets) - visible_message("[src] swivels to face [target]!") - if(isliving(target)) - var/mob/living/L = target - L << "\"I SEE YOU!\"\n[src]'s gaze [ratvar_awakens ? "melts you alive" : "burns you"]!" - else if(istype(target,/obj/mecha)) - var/obj/mecha/M = target - M.occupant << "\"I SEE YOU!\"" //heeeellooooooo, person in mech. - else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes - if(prob(50)) - visible_message("[src][pick(idle_messages)]") - else - setDir(pick(cardinal))//Random rotation - -/obj/structure/destructible/clockwork/ocular_warden/proc/acquire_nearby_targets() - . = list() - for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind - var/obj/item/weapon/storage/book/bible/B = L.bible_check() - if(!is_servant_of_ratvar(L) && !L.stat && L.mind && !(L.disabilities & BLIND) && !L.null_rod_check() && !B) - . += L - else if(B) - if(!(B.resistance_flags & ON_FIRE)) - L << "Your [B.name] bursts into flames!" - for(var/obj/item/weapon/storage/book/bible/BI in L.GetAllContents()) - if(!(BI.resistance_flags & ON_FIRE)) - BI.fire_act() - for(var/N in mechas_list) - var/obj/mecha/M = N - if(get_dist(M, src) <= sight_range && M.occupant && !is_servant_of_ratvar(M.occupant) && (M in view(sight_range, src))) - . += M - -/obj/structure/destructible/clockwork/ocular_warden/proc/lose_target() - if(!target) - return 0 - target = null - visible_message("[src] settles and seems almost disappointed.") - return 1 - - -/obj/structure/destructible/clockwork/shell - construction_value = 0 - anchored = 0 - density = 0 - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF - var/mobtype = /mob/living/simple_animal/hostile/clockwork - var/spawn_message = " is an error and you should yell at whoever spawned this shell." - -/obj/structure/destructible/clockwork/shell/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/device/mmi/posibrain/soul_vessel)) - if(!is_servant_of_ratvar(user)) - ..() - return 0 - var/obj/item/device/mmi/posibrain/soul_vessel/S = I - if(!S.brainmob) - user << "[S] hasn't trapped a spirit! Turn it on first." - return 0 - if(S.brainmob && (!S.brainmob.client || !S.brainmob.mind)) - user << "[S]'s trapped spirit appears inactive!" - return 0 - user.visible_message("[user] places [S] in [src], where it fuses to the shell.", "You place [S] in [src], fusing it to the shell.") - var/mob/living/simple_animal/A = new mobtype(get_turf(src)) - A.visible_message("[src][spawn_message]") - S.brainmob.mind.transfer_to(A) - user.drop_item() - qdel(S) - qdel(src) - return 1 - else - return ..() - -/obj/structure/destructible/clockwork/shell/cogscarab - name = "cogscarab shell" - desc = "A small brass shell with a cube-shaped receptable in its center. It gives off an aura of obsessive perfectionism." - clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt proselytizer." - icon_state = "clockdrone_shell" - mobtype = /mob/living/simple_animal/drone/cogscarab - spawn_message = "'s eyes blink open, glowing bright red." - -/obj/structure/destructible/clockwork/shell/fragment //Anima fragment: Useless on its own, but can accept an active soul vessel to create a powerful construct. - name = "fragment shell" - desc = "A massive brass shell with a small cube-shaped receptable in its center. It gives off an aura of contained power." - clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a powerful construct." - icon_state = "anime_fragment" - mobtype = /mob/living/simple_animal/hostile/clockwork/fragment - spawn_message = " whirs and rises from the ground on a flickering jet of reddish fire." - - -/obj/structure/destructible/clockwork/wall_gear - name = "massive gear" - icon_state = "wall_gear" - climbable = TRUE - max_integrity = 50 - obj_integrity = 50 - desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, or just climb over it." - clockwork_desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, just climb over it, or proselytize it into replicant alloy." - break_message = "The gear breaks apart into shards of alloy!" - debris = list(/obj/item/clockwork/alloy_shards/large = 1, \ - /obj/item/clockwork/alloy_shards/medium = 4, \ - /obj/item/clockwork/alloy_shards/small = 2) //slightly more debris than the default, totals 26 alloy - -/obj/structure/destructible/clockwork/wall_gear/displaced - anchored = FALSE - -/obj/structure/destructible/clockwork/wall_gear/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/weapon/wrench)) - default_unfasten_wrench(user, I, 10) - return 1 - else if(istype(I, /obj/item/stack/sheet/brass)) - var/obj/item/stack/sheet/brass/W = I - if(W.get_amount() < 1) - user << "You need one brass sheet to do this!" - return - var/turf/T = get_turf(src) - if(iswallturf(T)) - user << "There is already a wall present!" - return - if(!isfloorturf(T)) - user << "A floor must be present to build a [anchored ? "false ":""]wall!" - return - if(locate(/obj/structure/falsewall) in T.contents) - user << "There is already a false wall present!" - return - user << "You start adding [W] to [src]..." - if(do_after(user, 20, target = src)) - var/brass_floor = FALSE - if(istype(T, /turf/open/floor/clockwork)) //if the floor is already brass, costs less to make(conservation of masssssss) - brass_floor = TRUE - if(W.use(2 - brass_floor)) - if(anchored) - T.ChangeTurf(/turf/closed/wall/clockwork) - else - T.ChangeTurf(/turf/open/floor/clockwork) - new /obj/structure/falsewall/brass(T) - qdel(src) - else - user << "You need more brass to make a [anchored ? "false ":""]wall!" - return 1 - return ..() - -/obj/structure/destructible/clockwork/wall_gear/examine(mob/user) - ..() - user << "[src] is [anchored ? "":"not "]secured to the floor." - -/////////////////////// -// CLOCKWORK EFFECTS // -/////////////////////// - -/obj/effect/clockwork - name = "meme machine" - desc = "Still don't know what it is." - var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description - icon = 'icons/effects/clockwork_effects.dmi' - icon_state = "ratvars_flame" - anchored = 1 - density = 0 - opacity = 0 - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - -/obj/effect/clockwork/New() - ..() - all_clockwork_objects += src - -/obj/effect/clockwork/Destroy() - all_clockwork_objects -= src - return ..() - -/obj/effect/clockwork/examine(mob/user) - if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc) - desc = clockwork_desc - ..() - desc = initial(desc) - - -/obj/effect/clockwork/spatial_gateway //Spatial gateway: A usually one-way rift to another location. - name = "spatial gateway" - desc = "A gently thrumming tear in reality." - clockwork_desc = "A gateway in reality." - icon_state = "spatial_gateway" - density = 1 - var/sender = TRUE //If this gateway is made for sending, not receiving - var/both_ways = FALSE - var/lifetime = 25 //How many deciseconds this portal will last - var/uses = 1 //How many objects or mobs can go through the portal - var/obj/effect/clockwork/spatial_gateway/linked_gateway //The gateway linked to this one - -/obj/effect/clockwork/spatial_gateway/New() - ..() - spawn(1) - if(!linked_gateway) - qdel(src) - return 0 - if(both_ways) - clockwork_desc = "A gateway in reality. It can both send and receive objects." - else - clockwork_desc = "A gateway in reality. It can only [sender ? "send" : "receive"] objects." - QDEL_IN(src, lifetime) - -//set up a gateway with another gateway -/obj/effect/clockwork/spatial_gateway/proc/setup_gateway(obj/effect/clockwork/spatial_gateway/gatewayB, set_duration, set_uses, two_way) - if(!gatewayB || !set_duration || !uses) - return 0 - linked_gateway = gatewayB - gatewayB.linked_gateway = src - if(two_way) - both_ways = TRUE - gatewayB.both_ways = TRUE - else - sender = TRUE - gatewayB.sender = FALSE - gatewayB.density = FALSE - lifetime = set_duration - gatewayB.lifetime = set_duration - uses = set_uses - gatewayB.uses = set_uses - return 1 - -/obj/effect/clockwork/spatial_gateway/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "It has [uses] uses remaining." - -/obj/effect/clockwork/spatial_gateway/attack_ghost(mob/user) - if(linked_gateway) - user.forceMove(get_turf(linked_gateway)) - ..() - -/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user) - if(!uses) - return 0 - if(user.pulling && user.a_intent == "grab" && isliving(user.pulling)) - var/mob/living/L = user.pulling - if(L.buckled || L.anchored || L.has_buckled_mobs()) - return 0 - user.visible_message("[user] shoves [L] into [src]!", "You shove [L] into [src]!") - user.stop_pulling() - pass_through_gateway(L) - return 1 - if(!user.canUseTopic(src)) - return 0 - user.visible_message("[user] climbs through [src]!", "You brace yourself and step through [src]...") - pass_through_gateway(user) - return 1 - -/obj/effect/clockwork/spatial_gateway/attackby(obj/item/I, mob/living/user, params) - if(istype(I, /obj/item/weapon/nullrod)) - user.visible_message("[user] dispels [src] with [I]!", "You close [src] with [I]!") - qdel(linked_gateway) - qdel(src) - return 1 - if(istype(I, /obj/item/clockwork/slab)) - user << "\"I don't think you want to drop your slab into that\".\n\"If you really want to, try throwing it.\"" - return 1 - if(user.drop_item() && uses) - user.visible_message("[user] drops [I] into [src]!", "You drop [I] into [src]!") - pass_through_gateway(I) - ..() - -/obj/effect/clockwork/spatial_gateway/ex_act(severity) - if(severity == 1 && uses) - uses = 0 - visible_message("[src] is disrupted!") - animate(src, alpha = 0, transform = matrix()*2, time = 10) - QDEL_IN(src, 10) - linked_gateway.uses = 0 - linked_gateway.visible_message("[linked_gateway] is disrupted!") - animate(linked_gateway, alpha = 0, transform = matrix()*2, time = 10) - QDEL_IN(linked_gateway, 10) - return TRUE - return FALSE - -/obj/effect/clockwork/spatial_gateway/Bumped(atom/A) - ..() - if(isliving(A) || istype(A, /obj/item)) - pass_through_gateway(A) - -/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A) - if(!linked_gateway) - qdel(src) - return 0 - if(!sender) - visible_message("[A] bounces off of [src]!") - return 0 - if(!uses) - return 0 - if(isliving(A)) - var/mob/living/user = A - user << "You pass through [src] and appear elsewhere!" - linked_gateway.visible_message("A shape appears in [linked_gateway] before emerging!") - playsound(src, 'sound/effects/EMPulse.ogg', 50, 1) - playsound(linked_gateway, 'sound/effects/EMPulse.ogg', 50, 1) - transform = matrix() * 1.5 - animate(src, transform = matrix() / 1.5, time = 10) - linked_gateway.transform = matrix() * 1.5 - animate(linked_gateway, transform = matrix() / 1.5, time = 10) - A.forceMove(get_turf(linked_gateway)) - uses = max(0, uses - 1) - linked_gateway.uses = max(0, linked_gateway.uses - 1) - spawn(10) - if(!uses) - qdel(src) - qdel(linked_gateway) - return 1 - -/obj/effect/clockwork/overlay - mouse_opacity = 0 - var/atom/linked - -/obj/effect/clockwork/overlay/examine(mob/user) - if(linked) - linked.examine(user) - -/obj/effect/clockwork/overlay/ex_act() - return FALSE - -/obj/effect/clockwork/overlay/singularity_pull(S, current_size) - return - -/obj/effect/clockwork/overlay/Destroy() - if(linked) - linked = null - ..() - return QDEL_HINT_PUTINPOOL - -/obj/effect/clockwork/overlay/wall - name = "clockwork wall" - icon = 'icons/turf/walls/clockwork_wall.dmi' - icon_state = "clockwork_wall" - canSmoothWith = list(/obj/effect/clockwork/overlay/wall, /obj/structure/falsewall/brass) - smooth = SMOOTH_TRUE - layer = CLOSED_TURF_LAYER - -/obj/effect/clockwork/overlay/wall/New() - ..() - queue_smooth_neighbors(src) - addtimer(GLOBAL_PROC, "queue_smooth", 1, FALSE, src) - -/obj/effect/clockwork/overlay/wall/Destroy() - queue_smooth_neighbors(src) - ..() - return QDEL_HINT_QUEUE - -/obj/effect/clockwork/overlay/floor - icon = 'icons/turf/floors.dmi' - icon_state = "clockwork_floor" - layer = TURF_LAYER - -/obj/effect/clockwork/overlay/floor/bloodcult //this is used by BLOOD CULT, it shouldn't use such a path... - icon_state = "cult" - -/obj/effect/clockwork/general_marker - name = "general marker" - desc = "Some big guy. For you." - clockwork_desc = "One of Ratvar's generals." - alpha = 200 - layer = MASSIVE_OBJ_LAYER - -/obj/effect/clockwork/general_marker/New() - ..() - animate(src, alpha = 0, time = 10) - QDEL_IN(src, 10) - -/obj/effect/clockwork/general_marker/ex_act() - return FALSE - -/obj/effect/clockwork/general_marker/nezbere - name = "Nezbere, the Brass Eidolon" - desc = "A towering colossus clad in nigh-impenetrable brass armor. Its gaze is stern yet benevolent, even upon you." - clockwork_desc = "One of Ratvar's four generals. Nezbere is responsible for the design, testing, and creation of everything in Ratvar's domain." - icon = 'icons/effects/340x428.dmi' - icon_state = "nezbere" - pixel_x = -154 - pixel_y = -198 - -/obj/effect/clockwork/general_marker/sevtug - name = "Sevtug, the Formless Pariah" - desc = "A sinister cloud of purple energy. Looking at it gives you a headache." - clockwork_desc = "One of Ratvar's four generals. Sevtug taught him how to manipulate minds and is one of his oldest allies." - icon = 'icons/effects/211x247.dmi' - icon_state = "sevtug" - pixel_x = -89 - pixel_y = -107 - -/obj/effect/clockwork/general_marker/nzcrentr - name = "Nzcrentr, the Eternal Thunderbolt" - desc = "A terrifying spiked construct crackling with limitless energy." - clockwork_desc = "One of Ratvar's four generals. Before becoming one of Ratvar's generals, Nzcrentr sook out any and all sentient life to slaughter it for sport. \ - Nzcrentr was coerced by Ratvar into entering a shell constructed by Nezbere, ostensibly made to grant Nzcrentr more power. In reality, the shell was made to trap and control it. \ - Nzcrentr now serves loyally, though even one of Nezbere's finest creations was not enough to totally eliminate its will." - icon = 'icons/effects/254x361.dmi' - icon_state = "nzcrentr" - pixel_x = -111 - pixel_y = -164 - -/obj/effect/clockwork/general_marker/inathneq - name = "Inath-neq, the Resonant Cogwheel" - desc = "A humanoid form blazing with blue fire. It radiates an aura of kindness and caring." - clockwork_desc = "One of Ratvar's four generals. Before her current form, Inath-neq was a powerful warrior priestess commanding the Resonant Cogs, a sect of Ratvarian warriors renowned for \ - their prowess. After a lost battle with Nar-Sian cultists, Inath-neq was struck down and stated in her dying breath, \ - \"The Resonant Cogs shall not fall silent this day, but will come together to form a wheel that shall never stop turning.\" Ratvar, touched by this, granted Inath-neq an eternal body and \ - merged her soul with those of the Cogs slain with her on the battlefield." - icon = 'icons/effects/187x381.dmi' - icon_state = "inath-neq" - pixel_x = -77 - pixel_y = -174 - - -/obj/effect/clockwork/sigil //Sigils: Rune-like markings on the ground with various effects. - name = "sigil" - desc = "A strange set of markings drawn on the ground." - clockwork_desc = "A sigil of some purpose." - icon_state = "sigil" - layer = LOW_OBJ_LAYER - alpha = 50 - resistance_flags = NONE - var/affects_servants = FALSE - var/stat_affected = CONSCIOUS - var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]" - -/obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params) - if(I.force && !is_servant_of_ratvar(user)) - user.visible_message("[user] scatters [src] with [I]!", "You scatter [src] with [I]!") - qdel(src) - return 1 - ..() - -/obj/effect/clockwork/sigil/attack_hand(mob/user) - if(iscarbon(user) && !user.stat && (!is_servant_of_ratvar(user) || (is_servant_of_ratvar(user) && user.a_intent == "harm"))) - user.visible_message("[user] stamps out [src]!", "You stomp on [src], scattering it into thousands of particles.") - qdel(src) - return 1 - ..() - -/obj/effect/clockwork/sigil/ex_act(severity) - visible_message("[src] scatters into thousands of particles.") - qdel(src) - -/obj/effect/clockwork/sigil/Crossed(atom/movable/AM) - ..() - if(isliving(AM)) - var/mob/living/L = AM - if(L.stat <= stat_affected) - if((!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && affects_servants)) && L.mind) - if(L.null_rod_check()) - var/obj/item/I = L.null_rod_check() - L.visible_message("[L]'s [I.name] [resist_string], protecting them from [src]'s effects!", \ - "Your [I.name] [resist_string], protecting you!") - return - sigil_effects(L) - return 1 - -/obj/effect/clockwork/sigil/proc/sigil_effects(mob/living/L) - -/obj/effect/clockwork/sigil/transgression //Sigil of Transgression: Stuns and flashes the first non-servant to walk on it. Nar-Sian cultists are damaged and knocked down for a longer stun - name = "dull sigil" - desc = "A dull, barely-visible golden sigil. It's as though light was carved into the ground." - icon = 'icons/effects/clockwork_effects.dmi' - clockwork_desc = "A sigil that will stun the first non-servant to cross it. Nar-Sie's dogs will be knocked down." - icon_state = "sigildull" - color = "#FAE48C" - -/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L) - var/target_flashed = L.flash_act() - for(var/mob/living/M in viewers(5, src)) - if(!is_servant_of_ratvar(M) && M != L) - M.flash_act() - if(iscultist(L)) - L << "\"Watch your step, wretch.\"" - L.adjustBruteLoss(10) - L.Weaken(7) - L.visible_message("[src] appears around [L] in a burst of light!", \ - "[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!") - L.Stun(5) - PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/transgression, get_turf(src)) - qdel(src) - return 1 - -/obj/effect/clockwork/sigil/submission //Sigil of Submission: After a short time, converts any non-servant standing on it. Knocks down and silences them for five seconds afterwards. - name = "ominous sigil" - desc = "A luminous golden sigil. Something about it really bothers you." - clockwork_desc = "A sigil that will enslave the first person to cross it, provided they remain on it for seven seconds." - icon_state = "sigilsubmission" - color = "#FAE48C" - alpha = 125 - stat_affected = UNCONSCIOUS - resist_string = "glows faintly yellow" - var/convert_time = 70 - var/glow_light = 2 //soft light - var/glow_falloff = 1 - var/delete_on_finish = TRUE - var/sigil_name = "Sigil of Submission" - var/glow_type - -/obj/effect/clockwork/sigil/submission/New() - ..() - SetLuminosity(glow_light,glow_falloff) - -/obj/effect/clockwork/sigil/submission/proc/post_channel(mob/living/L) - -/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L) - L.visible_message("[src] begins to glow a piercing magenta!", "You feel something start to invade your mind...") - animate(src, color = "#AF0AAF", time = convert_time) - var/obj/effect/overlay/temp/ratvar/sigil/glow - if(glow_type) - glow = PoolOrNew(glow_type, get_turf(src)) - animate(glow, alpha = 255, time = convert_time) - var/I = 0 - while(I < convert_time && get_turf(L) == get_turf(src)) - I++ - sleep(1) - if(get_turf(L) != get_turf(src)) - if(glow) - qdel(glow) - animate(src, color = initial(color), time = 20) - visible_message("[src] slowly stops glowing!") - return 0 - post_channel(L) - if(is_eligible_servant(L)) - L << "\"You belong to me now.\"" - add_servant_of_ratvar(L) - L.Weaken(3) //Completely defenseless for about five seconds - mainly to give them time to read over the information they've just been presented with - L.Stun(3) - if(iscarbon(L)) - var/mob/living/carbon/C = L - C.silent += 5 - var/message = "[sigil_name] in [get_area(src)] [is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]" - for(var/M in mob_list) - if(isobserver(M)) - var/link = FOLLOW_LINK(M, L) - M << "[link] [message] [L.real_name]!" - else if(is_servant_of_ratvar(M)) - if(M == L) - M << "[message] you!" - else - M << "[message] [L.real_name]!" - if(delete_on_finish) - qdel(src) - else - animate(src, color = initial(color), time = 20) - visible_message("[src] slowly stops glowing!") - return 1 - -/obj/effect/clockwork/sigil/submission/accession //Sigil of Accession: After a short time, converts any non-servant standing on it though implants. Knocks down and silences them for five seconds afterwards. - name = "terrifying sigil" - desc = "A luminous brassy sigil. Something about it makes you want to flee." - clockwork_desc = "A sigil that will enslave any person who crosses it, provided they remain on it for seven seconds. \n\ - It can convert a mindshielded target once before disppearing, but can convert any number of non-implanted targets." - icon_state = "sigiltransgression" - color = "#A97F1B" - alpha = 200 - glow_light = 4 //bright light - glow_falloff = 3 - delete_on_finish = FALSE - sigil_name = "Sigil of Accession" - glow_type = /obj/effect/overlay/temp/ratvar/sigil/accession - resist_string = "glows bright orange" - -/obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L) - if(L.isloyal()) - var/mob/living/carbon/C = L - delete_on_finish = TRUE - C.visible_message("[C] visibly trembles!", \ - "[text2ratvar("You will be mine and his. This puny trinket will not stop me.")]") - for(var/obj/item/weapon/implant/mindshield/M in C.implants) - qdel(M) - -/obj/effect/clockwork/sigil/transmission - name = "suspicious sigil" - desc = "A glowing orange sigil. The air around it feels staticky." - clockwork_desc = "A sigil that will serve as a battery for clockwork structures. Use Volt Void while standing on it to charge it." - icon_state = "sigiltransmission" - color = "#EC8A2D" - alpha = 50 - resist_string = "glows faintly" - var/power_charge = REPLICANT_ALLOY_POWER //starts with REPLICANT_ALLOY_POWER by default - -/obj/effect/clockwork/sigil/transmission/ex_act(severity) - if(severity == 3) - modify_charge(-500) - visible_message("[src] flares a brilliant orange!") - else - ..() - -/obj/effect/clockwork/sigil/transmission/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "It is storing [power_charge]W of power." - -/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L) - if(power_charge) - L << "You feel a slight, static shock." - return 1 - -/obj/effect/clockwork/sigil/transmission/New() - ..() - alpha = min(initial(alpha) + power_charge*0.02, 255) - -/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount) - if(power_charge - amount < 0) - return 0 - power_charge -= amount - alpha = min(initial(alpha) + power_charge*0.02, 255) - return 1 - -/obj/effect/clockwork/sigil/vitality - name = "comforting sigil" - desc = "A faint blue sigil. Looking at it makes you feel protected." - clockwork_desc = "A sigil that will drain non-servants that remain on it. Servants that remain on it will be healed if it has any vitality drained." - icon_state = "sigilvitality" - color = "#123456" - alpha = 75 - affects_servants = TRUE - stat_affected = DEAD - resist_string = "glows shimmering yellow" - var/vitality = 0 - var/base_revive_cost = 20 - var/sigil_active = FALSE - var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets - -/obj/effect/clockwork/sigil/vitality/examine(mob/user) - ..() - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "It is storing [ratvar_awakens ? "INFINITE":"[vitality]"] units of vitality." - user << "It requires at least [base_revive_cost] units of vitality to revive dead servants, in addition to any damage the servant has." - -/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L) - if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active) - return 0 - visible_message("[src] begins to glow bright blue!") - animate(src, alpha = 255, time = 10) - sleep(10) - sigil_active = TRUE -//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality - while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && vitality)) && get_turf(L) == get_turf(src)) - if(animation_number >= 4) - PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/vitality, get_turf(src)) - animation_number = 0 - animation_number++ - if(!is_servant_of_ratvar(L)) - var/vitality_drained = 0 - if(L.stat == DEAD) - vitality_drained = L.maxHealth - var/obj/effect/overlay/temp/ratvar/sigil/vitality/V = PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/vitality, get_turf(src)) - animate(V, alpha = 0, transform = matrix()*2, time = 8) - playsound(L, 'sound/magic/WandODeath.ogg', 50, 1) - L.visible_message("[L] collapses in on [L.p_them()]self as [src] flares bright blue!") - L << "\"[text2ratvar("Your life will not be wasted.")]\"" - for(var/obj/item/W in L) - if(!L.unEquip(W)) - qdel(W) - L.dust() - else - vitality_drained = L.adjustToxLoss(1.5) - if(vitality_drained) - vitality += vitality_drained - else - break - else - var/clone_to_heal = L.getCloneLoss() - var/tox_to_heal = L.getToxLoss() - var/burn_to_heal = L.getFireLoss() - var/brute_to_heal = L.getBruteLoss() - var/oxy_to_heal = L.getOxyLoss() - var/total_damage = clone_to_heal + tox_to_heal + burn_to_heal + brute_to_heal + oxy_to_heal - if(L.stat == DEAD) - var/revival_cost = base_revive_cost + total_damage - oxy_to_heal //ignores oxygen damage - if(ratvar_awakens) - revival_cost = 0 - var/mob/dead/observer/ghost = L.get_ghost(TRUE) - if(ghost) - if(vitality >= revival_cost) - ghost.reenter_corpse() - L.revive(1, 1) - playsound(L, 'sound/magic/Staff_Healing.ogg', 50, 1) - L.visible_message("[L] suddenly gets back up, [L.p_their()] mouth dripping blue ichor!", \ - "\"[text2ratvar("You will be okay, child.")]\"") - vitality -= revival_cost - break - else - break - if(!total_damage) - break - var/vitality_for_cycle = min(vitality, 3) - var/vitality_used = 0 - if(ratvar_awakens) - vitality_for_cycle = 3 - - if(clone_to_heal && vitality_for_cycle) - var/healing = min(vitality_for_cycle, clone_to_heal) - vitality_for_cycle -= healing - L.adjustCloneLoss(-healing) - vitality_used += healing - - if(tox_to_heal && vitality_for_cycle) - var/healing = min(vitality_for_cycle, tox_to_heal) - vitality_for_cycle -= healing - L.adjustToxLoss(-healing) - vitality_used += healing - - if(burn_to_heal && vitality_for_cycle) - var/healing = min(vitality_for_cycle, burn_to_heal) - vitality_for_cycle -= healing - L.adjustFireLoss(-healing) - vitality_used += healing - - if(brute_to_heal && vitality_for_cycle) - var/healing = min(vitality_for_cycle, brute_to_heal) - vitality_for_cycle -= healing - L.adjustBruteLoss(-healing) - vitality_used += healing - - if(oxy_to_heal && vitality_for_cycle) - var/healing = min(vitality_for_cycle, oxy_to_heal) - vitality_for_cycle -= healing - L.adjustOxyLoss(-healing) - vitality_used += healing - - if(!ratvar_awakens) - vitality -= vitality_used - sleep(2) - - animation_number = initial(animation_number) - sigil_active = FALSE - animate(src, alpha = initial(alpha), time = 20) - visible_message("[src] slowly stops glowing!") diff --git a/code/game/gamemodes/clock_cult/clock_ratvar.dm b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm similarity index 51% rename from code/game/gamemodes/clock_cult/clock_ratvar.dm rename to code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm index 08a445033c0..30cbd5851be 100644 --- a/code/game/gamemodes/clock_cult/clock_ratvar.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm @@ -1,21 +1,3 @@ -/obj/structure/destructible/clockwork/massive //For objects that are typically very large - name = "massive construct" - desc = "A very large construction." - layer = MASSIVE_OBJ_LAYER - density = FALSE - resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - -/obj/structure/destructible/clockwork/massive/New() - ..() - poi_list += src - -/obj/structure/destructible/clockwork/massive/Destroy() - poi_list -= src - return ..() - -/obj/structure/destructible/clockwork/massive/singularity_pull(S, current_size) - return - /obj/structure/destructible/clockwork/massive/celestial_gateway //The gateway to Reebe, from which Ratvar emerges name = "Gateway to the Celestial Derelict" desc = "A massive, thrumming rip in spacetime." @@ -88,6 +70,28 @@ else if(GATEWAY_RATVAR_ARRIVAL - progress_in_seconds > 0) . = "[round(max((GATEWAY_RATVAR_ARRIVAL - progress_in_seconds) / (GATEWAY_SUMMON_RATE * 0.5), 0), 1)][s_on_time ? "S":""]" +/obj/structure/destructible/clockwork/massive/celestial_gateway/examine(mob/user) + icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon + ..() + icon_state = initial(icon_state) + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "Seconds until [ratvar_portal ? "Ratvar's arrival":"Proselytization"]: [get_arrival_text(TRUE)]" + switch(progress_in_seconds) + if(-INFINITY to GATEWAY_REEBE_FOUND) + user << "It's still opening." + if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING) + user << "It's reached the Celestial Derelict and is drawing power from it." + if(GATEWAY_RATVAR_COMING to INFINITY) + user << "[ratvar_portal ? "Ratvar is coming through the gateway":"The gateway is glowing with massed power"]!" + else + switch(progress_in_seconds) + if(-INFINITY to GATEWAY_REEBE_FOUND) + user << "It's a swirling mass of blackness." + if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING) + user << "It seems to be leading somewhere." + if(GATEWAY_RATVAR_COMING to INFINITY) + user << "[ratvar_portal ? "Something is coming through":"It's glowing brightly"]!" + /obj/structure/destructible/clockwork/massive/celestial_gateway/process() if(!progress_in_seconds || prob(7)) for(var/M in mob_list) @@ -154,181 +158,10 @@ if(M.stat == CONSCIOUS) clockwork_say(M, text2ratvar(pick("Purge all untruths and honor Engine!", "All glory to Engine's light!", "Engine's power is unmatched!"))) -/obj/structure/destructible/clockwork/massive/celestial_gateway/examine(mob/user) - icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon - ..() - icon_state = initial(icon_state) - if(is_servant_of_ratvar(user) || isobserver(user)) - user << "Seconds until [ratvar_portal ? "Ratvar's arrival":"Proselytization"]: [get_arrival_text(TRUE)]" - switch(progress_in_seconds) - if(-INFINITY to GATEWAY_REEBE_FOUND) - user << "It's still opening." - if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING) - user << "It's reached the Celestial Derelict and is drawing power from it." - if(GATEWAY_RATVAR_COMING to INFINITY) - user << "[ratvar_portal ? "Ratvar is coming through the gateway":"The gateway is glowing with massed power"]!" - else - switch(progress_in_seconds) - if(-INFINITY to GATEWAY_REEBE_FOUND) - user << "It's a swirling mass of blackness." - if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING) - user << "It seems to be leading somewhere." - if(GATEWAY_RATVAR_COMING to INFINITY) - user << "[ratvar_portal ? "Something is coming through":"It's glowing brightly"]!" - -/obj/effect/clockwork/overlay/gateway_glow //the actual appearance of the Gateway to the Celestial Derelict; an object so the edges of the gate can be clicked through. +//the actual appearance of the Gateway to the Celestial Derelict; an object so the edges of the gate can be clicked through. +/obj/effect/clockwork/overlay/gateway_glow icon = 'icons/effects/96x96.dmi' icon_state = "clockwork_gateway_charging" pixel_x = -32 pixel_y = -32 layer = MASSIVE_OBJ_LAYER - - -/obj/structure/destructible/clockwork/massive/ratvar - name = "Ratvar, the Clockwork Justiciar" - desc = "What is what is what are what real what is all a lie all a lie it's all a lie why how can what is" - clockwork_desc = "Ratvar, the Clockwork Justiciar, your master eternal." - icon = 'icons/effects/512x512.dmi' - icon_state = "ratvar" - pixel_x = -235 - pixel_y = -248 - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - appearance_flags = 0 - var/atom/prey //Whatever Ratvar is chasing - var/clashing = FALSE //If Ratvar is FUCKING FIGHTING WITH NAR-SIE - var/proselytize_range = 10 - -/obj/structure/destructible/clockwork/massive/ratvar/New() - ..() - ratvar_awakens++ - for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects) - R.update_force() - START_PROCESSING(SSobj, src) - world << "\"[text2ratvar("ONCE AGAIN MY LIGHT SHALL SHINE ACROSS THIS PATHETIC REALM")]!!\"" - world << 'sound/effects/ratvar_reveal.ogg' - var/image/alert_overlay = image('icons/effects/clockwork_effects.dmi', "ratvar_alert") - var/area/A = get_area(src) - notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [A.name] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay) - addtimer(SSshuttle.emergency, "request", 50, FALSE, null, 0.1) - - -/obj/structure/destructible/clockwork/massive/ratvar/Destroy() - ratvar_awakens-- - for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects) - R.update_force() - STOP_PROCESSING(SSobj, src) - world << "\"NO! I will not... be... banished... again...\"" - return ..() - - -/obj/structure/destructible/clockwork/massive/ratvar/attack_ghost(mob/dead/observer/O) - var/alertresult = alert(O, "Embrace the Justiciar's light? You can no longer be cloned!",,"Yes", "No") - if(alertresult == "No" || !O) - return 0 - var/mob/living/simple_animal/drone/cogscarab/ratvar/R = new/mob/living/simple_animal/drone/cogscarab/ratvar(get_turf(src)) - R.visible_message("[R] forms, and its eyes blink open, glowing bright red!") - R.key = O.key - - -/obj/structure/destructible/clockwork/massive/ratvar/Bump(atom/A) - var/turf/T = get_turf(A) - forceMove(T) - T.ratvar_act() - - -/obj/structure/destructible/clockwork/massive/ratvar/Process_Spacemove() - return clashing - - -/obj/structure/destructible/clockwork/massive/ratvar/process() - if(clashing) //I'm a bit occupied right now, thanks - return - for(var/I in circlerangeturfs(src, proselytize_range)) - var/turf/T = I - T.ratvar_act() - for(var/I in circleviewturfs(src, round(proselytize_range * 0.5))) - var/turf/T = I - T.ratvar_act(1) - var/dir_to_step_in = pick(cardinal) - if(!prey) - for(var/obj/singularity/narsie/N in poi_list) - if(N.z == z) - prey = N - break - if(!prey) //In case there's a Nar-Sie - var/list/meals = list() - for(var/mob/living/L in living_mob_list) - if(L.z == z && !is_servant_of_ratvar(L) && L.mind) - meals += L - if(meals.len) - prey = pick(meals) - prey << "\"You will do.\"\n\ - Something very large and very malevolent begins lumbering its way towards you..." - prey << 'sound/effects/ratvar_reveal.ogg' - else - if(prob(10) || is_servant_of_ratvar(prey) || prey.z != z) - prey << "\"How dull. Leave me.\"\n\ - You feel tremendous relief as a set of horrible eyes loses sight of you..." - prey = null - else - dir_to_step_in = get_dir(src, prey) //Unlike Nar-Sie, Ratvar ruthlessly chases down his target - step(src, dir_to_step_in) - -/obj/structure/destructible/clockwork/massive/ratvar/narsie_act() - if(clashing) - return 0 - clashing = TRUE - world << "\"[pick("BLOOD GOD!!!", "NAR-SIE!!!", "AT LAST, YOUR TIME HAS COME!")]\"" - world << "\"Ratvar?! How?!\"" - for(var/obj/singularity/narsie/N in range(15, src)) - if(N.clashing) - continue - N.clashing = TRUE - clash_of_the_titans(N) //IT'S TIME FOR THE BATTLE OF THE AGES - break - return 1 - -/obj/structure/destructible/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie) - var/winner = "Undeclared" - var/base_victory_chance = 1 - while(TRUE) - world << 'sound/magic/clockwork/ratvar_attack.ogg' - sleep(5.2) - for(var/mob/M in mob_list) - flash_color(M, flash_color="#966400", flash_time=1) - shake_camera(M, 4, 3) - var/ratvar_chance = min(ticker.mode.servants_of_ratvar.len, 50) - var/narsie_chance = ticker.mode.cult.len - for(var/mob/living/simple_animal/hostile/construct/harvester/C in player_list) - narsie_chance++ - ratvar_chance = rand(base_victory_chance, ratvar_chance) - narsie_chance = rand(base_victory_chance, min(narsie_chance, 50)) - if(ratvar_chance > narsie_chance) - winner = "Ratvar" - break - sleep(rand(2,5)) - world << 'sound/magic/clockwork/narsie_attack.ogg' - sleep(7.4) - for(var/mob/M in mob_list) - flash_color(M, flash_color="#C80000", flash_time=1) - shake_camera(M, 4, 3) - if(narsie_chance > ratvar_chance) - winner = "Nar-Sie" - break - base_victory_chance *= 2 //The clash has a higher chance of resolving each time both gods attack one another - switch(winner) - if("Ratvar") - world << "\"[pick("DIE! DIE! DIE!", "FILTH!!!", "SUFFER!!!", text2ratvar("ROT FOR CENTURIES AS I HAVE!!"))]\"" //nar-sie get out - world << "\"[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"" - world << 'sound/magic/clockwork/anima_fragment_attack.ogg' - world << 'sound/magic/demon_dies.ogg' - clashing = FALSE - qdel(narsie) - return 1 - if("Nar-Sie") - world << "\"[pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here.")]\"" //Broken English - world << 'sound/magic/demon_attack1.ogg' - world << 'sound/magic/clockwork/anima_fragment_death.ogg' - narsie.clashing = FALSE - qdel(src) - return 1 diff --git a/code/game/gamemodes/clock_cult/clock_structures/clock_shells.dm b/code/game/gamemodes/clock_cult/clock_structures/clock_shells.dm new file mode 100644 index 00000000000..c69b56908a0 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/clock_shells.dm @@ -0,0 +1,47 @@ +//Useless on their own, these shells can create powerful constructs. +/obj/structure/destructible/clockwork/shell + construction_value = 0 + anchored = 0 + density = 0 + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + var/mobtype = /mob/living/simple_animal/hostile/clockwork + var/spawn_message = " is an error and you should yell at whoever spawned this shell." + +/obj/structure/destructible/clockwork/shell/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/device/mmi/posibrain/soul_vessel)) + if(!is_servant_of_ratvar(user)) + ..() + return 0 + var/obj/item/device/mmi/posibrain/soul_vessel/S = I + if(!S.brainmob) + user << "[S] hasn't trapped a spirit! Turn it on first." + return 0 + if(S.brainmob && (!S.brainmob.client || !S.brainmob.mind)) + user << "[S]'s trapped spirit appears inactive!" + return 0 + user.visible_message("[user] places [S] in [src], where it fuses to the shell.", "You place [S] in [src], fusing it to the shell.") + var/mob/living/simple_animal/A = new mobtype(get_turf(src)) + A.visible_message("[src][spawn_message]") + S.brainmob.mind.transfer_to(A) + user.drop_item() + qdel(S) + qdel(src) + return 1 + else + return ..() + +/obj/structure/destructible/clockwork/shell/cogscarab + name = "cogscarab shell" + desc = "A small brass shell with a cube-shaped receptable in its center. It gives off an aura of obsessive perfectionism." + clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt proselytizer." + icon_state = "clockdrone_shell" + mobtype = /mob/living/simple_animal/drone/cogscarab + spawn_message = "'s eyes blink open, glowing bright red." + +/obj/structure/destructible/clockwork/shell/fragment + name = "fragment shell" + desc = "A massive brass shell with a small cube-shaped receptable in its center. It gives off an aura of contained power." + clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a powerful construct." + icon_state = "anime_fragment" + mobtype = /mob/living/simple_animal/hostile/clockwork/fragment + spawn_message = " whirs and rises from the ground on a flickering jet of reddish fire." diff --git a/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm b/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm new file mode 100644 index 00000000000..28934bb6475 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm @@ -0,0 +1,69 @@ +//Clockwork Obelisk: Can broadcast a message at a small power cost or outright open a spatial gateway at a massive power cost. +/obj/structure/destructible/clockwork/powered/clockwork_obelisk + name = "clockwork obelisk" + desc = "A large brass obelisk hanging in midair." + clockwork_desc = "A powerful obelisk that can send a message to all servants or open a gateway to a target servant or clockwork obelisk." + icon_state = "obelisk_inactive" + active_icon = "obelisk" + inactive_icon = "obelisk_inactive" + construction_value = 20 + max_integrity = 150 + obj_integrity = 150 + break_message = "The obelisk falls to the ground, undamaged!" + debris = list(/obj/item/clockwork/alloy_shards/small = 3, \ + /obj/item/clockwork/component/hierophant_ansible/obelisk = 1) + var/hierophant_cost = MIN_CLOCKCULT_POWER //how much it costs to broadcast with large text + var/gateway_cost = 2000 //how much it costs to open a gateway + var/gateway_active = FALSE + +/obj/structure/destructible/clockwork/powered/clockwork_obelisk/New() + ..() + toggle(1) + +/obj/structure/destructible/clockwork/powered/clockwork_obelisk/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "It requires [hierophant_cost]W to broadcast over the Hierophant Network, and [gateway_cost]W to open a Spatial Gateway." + +/obj/structure/destructible/clockwork/powered/clockwork_obelisk/process() + if(locate(/obj/effect/clockwork/spatial_gateway) in loc) + icon_state = active_icon + density = 0 + gateway_active = TRUE + else + icon_state = inactive_icon + density = 1 + gateway_active = FALSE + +/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user) + if(!is_servant_of_ratvar(user) || !total_accessable_power() >= hierophant_cost) + user << "You place your hand on the obelisk, but it doesn't react." + return + var/choice = alert(user,"You place your hand on the obelisk...",,"Hierophant Broadcast","Spatial Gateway","Cancel") + switch(choice) + if("Hierophant Broadcast") + if(gateway_active) + user << "The obelisk is sustaining a gateway and cannot broadcast!" + return + var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "") + if(!input || !user.canUseTopic(src, BE_CLOSE)) + return + if(gateway_active) + user << "The obelisk is sustaining a gateway and cannot broadcast!" + return + if(!try_use_power(hierophant_cost)) + user << "The obelisk lacks the power to broadcast!" + return + clockwork_say(user, text2ratvar("Hierophant Broadcast, activate!")) + titled_hierophant_message(user, input, "big_brass", "large_brass") + if("Spatial Gateway") + if(gateway_active) + user << "The obelisk is already sustaining a gateway!" + return + if(!try_use_power(gateway_cost)) + user << "The obelisk lacks the power to open a gateway!" + return + if(procure_gateway(user, 100, 5, 1) && !gateway_active) + clockwork_say(user, text2ratvar("Spatial Gateway, activate!")) + else + return_power(gateway_cost) diff --git a/code/game/gamemodes/clock_cult/clock_structures/interdiction_lens.dm b/code/game/gamemodes/clock_cult/clock_structures/interdiction_lens.dm new file mode 100644 index 00000000000..d88452b1baf --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/interdiction_lens.dm @@ -0,0 +1,96 @@ +//Interdiction Lens: A powerful artifact that constantly disrupts electronics and drains power but, if it fails to find something to disrupt, turns off. +/obj/structure/destructible/clockwork/powered/interdiction_lens + name = "interdiction lens" + desc = "An ominous, double-pronged brass totem. There's a strange gemstone clasped between the pincers." + clockwork_desc = "A powerful totem that constantly drains nearby electronics and funnels the power drained into nearby Sigils of Transmission." + icon_state = "interdiction_lens" + construction_value = 25 + active_icon = "interdiction_lens_active" + inactive_icon = "interdiction_lens" + break_message = "The lens flares a blinding violet before shattering!" + break_sound = 'sound/effects/Glassbr3.ogg' + var/recharging = 0 //world.time when the lens was last used + var/recharge_time = 1200 //if it drains no power and affects no objects, it turns off for two minutes + var/disabled = FALSE //if it's actually usable + var/interdiction_range = 14 //how large an area it drains and disables in + +/obj/structure/destructible/clockwork/powered/interdiction_lens/examine(mob/user) + ..() + user << "Its gemstone [recharging > world.time ? "has been breached by writhing tendrils of blackness that cover the totem" \ + : "vibrates in place and thrums with power"]." + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "If it fails to drain any electronics, it will disable itself for [round(recharge_time/600, 1)] minutes." + +/obj/structure/destructible/clockwork/powered/interdiction_lens/toggle(fast_process, mob/living/user) + ..() + if(active) + SetLuminosity(4,2) + else + SetLuminosity(0) + +/obj/structure/destructible/clockwork/powered/interdiction_lens/attack_hand(mob/living/user) + if(user.canUseTopic(src, BE_CLOSE)) + if(disabled) + user << "As you place your hand on the gemstone, cold tendrils of black matter crawl up your arm. You quickly pull back." + return 0 + toggle(0, user) + +/obj/structure/destructible/clockwork/powered/interdiction_lens/process() + if(recharging > world.time) + return + if(disabled) + visible_message("The writhing tendrils return to the gemstone, which begins to glow with power!") + flick("interdiction_lens_recharged", src) + disabled = FALSE + toggle(0) + else + var/successfulprocess = FALSE + var/power_drained = 0 + var/list/atoms_to_test = list() + for(var/A in spiral_range_turfs(interdiction_range, src)) + var/turf/T = A + for(var/M in T) + atoms_to_test |= M + + CHECK_TICK + + for(var/M in atoms_to_test) + var/atom/movable/A = M + if(!A || qdeleted(A)) + continue + power_drained += A.power_drain(TRUE) + + if(istype(A, /obj/machinery/camera)) + var/obj/machinery/camera/C = A + if(C.isEmpProof() || !C.status) + continue + successfulprocess = TRUE + if(C.emped) + continue + C.emp_act(1) + else if(istype(A, /obj/item/device/radio)) + var/obj/item/device/radio/O = A + successfulprocess = TRUE + if(O.emped || !O.on) + continue + O.emp_act(1) + else if((isliving(A) && !is_servant_of_ratvar(A)) || istype(A, /obj/structure/closet) || istype(A, /obj/item/weapon/storage)) //other things may have radios in them but we don't care + for(var/obj/item/device/radio/O in A.GetAllContents()) + successfulprocess = TRUE + if(O.emped || !O.on) + continue + O.emp_act(1) + + CHECK_TICK + + if(power_drained && power_drained >= MIN_CLOCKCULT_POWER && return_power(power_drained)) + successfulprocess = TRUE + playsound(src, 'sound/items/PSHOOM.ogg', 50, 1, interdiction_range-7, 1) + + if(!successfulprocess) + visible_message("The gemstone suddenly turns horribly dark, writhing tendrils covering it!") + recharging = world.time + recharge_time + flick("interdiction_lens_discharged", src) + icon_state = "interdiction_lens_inactive" + SetLuminosity(2,1) + disabled = TRUE diff --git a/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm b/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm new file mode 100644 index 00000000000..ba004acfb2d --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/mania_motor.dm @@ -0,0 +1,135 @@ +//Mania Motor: A pair of antenna that, while active, cause braindamage and hallucinations in nearby human mobs. +/obj/structure/destructible/clockwork/powered/mania_motor + name = "mania motor" + desc = "A pair of antenna with what appear to be sockets around the base. It reminds you of an antlion." + clockwork_desc = "A transmitter that allows Sevtug to whisper into the minds of nearby non-servants, causing hallucinations and brain damage as long as it remains powered." + icon_state = "mania_motor_inactive" + active_icon = "mania_motor" + inactive_icon = "mania_motor_inactive" + construction_value = 20 + max_integrity = 80 + obj_integrity = 80 + break_message = "The antenna break off, leaving a pile of shards!" + debris = list(/obj/item/clockwork/alloy_shards/large = 1, \ + /obj/item/clockwork/alloy_shards/small = 3, \ + /obj/item/clockwork/component/guvax_capacitor/antennae = 1) + var/mania_cost = 200 + var/convert_attempt_cost = 200 + var/convert_cost = 200 + + var/mania_messages = list("\"Go nuts.\"", "\"Take a crack at crazy.\"", "\"Make a bid for insanity.\"", "\"Get kooky.\"", "\"Move towards mania.\"", "\"Become bewildered.\"", "\"Wax wild.\"", \ + "\"Go round the bend.\"", "\"Land in lunacy.\"", "\"Try dementia.\"", "\"Strive to get a screw loose.\"") + var/compel_messages = list("\"Come closer.\"", "\"Approach the transmitter.\"", "\"Touch the antennae.\"", "\"I always have to deal with idiots. Move towards the mania motor.\"", \ + "\"Advance forward and place your head between the antennae - that's all it's good for.\"", "\"If you were smarter, you'd be over here already.\"", "\"Move FORWARD, you fool.\"") + var/convert_messages = list("\"You won't do. Go to sleep while I tell these nitwits how to convert you.\"", "\"You are insufficient. I must instruct these idiots in the art of conversion.\"", \ + "\"Oh of course, someone we can't convert. These servants are fools.\"", "\"How hard is it to use a Sigil, anyway? All it takes is dragging someone onto it.\"", \ + "\"How do they fail to use a Sigil of Accession, anyway?\"", "\"Why is it that all servants are this inept?\"", "\"It's quite likely you'll be stuck here for a while.\"") + var/close_messages = list("\"Well, you can't reach the motor from THERE, you moron.\"", "\"Interesting location. I'd prefer if you went somewhere you could ACTUALLY TOUCH THE ANTENNAE!\"", \ + "\"Amazing. You somehow managed to wedge yourself somewhere you can't actually reach the motor from.\"", "\"Such a show of idiocy is unparalleled. Perhaps I should put you on display?\"", \ + "\"Did you do this on purpose? I can't imagine you doing so accidentally. Oh, wait, I can.\"", "\"How is it that such smart creatures can still do something AS STUPID AS THIS!\"") + + +/obj/structure/destructible/clockwork/powered/mania_motor/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "It requires [mania_cost]W to run, and [convert_attempt_cost + convert_cost]W to convert humans adjecent to it." + +/obj/structure/destructible/clockwork/powered/mania_motor/process() + if(try_use_power(mania_cost)) + var/turf/T = get_turf(src) + var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected + for(var/mob/living/carbon/human/H in view(1, src)) + if(is_servant_of_ratvar(H)) + continue + if(H.Adjacent(src) && try_use_power(convert_attempt_cost)) + if(is_eligible_servant(H) && try_use_power(convert_cost)) + H << "\"[text2ratvar("You are mine and his, now.")]\"" + H.playsound_local(T, hum, 80, 1) + add_servant_of_ratvar(H) + else if(!H.stat) + if(H.getBrainLoss() >= 100) + H.Paralyse(5) + H << "[text2ratvar(pick(convert_messages))]" + else + H.adjustBrainLoss(100) + H.visible_message("[H] reaches out and touches [src].", "You touch [src] involuntarily.") + else + visible_message("[src]'s antennae fizzle quietly.") + playsound(src, 'sound/effects/light_flicker.ogg', 50, 1) + for(var/mob/living/carbon/human/H in range(10, src)) + if(is_servant_of_ratvar(H)) + if(H.getBrainLoss() || H.hallucination || H.druggy || H.dizziness || H.confused) + H.adjustBrainLoss(-H.getBrainLoss()) //heals servants of braindamage, hallucination, druggy, dizziness, and confusion + H.hallucination = 0 + H.adjust_drugginess(-H.druggy) + H.dizziness = 0 + H.confused = 0 + else if(!H.null_rod_check() && H.stat == CONSCIOUS) + var/distance = get_dist(T, get_turf(H)) + var/falloff_distance = min((110) - distance * 10, 80) + var/sound_distance = falloff_distance * 0.5 + var/targetbrainloss = H.getBrainLoss() + if(distance >= 4 && prob(falloff_distance * 0.5)) + H << "[text2ratvar(pick(mania_messages))]" + H.playsound_local(T, hum, sound_distance, 1) + switch(distance) + if(2 to 3) + if(prob(falloff_distance * 0.5)) + if(prob(falloff_distance)) + H << "[text2ratvar(pick(mania_messages))]" + else + H << "[text2ratvar(pick(compel_messages))]" + if(targetbrainloss <= 50) + H.adjustBrainLoss(50 - targetbrainloss) //got too close had brain eaten + H.adjust_drugginess(Clamp(7, 0, 100 - H.druggy)) + H.hallucination = min(H.hallucination + 7, 100) + H.dizziness = min(H.dizziness + 3, 45) + H.confused = min(H.confused + 3, 45) + if(4 to 5) + if(targetbrainloss <= 50) + H.adjustBrainLoss(1) + H.adjust_drugginess(Clamp(5, 0, 80 - H.druggy)) + H.hallucination = min(H.hallucination + 5, 80) + H.dizziness = min(H.dizziness + 2, 30) + H.confused = min(H.confused + 2, 30) + if(6 to 7) + if(targetbrainloss <= 30) + H.adjustBrainLoss(1) + H.adjust_drugginess(Clamp(2, 0, 60 - H.druggy)) + H.hallucination = min(H.hallucination + 2, 60) + H.dizziness = min(H.dizziness + 2, 15) + H.confused = min(H.confused + 2, 15) + if(8 to 9) + if(targetbrainloss <= 10) + H.adjustBrainLoss(1) + H.adjust_drugginess(Clamp(2, 0, 40 - H.druggy)) + H.hallucination = min(H.hallucination + 2, 40) + if(10 to INFINITY) + H.adjust_drugginess(Clamp(2, 0, 20 - H.druggy)) + H.hallucination = min(H.hallucination + 2, 20) + else //if it's a distance of 1 and they can't see it/aren't adjacent or they're on top of it(how'd they get on top of it and still trigger this???) + if(prob(falloff_distance * 0.5)) + if(prob(falloff_distance)) + H << "[text2ratvar(pick(compel_messages))]" + else if(prob(falloff_distance * 0.5)) + H << "[text2ratvar(pick(close_messages))]" + else + H << "[text2ratvar(pick(mania_messages))]" + if(targetbrainloss <= 99) + H.adjustBrainLoss(99 - targetbrainloss) + H.adjust_drugginess(Clamp(10, 0, 150 - H.druggy)) + H.hallucination = min(H.hallucination + 10, 150) + H.dizziness = min(H.dizziness + 5, 60) + H.confused = min(H.confused + 5, 60) + + else + visible_message("[src] hums loudly, then the sockets at its base fall dark!") + playsound(src, 'sound/effects/screech.ogg', 40, 1) + toggle(0) + +/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user) + if(user.canUseTopic(src, BE_CLOSE) && is_servant_of_ratvar(user)) + if(!total_accessable_power() >= mania_cost) + user << "[src] needs more power to function!" + return 0 + toggle(0, user) diff --git a/code/game/gamemodes/clock_cult/clock_structures/mending_motor.dm b/code/game/gamemodes/clock_cult/clock_structures/mending_motor.dm new file mode 100644 index 00000000000..ab35bf49635 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/mending_motor.dm @@ -0,0 +1,105 @@ +//Mending Motor: A prism that consumes replicant alloy or power to repair nearby mechanical servants at a quick rate. +/obj/structure/destructible/clockwork/powered/mending_motor + name = "mending motor" + desc = "A dark onyx prism, held in midair by spiraling tendrils of stone." + clockwork_desc = "A powerful prism that rapidly repairs nearby mechanical servants and clockwork structures." + icon_state = "mending_motor_inactive" + active_icon = "mending_motor" + inactive_icon = "mending_motor_inactive" + construction_value = 20 + max_integrity = 125 + obj_integrity = 125 + break_message = "The prism collapses with a heavy thud!" + debris = list(/obj/item/clockwork/alloy_shards/small = 5, \ + /obj/item/clockwork/alloy_shards/medium = 1, \ + /obj/item/clockwork/alloy_shards/large = 1, \ + /obj/item/clockwork/component/vanguard_cogwheel = 1) + var/stored_alloy = 0 + var/max_alloy = REPLICANT_ALLOY_POWER * 10 + var/mob_cost = 200 + var/structure_cost = 250 + var/cyborg_cost = 300 + +/obj/structure/destructible/clockwork/powered/mending_motor/prefilled + stored_alloy = REPLICANT_ALLOY_POWER //starts with 1 replicant alloy's worth of power + +/obj/structure/destructible/clockwork/powered/mending_motor/total_accessable_power() + . = ..() + if(. != INFINITY) + . += accessable_alloy_power() + +/obj/structure/destructible/clockwork/powered/mending_motor/proc/accessable_alloy_power() + return stored_alloy + +/obj/structure/destructible/clockwork/powered/mending_motor/use_power(amount) + var/alloypower = accessable_alloy_power() + while(alloypower >= MIN_CLOCKCULT_POWER && amount >= MIN_CLOCKCULT_POWER) + stored_alloy -= MIN_CLOCKCULT_POWER + alloypower -= MIN_CLOCKCULT_POWER + amount -= MIN_CLOCKCULT_POWER + return ..() + +/obj/structure/destructible/clockwork/powered/mending_motor/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + user << "It contains [stored_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER]/[max_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER] units of liquified alloy, \ + which is equivalent to [stored_alloy]W/[max_alloy]W of power." + user << "It requires [mob_cost]W to heal clockwork mobs, [structure_cost]W for clockwork structures, and [cyborg_cost]W for cyborgs." + +/obj/structure/destructible/clockwork/powered/mending_motor/process() + if(..() < mob_cost) + visible_message("[src] emits an airy chuckling sound and falls dark!") + toggle() + return + for(var/atom/movable/M in range(5, src)) + if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab)) + var/mob/living/simple_animal/hostile/clockwork/W = M + var/fatigued = FALSE + if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder)) + var/mob/living/simple_animal/hostile/clockwork/marauder/E = M + if(E.fatigue) + fatigued = TRUE + if((!fatigued && W.health == W.maxHealth) || W.stat) + continue + if(!try_use_power(mob_cost)) + break + W.adjustHealth(-20) + else if(istype(M, /obj/structure/destructible/clockwork)) + var/obj/structure/destructible/clockwork/C = M + if(C.obj_integrity == C.max_integrity) + continue + if(!try_use_power(structure_cost)) + break + C.obj_integrity = min(C.obj_integrity + 20, C.max_integrity) + else if(issilicon(M)) + var/mob/living/silicon/S = M + if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S)) + continue + if(!try_use_power(cyborg_cost)) + break + S.adjustBruteLoss(-20) + S.adjustFireLoss(-10) + return 1 + +/obj/structure/destructible/clockwork/powered/mending_motor/attack_hand(mob/living/user) + if(user.canUseTopic(src, BE_CLOSE)) + if(total_accessable_power() < mob_cost) + user << "[src] needs more power or replicant alloy to function!" + return 0 + toggle(0, user) + +/obj/structure/destructible/clockwork/powered/mending_motor/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user)) + if(stored_alloy + REPLICANT_ALLOY_POWER > max_alloy) + user << "[src] is too full to accept any more alloy!" + return 0 + playsound(user, 'sound/machines/click.ogg', 50, 1) + clockwork_say(user, text2ratvar("Transmute into fuel."), TRUE) + user << "You force [I] to liquify and pour it into [src]'s compartments. \ + It now contains [stored_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER]/[max_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER] units of liquified alloy." + stored_alloy = stored_alloy + REPLICANT_ALLOY_POWER + user.drop_item() + qdel(I) + return 1 + else + return ..() diff --git a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm new file mode 100644 index 00000000000..da8f6f58273 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm @@ -0,0 +1,90 @@ +//Ocular warden: Low-damage, low-range turret. Deals constant damage to whoever it makes eye contact with. +/obj/structure/destructible/clockwork/ocular_warden + name = "ocular warden" + desc = "A large brass eye with tendrils trailing below it and a wide red iris." + clockwork_desc = "A fragile turret that will deal sustained damage to any non-faithful it sees." + icon_state = "ocular_warden" + obj_integrity = 25 + max_integrity = 25 + construction_value = 15 + layer = HIGH_OBJ_LAYER + break_message = "The warden's eye gives a glare of utter hate before falling dark!" + debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye = 1) + resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF + var/damage_per_tick = 2.5 + var/sight_range = 3 + var/atom/movable/target + var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.") + +/obj/structure/destructible/clockwork/ocular_warden/New() + ..() + START_PROCESSING(SSfastprocess, src) + +/obj/structure/destructible/clockwork/ocular_warden/Destroy() + STOP_PROCESSING(SSfastprocess, src) + return ..() + +/obj/structure/destructible/clockwork/ocular_warden/examine(mob/user) + ..() + user << "[target ? "It's fixated on [target]!" : "Its gaze is wandering aimlessly."]" + +/obj/structure/destructible/clockwork/ocular_warden/process() + var/list/validtargets = acquire_nearby_targets() + if(ratvar_awakens && (damage_per_tick == initial(damage_per_tick) || sight_range == initial(sight_range))) //Massive buff if Ratvar has returned + damage_per_tick = 10 + sight_range = 5 + if(target) + if(!(target in validtargets)) + lose_target() + else + if(isliving(target)) + var/mob/living/L = target + if(!L.null_rod_check()) + L.adjustFireLoss(!iscultist(L) ? damage_per_tick : damage_per_tick * 2) //Nar-Sian cultists take additional damage + if(ratvar_awakens && L) + L.adjust_fire_stacks(damage_per_tick) + L.IgniteMob() + else if(istype(target,/obj/mecha)) + var/obj/mecha/M = target + M.take_damage(damage_per_tick, BURN, "melee", 1, get_dir(src, M)) //does about half of standard damage to mechs * whatever their fire armor is + + setDir(get_dir(get_turf(src), get_turf(target))) + if(!target) + if(validtargets.len) + target = pick(validtargets) + visible_message("[src] swivels to face [target]!") + if(isliving(target)) + var/mob/living/L = target + L << "\"I SEE YOU!\"\n[src]'s gaze [ratvar_awakens ? "melts you alive" : "burns you"]!" + else if(istype(target,/obj/mecha)) + var/obj/mecha/M = target + M.occupant << "\"I SEE YOU!\"" //heeeellooooooo, person in mech. + else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes + if(prob(50)) + visible_message("[src][pick(idle_messages)]") + else + setDir(pick(cardinal))//Random rotation + +/obj/structure/destructible/clockwork/ocular_warden/proc/acquire_nearby_targets() + . = list() + for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind + var/obj/item/weapon/storage/book/bible/B = L.bible_check() + if(!is_servant_of_ratvar(L) && !L.stat && L.mind && !(L.disabilities & BLIND) && !L.null_rod_check() && !B) + . += L + else if(B) + if(!(B.resistance_flags & ON_FIRE)) + L << "Your [B.name] bursts into flames!" + for(var/obj/item/weapon/storage/book/bible/BI in L.GetAllContents()) + if(!(BI.resistance_flags & ON_FIRE)) + BI.fire_act() + for(var/N in mechas_list) + var/obj/mecha/M = N + if(get_dist(M, src) <= sight_range && M.occupant && !is_servant_of_ratvar(M.occupant) && (M in view(sight_range, src))) + . += M + +/obj/structure/destructible/clockwork/ocular_warden/proc/lose_target() + if(!target) + return 0 + target = null + visible_message("[src] settles and seems almost disappointed.") + return 1 diff --git a/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm new file mode 100644 index 00000000000..13d5203f775 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm @@ -0,0 +1,143 @@ +//Ratvar himself. Impossible to damage by most standard means, He will dominate the station and all upon it. +/obj/structure/destructible/clockwork/massive/ratvar + name = "Ratvar, the Clockwork Justiciar" + desc = "What is what is what are what real what is all a lie all a lie it's all a lie why how can what is" + clockwork_desc = "Ratvar, the Clockwork Justiciar, your master eternal." + icon = 'icons/effects/512x512.dmi' + icon_state = "ratvar" + pixel_x = -235 + pixel_y = -248 + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + appearance_flags = 0 + var/atom/prey //Whatever Ratvar is chasing + var/clashing = FALSE //If Ratvar is FUCKING FIGHTING WITH NAR-SIE + var/proselytize_range = 10 + +/obj/structure/destructible/clockwork/massive/ratvar/New() + ..() + ratvar_awakens++ + for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects) + R.update_force() + START_PROCESSING(SSobj, src) + world << "\"[text2ratvar("ONCE AGAIN MY LIGHT SHALL SHINE ACROSS THIS PATHETIC REALM")]!!\"" + world << 'sound/effects/ratvar_reveal.ogg' + var/image/alert_overlay = image('icons/effects/clockwork_effects.dmi', "ratvar_alert") + var/area/A = get_area(src) + notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [A.name] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay) + addtimer(SSshuttle.emergency, "request", 50, FALSE, null, 0.1) + +/obj/structure/destructible/clockwork/massive/ratvar/Destroy() + ratvar_awakens-- + for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects) + R.update_force() + STOP_PROCESSING(SSobj, src) + world << "\"NO! I will not... be... banished... again...\"" + return ..() + +/obj/structure/destructible/clockwork/massive/ratvar/attack_ghost(mob/dead/observer/O) + var/alertresult = alert(O, "Embrace the Justiciar's light? You can no longer be cloned!",,"Yes", "No") + if(alertresult == "No" || !O) + return 0 + var/mob/living/simple_animal/drone/cogscarab/ratvar/R = new/mob/living/simple_animal/drone/cogscarab/ratvar(get_turf(src)) + R.visible_message("[R] forms, and its eyes blink open, glowing bright red!") + R.key = O.key + +/obj/structure/destructible/clockwork/massive/ratvar/Bump(atom/A) + var/turf/T = get_turf(A) + forceMove(T) + T.ratvar_act() + +/obj/structure/destructible/clockwork/massive/ratvar/Process_Spacemove() + return clashing + +/obj/structure/destructible/clockwork/massive/ratvar/process() + if(clashing) //I'm a bit occupied right now, thanks + return + for(var/I in circlerangeturfs(src, proselytize_range)) + var/turf/T = I + T.ratvar_act() + for(var/I in circleviewturfs(src, round(proselytize_range * 0.5))) + var/turf/T = I + T.ratvar_act(1) + var/dir_to_step_in = pick(cardinal) + if(!prey) + for(var/obj/singularity/narsie/N in poi_list) + if(N.z == z) + prey = N + break + if(!prey) //In case there's a Nar-Sie + var/list/meals = list() + for(var/mob/living/L in living_mob_list) + if(L.z == z && !is_servant_of_ratvar(L) && L.mind) + meals += L + if(meals.len) + prey = pick(meals) + prey << "\"You will do.\"\n\ + Something very large and very malevolent begins lumbering its way towards you..." + prey << 'sound/effects/ratvar_reveal.ogg' + else + if(prob(10) || is_servant_of_ratvar(prey) || prey.z != z) + prey << "\"How dull. Leave me.\"\n\ + You feel tremendous relief as a set of horrible eyes loses sight of you..." + prey = null + else + dir_to_step_in = get_dir(src, prey) //Unlike Nar-Sie, Ratvar ruthlessly chases down his target + step(src, dir_to_step_in) + +/obj/structure/destructible/clockwork/massive/ratvar/narsie_act() + if(clashing) + return FALSE + clashing = TRUE + world << "\"[pick("BLOOD GOD!!!", "NAR-SIE!!!", "AT LAST, YOUR TIME HAS COME!")]\"" + world << "\"Ratvar?! How?!\"" + for(var/obj/singularity/narsie/N in range(15, src)) + if(N.clashing) + continue + N.clashing = TRUE + clash_of_the_titans(N) //IT'S TIME FOR THE BATTLE OF THE AGES + break + return TRUE + +//Put me in Reebe, will you? Ratvar has found and is going to fucking murder Nar-Sie +/obj/structure/destructible/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie) + var/winner = "Undeclared" + var/base_victory_chance = 1 + while(src && narsie) + world << 'sound/magic/clockwork/ratvar_attack.ogg' + sleep(5.2) + for(var/mob/M in mob_list) + flash_color(M, flash_color="#966400", flash_time=1) + shake_camera(M, 4, 3) + var/ratvar_chance = min(ticker.mode.servants_of_ratvar.len, 50) + var/narsie_chance = ticker.mode.cult.len + for(var/mob/living/simple_animal/hostile/construct/harvester/C in player_list) + narsie_chance++ + ratvar_chance = rand(base_victory_chance, ratvar_chance) + narsie_chance = rand(base_victory_chance, min(narsie_chance, 50)) + if(ratvar_chance > narsie_chance) + winner = "Ratvar" + break + sleep(rand(2,5)) + world << 'sound/magic/clockwork/narsie_attack.ogg' + sleep(7.4) + for(var/mob/M in mob_list) + flash_color(M, flash_color="#C80000", flash_time=1) + shake_camera(M, 4, 3) + if(narsie_chance > ratvar_chance) + winner = "Nar-Sie" + break + base_victory_chance *= 2 //The clash has a higher chance of resolving each time both gods attack one another + switch(winner) + if("Ratvar") + world << "\"[pick("DIE! DIE! DIE!", "FILTH!!!", "SUFFER!!!", text2ratvar("ROT FOR CENTURIES AS I HAVE!!"))]\"" //nar-sie get out + world << "\"[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"" + world << 'sound/magic/clockwork/anima_fragment_attack.ogg' + world << 'sound/magic/demon_dies.ogg' + clashing = FALSE + qdel(narsie) + if("Nar-Sie") + world << "\"[pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here.")]\"" //Broken English + world << 'sound/magic/demon_attack1.ogg' + world << 'sound/magic/clockwork/anima_fragment_death.ogg' + narsie.clashing = FALSE + qdel(src) diff --git a/code/game/gamemodes/clock_cult/clock_structures/tinkerers_cache.dm b/code/game/gamemodes/clock_cult/clock_structures/tinkerers_cache.dm new file mode 100644 index 00000000000..4ca862b8663 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/tinkerers_cache.dm @@ -0,0 +1,89 @@ +//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" + construction_value = 10 + break_message = "The cache's fire winks out before it falls in on itself!" + max_integrity = 80 + obj_integrity = 80 + var/wall_generation_cooldown + var/turf/closed/wall/clockwork/linkedwall //if we've got a linked wall and are producing + +/obj/structure/destructible/clockwork/cache/New() + ..() + START_PROCESSING(SSobj, src) + clockwork_caches++ + SetLuminosity(2,1) + for(var/i in all_clockwork_mobs) + cache_check(i) + +/obj/structure/destructible/clockwork/cache/Destroy() + clockwork_caches-- + STOP_PROCESSING(SSobj, src) + if(linkedwall) + linkedwall.linkedcache = null + linkedwall = null + for(var/i in all_clockwork_mobs) + cache_check(i) + return ..() + +/obj/structure/destructible/clockwork/cache/process() + for(var/turf/closed/wall/clockwork/C in view(4, src)) + if(!C.linkedcache && !linkedwall) + C.linkedcache = src + linkedwall = C + wall_generation_cooldown = world.time + CACHE_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 + CACHE_PRODUCTION_TIME + var/component_to_generate = get_weighted_component_id() + PoolOrNew(get_component_animation_type(component_to_generate), get_turf(src)) + clockwork_component_cache[component_to_generate]++ + playsound(C, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1) + visible_message("Something clunks around inside of [src]...") + break + +/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 + clockwork_component_cache[C.component_id]++ + 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 + for(var/i in S.stored_components) + clockwork_component_cache[i] += S.stored_components[i] + S.stored_components[i] = 0 + 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/attack_hand(mob/user) + if(!is_servant_of_ratvar(user)) + return 0 + if(!clockwork_component_cache["replicant_alloy"]) + user << "There is no Replicant Alloy in the global component cache!" + return 0 + clockwork_component_cache["replicant_alloy"]-- + var/obj/item/clockwork/component/replicant_alloy/A = new(get_turf(src)) + user.visible_message("[user] withdraws [A] from [src].", "You withdraw [A] from [src].") + user.put_in_hands(A) + return 1 + +/obj/structure/destructible/clockwork/cache/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + if(linkedwall) + user << "It is linked and will generate components!" + user << "Stored components:" + for(var/i in clockwork_component_cache) + user << "[get_component_name(i)][i != "replicant_alloy" ? "s":""]: [clockwork_component_cache[i]]" diff --git a/code/game/gamemodes/clock_cult/clock_structures/tinkerers_daemon.dm b/code/game/gamemodes/clock_cult/clock_structures/tinkerers_daemon.dm new file mode 100644 index 00000000000..e15cf9eb1dd --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/tinkerers_daemon.dm @@ -0,0 +1,130 @@ +//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 outnumbered by servants at a rate to 5:1." + icon_state = "tinkerers_daemon" + active_icon = "tinkerers_daemon" + inactive_icon = "tinkerers_daemon" + max_integrity = 100 + obj_integrity = 100 + break_message = "The daemon shatters into millions of pieces!" + debris = list(/obj/item/clockwork/alloy_shards/large = 2, \ + /obj/item/clockwork/alloy_shards/medium = 4, \ + /obj/item/clockwork/alloy_shards/small = 6) + var/image/daemon_glow + var/image/component_glow + var/component_id_to_produce + var/production_time = 0 //last time we produced a component + var/production_cooldown = 120 + +/obj/structure/destructible/clockwork/powered/tinkerers_daemon/New() + ..() + clockwork_daemons++ + +/obj/structure/destructible/clockwork/powered/tinkerers_daemon/Destroy() + clockwork_daemons-- + 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) + user << "It is currently producing [get_component_name(component_id_to_produce)][component_id_to_produce != "replicant_alloy" ? "s":""]." + else + user << "It is currently producing random components." + user << "It will produce a component every [production_cooldown*0.1] seconds and requires at least the following power for each component type:" + for(var/i in clockwork_component_cache) + user << "[get_component_name(i)]: [get_component_cost(i)]W ([clockwork_component_cache[i]] exist[clockwork_component_cache[i] == 1 ? "s" : ""])" + +/obj/structure/destructible/clockwork/powered/tinkerers_daemon/attack_hand(mob/living/user) + if(!is_servant_of_ratvar(user)) + user << "You place your hand on the daemon, but nothing happens." + return + if(active) + toggle(0, user) + else + if(!clockwork_caches) + user << "There are no clockwork caches! Activating this daemon would be a waste of power." + 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 clockwork_component_cache) + components["[get_component_name(i)] ([get_component_cost(i)]W)"] = i + var/input_component = input(user, "Choose a component type.", name) as null|anything in components + component_id_to_produce = components[input_component] + if(!user.canUseTopic(src, BE_CLOSE) || active) + return + if(!component_id_to_produce) + user << "You decide not to select a component and activate the daemon." + return + if(total_accessable_power() < get_component_cost(component_id_to_produce)) + user << "There is too little power to produce this type of component!" + return + toggle(0, user) + if("Random Component") + component_id_to_produce = null + toggle(0, user) + +/obj/structure/destructible/clockwork/powered/tinkerers_daemon/toggle(fast_process, mob/living/user) + . = ..() + if(active) + var/component_color = get_component_color(component_id_to_produce) + if(!daemon_glow) + daemon_glow = new('icons/obj/clockwork_objects.dmi', "tinkerglow") + daemon_glow.color = component_color + add_overlay(daemon_glow) + if(!component_glow) + component_glow = new('icons/obj/clockwork_objects.dmi', "t_[component_id_to_produce ? component_id_to_produce :"random_component"]") + else + 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 afteer being off + else + cut_overlays() + +/obj/structure/destructible/clockwork/powered/tinkerers_daemon/proc/get_component_cost(id) + return max(MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER * (1 + round(clockwork_component_cache[id] * 0.2))) + +/obj/structure/destructible/clockwork/powered/tinkerers_daemon/process() + var/servants = 0 + for(var/mob/living/L in living_mob_list) + if(is_servant_of_ratvar(L)) + servants++ + . = ..() + var/min_power_usable = 0 + if(!component_id_to_produce) + for(var/i in 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(!clockwork_caches || servants * 0.2 < clockwork_daemons || . < min_power_usable) //if we don't have enough to produce the lowest or what we chose to produce, cancel out + visible_message("[src] shuts down!") + toggle() + 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 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) + PoolOrNew(get_component_animation_type(component_to_generate), get_turf(src)) + clockwork_component_cache[component_to_generate]++ + production_time = world.time + production_cooldown //go on cooldown + visible_message("[src] hums as it produces a [get_component_name(component_to_generate)].") + else + visible_message("[src] shuts down!") //we shouldn't actually ever get here, as we should cancel out way before this + toggle() diff --git a/code/game/gamemodes/clock_cult/clock_structures/wall_gear.dm b/code/game/gamemodes/clock_cult/clock_structures/wall_gear.dm new file mode 100644 index 00000000000..85b35bd2eb4 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_structures/wall_gear.dm @@ -0,0 +1,56 @@ +//A massive gear, effectively a girder for clocks. +/obj/structure/destructible/clockwork/wall_gear + name = "massive gear" + icon_state = "wall_gear" + climbable = TRUE + max_integrity = 50 + obj_integrity = 50 + desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, or just climb over it." + clockwork_desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, just climb over it, or proselytize it into replicant alloy." + break_message = "The gear breaks apart into shards of alloy!" + debris = list(/obj/item/clockwork/alloy_shards/large = 1, \ + /obj/item/clockwork/alloy_shards/medium = 4, \ + /obj/item/clockwork/alloy_shards/small = 2) //slightly more debris than the default, totals 26 alloy + +/obj/structure/destructible/clockwork/wall_gear/displaced + anchored = FALSE + +/obj/structure/destructible/clockwork/wall_gear/examine(mob/user) + ..() + user << "[src] is [anchored ? "":"not "]secured to the floor." + +/obj/structure/destructible/clockwork/wall_gear/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/wrench)) + default_unfasten_wrench(user, I, 10) + return 1 + else if(istype(I, /obj/item/stack/sheet/brass)) + var/obj/item/stack/sheet/brass/W = I + if(W.get_amount() < 1) + user << "You need one brass sheet to do this!" + return + var/turf/T = get_turf(src) + if(iswallturf(T)) + user << "There is already a wall present!" + return + if(!isfloorturf(T)) + user << "A floor must be present to build a [anchored ? "false ":""]wall!" + return + if(locate(/obj/structure/falsewall) in T.contents) + user << "There is already a false wall present!" + return + user << "You start adding [W] to [src]..." + if(do_after(user, 20, target = src)) + var/brass_floor = FALSE + if(istype(T, /turf/open/floor/clockwork)) //if the floor is already brass, costs less to make(conservation of masssssss) + brass_floor = TRUE + if(W.use(2 - brass_floor)) + if(anchored) + T.ChangeTurf(/turf/closed/wall/clockwork) + else + T.ChangeTurf(/turf/open/floor/clockwork) + new /obj/structure/falsewall/brass(T) + qdel(src) + else + user << "You need more brass to make a [anchored ? "false ":""]wall!" + return 1 + return ..() diff --git a/code/game/gamemodes/clock_cult/clock_unsorted.dm b/code/game/gamemodes/clock_cult/clock_unsorted.dm deleted file mode 100644 index f21c151a73f..00000000000 --- a/code/game/gamemodes/clock_cult/clock_unsorted.dm +++ /dev/null @@ -1,372 +0,0 @@ -//sends messages via hierophant -/proc/titled_hierophant_message(mob/user, message, name_span = "heavy_brass", message_span = "brass", user_title = "Servant") - if(!user || !message || !ticker || !ticker.mode) - return 0 - var/parsed_message = "[user_title ? "[user_title] ":""][findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: \ - \"[message]\"" - hierophant_message(parsed_message, FALSE, user) - return 1 - -/proc/hierophant_message(message, servantsonly, atom/target) //sends a generic message to all servants and optionally observers - if(!message || !ticker || !ticker.mode) - return 0 - for(var/M in mob_list) - if(!servantsonly && isobserver(M)) - if(target) - var/link = FOLLOW_LINK(M, target) - M << "[link] [message]" - else - M << message - else if(is_servant_of_ratvar(M)) - M << message - -//Hierophant Network action, allows a servant with it to communicate -/datum/action/innate/hierophant - name = "Hierophant Network" - desc = "Allows you to communicate with other Servants." - button_icon_state = "hierophant" - background_icon_state = "bg_clock" - check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS - buttontooltipstyle = "clockcult" - var/title = "Servant" - var/span_for_name = "heavy_brass" - var/span_for_message = "brass" - -/datum/action/innate/hierophant/IsAvailable() - if(!is_servant_of_ratvar(owner)) - return 0 - return ..() - -/datum/action/innate/hierophant/Activate() - var/input = stripped_input(usr, "Please enter a message to send to other servants.", "Hierophant Network", "") - if(!input || !IsAvailable()) - return - - titled_hierophant_message(owner, input, span_for_name, span_for_message, title) - -//Function Call action: Calls forth a Ratvarian spear once every 3 minutes -/datum/action/innate/function_call - name = "Function Call" - desc = "Allows you to summon a Ratvarian spear to fight enemies." - button_icon_state = "ratvarian_spear" - background_icon_state = "bg_clock" - check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS - buttontooltipstyle = "clockcult" - var/cooldown = 0 - var/base_cooldown = 1800 - -/datum/action/innate/function_call/IsAvailable() - if(!is_servant_of_ratvar(owner) || cooldown > world.time) - return 0 - return ..() - -/datum/action/innate/function_call/Activate() - if(!owner.get_empty_held_indexes()) - usr << "You need an empty to hand to call forth your spear!" - return 0 - owner.visible_message("A strange spear materializes in [owner]'s hands!", "You call forth your spear!") - var/obj/item/clockwork/ratvarian_spear/R = new(get_turf(usr)) - owner.put_in_hands(R) - if(!ratvar_awakens) - owner << "Your spear begins to break down in this plane of existence. You can't use it for long!" - addtimer(R, "break_spear", base_cooldown, FALSE) - cooldown = base_cooldown + world.time - owner.update_action_buttons_icon() - addtimer(src, "update_actions", base_cooldown, FALSE) - return 1 - -/datum/action/innate/function_call/proc/update_actions() - if(owner) - owner.update_action_buttons_icon() - -//allows a mob to select a target to gate to -/atom/movable/proc/procure_gateway(mob/living/invoker, time_duration, gateway_uses, two_way) - var/list/possible_targets = list() - var/list/teleportnames = list() - var/list/duplicatenamecount = list() - - for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects) - if(!O.Adjacent(invoker) && O != src && (O.z <= ZLEVEL_SPACEMAX)) //don't list obelisks that we're next to - var/area/A = get_area(O) - var/locname = initial(A.name) - var/resultkey = "[locname] [O.name]" - if(resultkey in teleportnames) //why the fuck did you put two obelisks in the same area - duplicatenamecount[resultkey]++ - resultkey = "[resultkey] ([duplicatenamecount[resultkey]])" - else - teleportnames.Add(resultkey) - duplicatenamecount[resultkey] = 1 - possible_targets[resultkey] = O - - for(var/mob/living/L in living_mob_list) - if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && L != invoker && (L.z <= ZLEVEL_SPACEMAX)) //People right next to the invoker can't be portaled to, for obvious reasons - var/resultkey = "[L.name] ([L.real_name])" - if(resultkey in teleportnames) - duplicatenamecount[resultkey]++ - resultkey = "[resultkey] ([duplicatenamecount[resultkey]])" - else - teleportnames.Add(resultkey) - duplicatenamecount[resultkey] = 1 - possible_targets[resultkey] = L - - if(!possible_targets.len) - invoker << "There are no other eligible targets for a Spatial Gateway!" - return 0 - var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets - var/atom/movable/target = possible_targets[input_target_key] - if(!src || !target || !invoker || !invoker.canUseTopic(src, BE_CLOSE) || !is_servant_of_ratvar(invoker) || (istype(src, /obj/item) && invoker.get_active_held_item() != src)) - return 0 //if any of the involved things no longer exist, the invoker is stunned, too far away to use the object, or does not serve ratvar, or if the object is an item and not in the mob's active hand, fail - var/istargetobelisk = istype(target, /obj/structure/destructible/clockwork/powered/clockwork_obelisk) - if(istargetobelisk) - gateway_uses *= 2 - time_duration *= 2 - invoker.visible_message("The air in front of [invoker] ripples before suddenly tearing open!", \ - "With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [time_duration / 10] seconds and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].") - var/obj/effect/clockwork/spatial_gateway/S1 = new(istype(src, /obj/structure/destructible/clockwork/powered/clockwork_obelisk) ? get_turf(src) : get_step(get_turf(invoker), invoker.dir)) - var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir)) - - //Set up the portals now that they've spawned - S1.setup_gateway(S2, time_duration, gateway_uses, two_way) - S2.visible_message("The air in front of [target] ripples before suddenly tearing open!") - return 1 - -/proc/scripture_unlock_check() //returns a list of scriptures and if they're unlocked or not - var/servants = 0 - var/unconverted_ai_exists = FALSE - for(var/mob/living/M in living_mob_list) - if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M))) - servants++ - else if(isAI(M)) - unconverted_ai_exists = TRUE - . = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_REVENANT = FALSE, SCRIPTURE_JUDGEMENT = FALSE) - //Drivers: always unlocked - .[SCRIPTURE_SCRIPT] = (servants >= 5 && clockwork_caches >= 1) - //Script: 5 or more non-brain servants and 1+ clockwork caches - .[SCRIPTURE_APPLICATION] = (servants >= 8 && clockwork_caches >= 3 && clockwork_construction_value >= 100) - //Application: 8 or more non-brain servants, 3+ clockwork caches, and at least 100 CV - .[SCRIPTURE_REVENANT] = (servants >= 10 && clockwork_caches >= 4 && clockwork_construction_value >= 200) - //Revenant: 10 or more non-brain servants, 4+ clockwork caches, and at least 200 CV - .[SCRIPTURE_JUDGEMENT] = (servants >= 12 && clockwork_caches >= 5 && clockwork_construction_value >= 300 && !unconverted_ai_exists) - //Judgement: 12 or more non-brain servants, 5+ clockwork caches, at least 300 CV, and there are no living, non-servant ais - -/proc/scripture_unlock_alert(list/previous_states) //reports to servants when scripture is locked or unlocked - . = scripture_unlock_check() - for(var/i in .) - if(.[i] != previous_states[i]) - hierophant_message("Hierophant Network: [i] Scripture has been [.[i] ? "un":""]locked.") - -/proc/change_construction_value(amount) - clockwork_construction_value += amount - -/proc/get_component_name(id) //returns a component name from a component id - switch(id) - if("belligerent_eye") - return "Belligerent Eye" - if("vanguard_cogwheel") - return "Vanguard Cogwheel" - if("guvax_capacitor") - return "Guvax Capacitor" - if("replicant_alloy") - return "Replicant Alloy" - if("hierophant_ansible") - return "Hierophant Ansible" - else - return null - -/proc/get_component_span(id) //returns a component spanclass from a component id - switch(id) - if("belligerent_eye") - return "neovgre" - if("vanguard_cogwheel") - return "inathneq" - if("guvax_capacitor") - return "sevtug" - if("replicant_alloy") - return "nezbere" - if("hierophant_ansible") - return "nzcrentr" - else - return null - -/proc/get_component_color(id) //returns a component color from a component id - switch(id) - if("belligerent_eye") - return "#6E001A" - if("vanguard_cogwheel") - return "#1E8CE1" - if("guvax_capacitor") - return "#AF0AAF" - if("replicant_alloy") - return "#42474D" - if("hierophant_ansible") - return "#DAAA18" - else - return "#BE8700" - -/proc/get_component_id(name) //returns a component id from a component name - switch(name) - if("Belligerent Eye") - return "belligerent_eye" - if("Vanguard Cogwheel") - return "vanguard_cogwheel" - if("Guvax Capacitor") - return "guvax_capacitor" - if("Replicant Alloy") - return "replicant_alloy" - if("Hierophant Ansible") - return "hierophant_ansible" - else - return null - -/proc/get_component_animation_type(id) - switch(id) - if("belligerent_eye") - return /obj/effect/overlay/temp/ratvar/component - if("vanguard_cogwheel") - return /obj/effect/overlay/temp/ratvar/component/cogwheel - if("guvax_capacitor") - return /obj/effect/overlay/temp/ratvar/component/capacitor - if("replicant_alloy") - return /obj/effect/overlay/temp/ratvar/component/alloy - if("hierophant_ansible") - return /obj/effect/overlay/temp/ratvar/component/ansible - else - return null - -/proc/generate_cache_component(specific_component_id) //generates a component in the global component cache, either random based on lowest or a specific component - if(specific_component_id) - clockwork_component_cache[specific_component_id]++ - else - var/component_to_generate = get_weighted_component_id() - clockwork_component_cache[component_to_generate]++ - -/proc/get_weighted_component_id(obj/item/clockwork/slab/storage_slab) //returns a chosen component id based on the lowest amount of that component - . = list() - if(storage_slab) - if(clockwork_caches) - for(var/i in clockwork_component_cache) - .[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache[i] + storage_slab.stored_components[i]), 1) - else - for(var/i in clockwork_component_cache) - .[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*storage_slab.stored_components[i], 1) - else - for(var/i in clockwork_component_cache) - .[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache[i], 1) - . = pickweight(.) - -/proc/clockwork_say(atom/movable/AM, message, whisper=FALSE) - // When servants invoke ratvar's power, they speak in ways that non - // servants do not comprehend. - // Our ratvarian chants are stored in their ratvar forms - - var/list/spans = list(SPAN_ROBOT) - - var/old_languages_spoken = AM.languages_spoken - AM.languages_spoken = HUMAN //anyone who can understand HUMAN will hear weird shitty ratvar speak, otherwise it'll get starred out - if(isliving(AM)) - var/mob/living/L = AM - if(!whisper) - L.say(message, "clock", spans) - else - L.whisper(message) - else - AM.say(message) - AM.languages_spoken = old_languages_spoken - -/proc/cache_check(mob/M) - if(!clockwork_caches) - M.throw_alert("nocache", /obj/screen/alert/clockwork/nocache) - else - M.clear_alert("nocache") - -/* -The Ratvarian Language - In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar-Sie's language, but is in fact derived from -aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar-Sian cult). - - While the canon states that the language of Ratvar and his servants is incomprehensible to the unenlightened as it is a derivative of the most ancient known language, in reality it is -actually very simple. To translate a plain English sentence to Ratvar's tongue, simply move all of the letters thirteen places ahead, starting from "a" if the end of the alphabet is reached. -This cipher is known as "rot13" for "rotate 13 places" and there are many sites online that allow instant translation between English and rot13 - one of the benefits is that moving the translated -sentence thirteen places ahead changes it right back to plain English. - - There are, however, a few parts of the Ratvarian tongue that aren't typical and are implemented for fluff reasons. Some words may have graves, or hyphens (prefix and postfix), making the plain -English translation apparent but disjoined (for instance, "Orubyq zl-cbjre!" translates directly to "Behold my-power!") although this can be ignored without impacting overall quality. When -translating from Ratvar's tongue to plain English, simply remove the disjointments and use the finished sentence. This would make "Orubyq zl-cbjre!" into "Behold my power!" after removing the -abnormal spacing, hyphens, and grave accents. - -List of nuances: -- Any time the WORD "of" occurs, it is linked to the previous word by a hyphen. (i.e. "V nz-bs Ratvar." directly translates to "I am-of Ratvar.") -- Any time "th", followed by any two letters occurs, you add a grave (`) between those two letters, i.e; "Thi`s" -- In the same vein, any time "ti", followed by one letter occurs, you add a grave (`) between "i" and the letter, i.e; "Ti`me" -- Whereever "te" or "et" appear and there is another letter next to the e(i.e; "m"etal, greate"r"), add a hyphen between "e" and the letter, i.e; "M-etal", "Greate-r" -- Where "gua" appears, add a hyphen between "gu" and "a", i.e "Gu-ard" -- Where the WORD "and" appears it is linked to all surrounding words by hyphens, i.e; "Sword-and-shield" -- Where the WORD "to" appears, it is linked to the following word by a hyphen, i.e; "to-use" -- Where the WORD "my" appears, it is linked to the following word by a hyphen, i.e; "my-light" -- Although "Ratvar" translates to "Engine" in English, the word "Ratvar" is used regardless of language as it is a proper noun. - - The same rule applies to Ratvar's four generals: Nezbere (Armorer), Sevtug (Fright), Nzcrentr (Amperage), and Inath-neq (Vangu-Ard), although these words can be used in proper context if one is - not referring to the four generals and simply using the words themselves. -*/ - -//Regexes used to alter english to ratvarian style -#define RATVAR_OF_MATCH regex("(\\w)\\s(\[oO]\[fF])","g") -#define RATVAR_OF_REPLACEMENT "$1-$2" -#define RATVAR_GUA_MATCH regex("(\[gG]\[uU])(\[aA])","g") -#define RATVAR_GUA_REPLACEMENT "$1-$2" -#define RATVAR_TH_MATCH regex("(\[tT]\[hH]\\w)(\\w)","g") -#define RATVAR_TH_REPLACEMENT "$1`$2" -#define RATVAR_TI_MATCH regex("(\[tT]\[iI])(\\w)","g") -#define RATVAR_TI_REPLACEMENT "$1`$2" -#define RATVAR_ET_MATCH regex("(\\w)(\[eE]\[tT])","g") -#define RATVAR_ET_REPLACEMENT "$1-$2" -#define RATVAR_TE_MATCH regex("(\[tT]\[eE])(\\w)","g") -#define RATVAR_TE_REPLACEMENT "$1-$2" -#define RATVAR_PRE_AND_MATCH regex("(\\w)\\s(\[aA]\[nN]\[dD])","g") -#define RATVAR_PRE_AND_REPLACEMENT "$1-$2" -#define RATVAR_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])\\s(\\w)","g") -#define RATVAR_POST_AND_REPLACEMENT "$1-$2" -#define RATVAR_TO_MATCH regex("(\\s)(\[tT]\[oO])\\s(\\w)","g") -#define RATVAR_TO_REPLACEMENT "$1$2-$3" -#define RATVAR_MY_MATCH regex("(\\s)(\[mM]\[yY])\\s(\\w)","g") -#define RATVAR_MY_REPLACEMENT "$1$2-$3" - -//Regexes used to remove ratvarian styling from english -#define REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH regex("(\\w)-(\[aA]\[nN]\[dD])","g") //specifically structured to support -emphasis-, including with -and- -#define REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT "$1 $2" -#define REVERSE_RATVAR_HYPHEN_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])-(\\w)","g") -#define REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT "$1 $2" -#define REVERSE_RATVAR_HYPHEN_TO_MY_MATCH regex("(\[tTmM]\[oOyY])-","g") -#define REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT "$1 " -#define REVERSE_RATVAR_HYPHEN_TE_MATCH regex("(\[tT]\[eE])-","g") -#define REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT "$1" -#define REVERSE_RATVAR_HYPHEN_ET_MATCH regex("-(\[eE]\[tT])","g") -#define REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT "$1" -#define REVERSE_RATVAR_HYPHEN_GUA_MATCH regex("(\[gG]\[uU])-(\[aA])","g") -#define REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT "$1$2" -#define REVERSE_RATVAR_HYPHEN_OF_MATCH regex("-(\[oO]\[fF])","g") -#define REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT " $1" - - -/proc/text2ratvar(text) //Takes english and applies ratvarian styling rules (and rot13) to it - var/ratvarian = replacetext(text, RATVAR_OF_MATCH, RATVAR_OF_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_GUA_MATCH, RATVAR_GUA_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_TH_MATCH, RATVAR_TH_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_TI_MATCH, RATVAR_TI_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_ET_MATCH, RATVAR_ET_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_TE_MATCH, RATVAR_TE_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_PRE_AND_MATCH, RATVAR_PRE_AND_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_POST_AND_MATCH, RATVAR_POST_AND_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_TO_MATCH, RATVAR_TO_REPLACEMENT) - ratvarian = replacetext(ratvarian, RATVAR_MY_MATCH, RATVAR_MY_REPLACEMENT) - return rot13(ratvarian) - -/proc/ratvar2text(ratvarian) //Reverts ravarian styling and rot13 in text. - var/text = replacetext(rot13(ratvarian), "`", "") - text = replacetext(text, REVERSE_RATVAR_HYPHEN_GUA_MATCH, REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT) - text = replacetext(text, REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH, REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT) - text = replacetext(text, REVERSE_RATVAR_HYPHEN_POST_AND_MATCH, REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT) - text = replacetext(text, REVERSE_RATVAR_HYPHEN_TO_MY_MATCH, REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT) - text = replacetext(text, REVERSE_RATVAR_HYPHEN_TE_MATCH, REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT) - text = replacetext(text, REVERSE_RATVAR_HYPHEN_ET_MATCH, REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT) - text = replacetext(text, REVERSE_RATVAR_HYPHEN_OF_MATCH, REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT) - return text \ No newline at end of file diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 2a84348aaf1..0b076c59813 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -324,7 +324,7 @@ /mob/living/ratvar_act() - if(!add_servant_of_ratvar(src) && !is_servant_of_ratvar(src)) + if(!is_servant_of_ratvar(src) && !add_servant_of_ratvar(src)) src << "A blinding light boils you alive! Run!" adjustFireLoss(35) if(src) diff --git a/tgstation.dme b/tgstation.dme index e7f2f25e7ac..742744617e6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -348,22 +348,45 @@ #include "code\game\gamemodes\changeling\powers\tiny_prick.dm" #include "code\game\gamemodes\changeling\powers\transform.dm" #include "code\game\gamemodes\clock_cult\clock_cult.dm" +#include "code\game\gamemodes\clock_cult\clock_effect.dm" #include "code\game\gamemodes\clock_cult\clock_item.dm" -#include "code\game\gamemodes\clock_cult\clock_machines.dm" #include "code\game\gamemodes\clock_cult\clock_mobs.dm" -#include "code\game\gamemodes\clock_cult\clock_powerdrain.dm" -#include "code\game\gamemodes\clock_cult\clock_ratvar.dm" #include "code\game\gamemodes\clock_cult\clock_scripture.dm" -#include "code\game\gamemodes\clock_cult\clock_structures.dm" -#include "code\game\gamemodes\clock_cult\clock_unsorted.dm" -#include "code\game\gamemodes\clock_cult\clock_items\clock_armor.dm" +#include "code\game\gamemodes\clock_cult\clock_structure.dm" +#include "code\game\gamemodes\clock_cult\clock_effects\clock_overlay.dm" +#include "code\game\gamemodes\clock_cult\clock_effects\clock_sigils.dm" +#include "code\game\gamemodes\clock_cult\clock_effects\general_markers.dm" +#include "code\game\gamemodes\clock_cult\clock_effects\spatial_gateway.dm" +#include "code\game\gamemodes\clock_cult\clock_helpers\clock_powerdrain.dm" +#include "code\game\gamemodes\clock_cult\clock_helpers\component_helpers.dm" +#include "code\game\gamemodes\clock_cult\clock_helpers\hierophant_network.dm" +#include "code\game\gamemodes\clock_cult\clock_helpers\proselytizer_helpers.dm" +#include "code\game\gamemodes\clock_cult\clock_helpers\ratvarian_language.dm" +#include "code\game\gamemodes\clock_cult\clock_helpers\scripture_checks.dm" #include "code\game\gamemodes\clock_cult\clock_items\clock_components.dm" -#include "code\game\gamemodes\clock_cult\clock_items\clock_proselytizer.dm" -#include "code\game\gamemodes\clock_cult\clock_items\clock_slab.dm" +#include "code\game\gamemodes\clock_cult\clock_items\clockwork_armor.dm" +#include "code\game\gamemodes\clock_cult\clock_items\clockwork_proselytizer.dm" +#include "code\game\gamemodes\clock_cult\clock_items\clockwork_slab.dm" #include "code\game\gamemodes\clock_cult\clock_items\judicial_visor.dm" #include "code\game\gamemodes\clock_cult\clock_items\ratvarian_spear.dm" #include "code\game\gamemodes\clock_cult\clock_items\soul_vessel.dm" #include "code\game\gamemodes\clock_cult\clock_items\wraith_spectacles.dm" +#include "code\game\gamemodes\clock_cult\clock_scriptures\scripture_applications.dm" +#include "code\game\gamemodes\clock_cult\clock_scriptures\scripture_drivers.dm" +#include "code\game\gamemodes\clock_cult\clock_scriptures\scripture_judgement.dm" +#include "code\game\gamemodes\clock_cult\clock_scriptures\scripture_revenant.dm" +#include "code\game\gamemodes\clock_cult\clock_scriptures\scripture_scripts.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\ark_of_the_clockwork_justicar.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\clock_shells.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\clockwork_obelisk.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\interdiction_lens.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\mania_motor.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\mending_motor.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\ocular_warden.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\ratvar_the_clockwork_justicar.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\tinkerers_cache.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\tinkerers_daemon.dm" +#include "code\game\gamemodes\clock_cult\clock_structures\wall_gear.dm" #include "code\game\gamemodes\cult\cult.dm" #include "code\game\gamemodes\cult\cult_comms.dm" #include "code\game\gamemodes\cult\cult_items.dm"