From 9c399abe4687da5f33cf01c2689bd057cb899b1b Mon Sep 17 00:00:00 2001
From: Uristthedorf <40842973+Uristthedorf@users.noreply.github.com>
Date: Mon, 1 Jul 2024 22:23:27 -0700
Subject: [PATCH 1/5] Commit
---
.../code/game/machinery/exp_cloner.dm | 78 ++++++++++++++++++-
.../antagonists/evil_clone/evil_clone.dm | 23 ++++++
.../evil_clone/evil_clone_objective.dm | 38 +++++++++
.../antagonists/evil_clone/evil_event.dm | 19 +++++
tgstation.dme | 3 +
5 files changed, 157 insertions(+), 4 deletions(-)
create mode 100644 monkestation/code/modules/antagonists/evil_clone/evil_clone.dm
create mode 100644 monkestation/code/modules/antagonists/evil_clone/evil_clone_objective.dm
create mode 100644 monkestation/code/modules/antagonists/evil_clone/evil_event.dm
diff --git a/monkestation/code/game/machinery/exp_cloner.dm b/monkestation/code/game/machinery/exp_cloner.dm
index 6d522ee9cfcd..bd8623ea5191 100644
--- a/monkestation/code/game/machinery/exp_cloner.dm
+++ b/monkestation/code/game/machinery/exp_cloner.dm
@@ -7,13 +7,37 @@
req_access = null
circuit = /obj/item/circuitboard/machine/clonepod/experimental
internal_radio = FALSE
+ grab_ghost_when = CLONER_FRESH_CLONE // This helps with getting the objective for evil clones to display.
VAR_PRIVATE
static/list/image/cached_clone_images
+ /// Am I producing evil clones?
+ var/datum/objective/evil_clone/evil_objective = null
+ /// Can my objective be changed?
+ var/locked = FALSE
+ /// The custom objective given by the traitor item.
+ var/custom_objective = null
/obj/machinery/clonepod/experimental/Destroy()
clear_human_dummy(REF(src))
return ..()
+/obj/machinery/clonepod/experimental/examine(mob/user)
+ . = ..()
+ if((evil_objective || custom_objective) && (in_range(user, src) || isobserver(user)))
+ if(!isnull(evil_objective) || !isnull(custom_objective))
+ . += span_warning("You notice an ominous, flashing red LED light.")
+ if(isobserver(user))
+ if(!isnull(custom_objective))
+ . += span_notice("Those cloned will have the objective: [custom_objective]") //This doesn't look the best I think.
+ else
+ . += span_notice("Those cloned will have the objective: [evil_objective.explanation_text]")
+
+/obj/machinery/clonepod/experimental/RefreshParts()
+ . = ..()
+ if(!isnull(evil_objective) || !isnull(custom_objective))
+ speed_coeff = round(speed_coeff / 2) // So better parts have half the speed increase.
+ speed_coeff += 1 // I still want basic parts to have base 100% speed.
+
//Start growing a human clone in the pod!
/obj/machinery/clonepod/experimental/growclone(clonename, ui, mutation_index, mindref, blood_type, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance)
if(panel_open || mess || attempting)
@@ -54,13 +78,25 @@
ADD_TRAIT(clonee, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT)
clonee.Unconscious(80)
+ var/role_text
+ var/poll_text
+ if(!isnull(custom_objective))
+ role_text = "syndicate clone"
+ poll_text = "Do you want to play as [clonename]'s syndicate clone?"
+ else if(!isnull(evil_objective))
+ role_text = "evil clone"
+ poll_text = "Do you want to play as [clonename]'s evil clone?"
+ else
+ role_text = "defective clone"
+ poll_text = "Do you want to play as [clonename]'s defective clone?"
+
var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates_for_mob(
- "Do you want to play as [clonename]'s defective clone?",
+ poll_text,
poll_time = 10 SECONDS,
target_mob = clonee,
ignore_category = POLL_IGNORE_DEFECTIVECLONE,
pic_source = get_clone_preview(clonee.dna) || clonee,
- role_name_text = "defective clone"
+ role_name_text = role_text
)
if(LAZYLEN(candidates))
var/mob/dead/observer/candidate = pick(candidates)
@@ -84,8 +120,23 @@
/obj/machinery/clonepod/experimental/exp_clone_check(mob/living/carbon/human/mob_occupant)
if(!mob_occupant?.mind) //When experimental cloner fails to get a ghost, it won't spit out a body, so we don't get an army of brainless rejects.
qdel(mob_occupant)
- return FALSE
- return TRUE
+ else if(!isnull(custom_objective))
+ var/datum/antagonist/evil_clone/antag_object = new
+ var/datum/objective/evil_clone/custom = new
+ custom.explanation_text = custom_objective
+ antag_object.objectives += custom
+ mob_occupant.mind.add_antag_datum(antag_object)
+ mob_occupant.grant_language(/datum/language/codespeak) // So you don't have to remember to grant each and every identical clone codespeak with the manual.
+ mob_occupant.remove_blocked_language(/datum/language/codespeak, source=LANGUAGE_ALL) // All the effects the codespeak manual would have.
+ ADD_TRAIT(mob_occupant, TRAIT_TOWER_OF_BABEL, MAGIC_TRAIT)
+ var/obj/item/implant/radio/syndicate/imp = new(src)
+ imp.implant(mob_occupant)
+ mob_occupant.faction |= ROLE_SYNDICATE
+ mob_occupant.AddComponent(/datum/component/simple_access, list(ACCESS_SYNDICATE, ACCESS_MAINT_TUNNELS, ACCESS_GENETICS, ACCESS_MINERAL_STOREROOM)) //Basic/syndicate access, and genetics too because clones are genetics stuff.
+ else if(!isnull(evil_objective))
+ var/datum/antagonist/evil_clone/antag_object = new
+ antag_object.objectives += new evil_objective()
+ mob_occupant.mind.add_antag_datum(antag_object)
/obj/machinery/clonepod/experimental/proc/get_clone_preview(datum/dna/clone_dna)
RETURN_TYPE(/image)
@@ -104,6 +155,25 @@
LAZYSET(cached_clone_images, key, preview)
return preview
+/obj/machinery/clonepod/experimental/emag_act(mob/user)
+ if(!locked)
+ evil_objective = /datum/objective/evil_clone/murder //Emags will give a nasty objective.
+ locked = TRUE
+ to_chat(user, span_warning("You corrupt the genetic compiler."))
+ add_fingerprint(user)
+ log_cloning("[key_name(user)] emagged [src] at [AREACOORD(src)], causing it to malfunction.")
+ RefreshParts()
+ else
+ to_chat(user, span_warning("The cloner is already malfunctioning."))
+
+/obj/machinery/clonepod/experimental/emp_act(severity)
+ . = ..()
+ if (!(. & EMP_PROTECT_SELF))
+ if(prob(100/severity) && !locked)
+ evil_objective = pick(subtypesof(/datum/objective/evil_clone) - /datum/objective/evil_clone/murder)
+ RefreshParts()
+ log_cloning("[src] at [AREACOORD(src)] corrupted due to EMP pulse.")
+
//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
/obj/machinery/computer/prototype_cloning
name = "prototype cloning console"
diff --git a/monkestation/code/modules/antagonists/evil_clone/evil_clone.dm b/monkestation/code/modules/antagonists/evil_clone/evil_clone.dm
new file mode 100644
index 000000000000..a3b4bc9591db
--- /dev/null
+++ b/monkestation/code/modules/antagonists/evil_clone/evil_clone.dm
@@ -0,0 +1,23 @@
+/datum/antagonist/evil_clone
+ name = "\improper Evil Clone"
+ show_in_antagpanel = TRUE
+ roundend_category = "evil clones"
+ antagpanel_category = "Evil Clones"
+ show_name_in_check_antagonists = TRUE
+ show_to_ghosts = TRUE
+
+/datum/antagonist/evil_clone/greet()
+ . = ..()
+ owner.announce_objectives()
+ owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/revolutionary_tide.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
+
+/datum/antagonist/evil_clone/apply_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current = owner.current
+ current.AddElement(/datum/element/cult_eyes, initial_delay = 0 SECONDS)
+
+/datum/antagonist/evil_clone/remove_innate_effects(mob/living/mob_override)
+ . = ..()
+ var/mob/living/current = owner.current
+ if (HAS_TRAIT(current, TRAIT_UNNATURAL_RED_GLOWY_EYES))
+ current.RemoveElement(/datum/element/cult_eyes)
diff --git a/monkestation/code/modules/antagonists/evil_clone/evil_clone_objective.dm b/monkestation/code/modules/antagonists/evil_clone/evil_clone_objective.dm
new file mode 100644
index 000000000000..88aa241e4453
--- /dev/null
+++ b/monkestation/code/modules/antagonists/evil_clone/evil_clone_objective.dm
@@ -0,0 +1,38 @@
+/datum/objective/evil_clone/murder // The existance of the murderbone objective makes evil clones properly feared, so even when they aren't murderboning they will still be shunned and persecuted.
+ name = "clone supremacy"
+ explanation_text = "Make sure clones of yourself are the only ones alive. Do not spare the original."
+
+/datum/objective/evil_clone/sole
+ name = "real one"
+ explanation_text = "All other versions of you are imposters, eliminate them."
+
+/datum/objective/evil_clone/rule
+ name = "rightful rule"
+ explanation_text = "You and your fellow clones of yourself are the rightful rulers of the station, take control."
+
+/datum/objective/evil_clone/minion
+ name = "minion"
+ explanation_text = "Find the most evil being you can, and become their minion."
+
+/datum/objective/evil_clone/dud // Relies on more destructive objectives, to create conflict from crew hating evil clones because they MIGHT have a more evil objective.
+ name = "peaceful clone"
+ explanation_text = "You find it really mean that some people don't like you because of your red eyes."
+
+/datum/objective/evil_clone/tide
+ name = "tider"
+ explanation_text = "Crime is your religion, commit as much crime as possible. Only seriously injure people if they try to stop crime."
+
+/datum/objective/evil_clone/fake_cult
+ name = "fake cultist"
+ explanation_text = "Praise"
+
+/datum/objective/evil_clone/fake_cult/New()
+ var/god = pick(list("Rat'var", "Nar'sie")) //So clones with different gods will fight eachother.
+ explanation_text+=" [god]! They haven't answered your prayers yet, but surely if you pray enough and make elaborate enough rituals they will inevitably come. Make sure no heretical religions prosper."
+
+/datum/objective/evil_clone/territorial
+ name = "territorial"
+ explanation_text = "The clonepod which created you is a holy site only you and your fellow clones of yourself are worthy to be in the presence of. Secure the area around the clonepod and ensure no non-clones threaten it."
+
+/datum/objective/evil_clone/check_completion()
+ return TRUE
diff --git a/monkestation/code/modules/antagonists/evil_clone/evil_event.dm b/monkestation/code/modules/antagonists/evil_clone/evil_event.dm
new file mode 100644
index 000000000000..10d5b481d9cc
--- /dev/null
+++ b/monkestation/code/modules/antagonists/evil_clone/evil_event.dm
@@ -0,0 +1,19 @@
+/datum/round_event_control/cloner_corruption
+ name = "Experimental Cloner Corruption"
+ typepath = /datum/round_event/cloner_corruption
+ max_occurrences = 1
+ weight = 3
+ category = EVENT_CATEGORY_ENTITIES //Kinda, evil clones ARE entities.
+ track = EVENT_TRACK_MODERATE
+ tags = list(TAG_COMBAT) // Clones will likely start a fight, but will usually not cause wanton destruction.
+ earliest_start = 35 MINUTES //This requires an experimental cloner to be made, so should wait until later to fire when there's better chance one has been set up.
+
+/datum/round_event/cloner_corruption/start()
+ var/found = FALSE
+ for(var/obj/machinery/clonepod/experimental/cloner in GLOB.machines)
+ if(!cloner.locked)
+ cloner.evil_objective = pick(subtypesof(/datum/objective/evil_clone))
+ cloner.RefreshParts()
+ found = TRUE
+ if(!found) // Refund if no experimental cloners are found.
+ control.occurrences--
diff --git a/tgstation.dme b/tgstation.dme
index 5a26bb276b5f..9da6933e6f50 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -6057,6 +6057,9 @@
#include "monkestation\code\modules\antagonists\contractor\items\modsuit\theme.dm"
#include "monkestation\code\modules\antagonists\cult\blood_magic.dm"
#include "monkestation\code\modules\antagonists\ert\moff_inspectors.dm"
+#include "monkestation\code\modules\antagonists\evil_clone\evil_clone.dm"
+#include "monkestation\code\modules\antagonists\evil_clone\evil_clone_objective.dm"
+#include "monkestation\code\modules\antagonists\evil_clone\evil_event.dm"
#include "monkestation\code\modules\antagonists\florida_man\__outfits.dm"
#include "monkestation\code\modules\antagonists\florida_man\_defines.dm"
#include "monkestation\code\modules\antagonists\florida_man\_florida_man.dm"
From b18c5aa8ce3eda139dc33ac4c0571b2c204e7d68 Mon Sep 17 00:00:00 2001
From: Uristthedorf <40842973+Uristthedorf@users.noreply.github.com>
Date: Mon, 1 Jul 2024 22:33:54 -0700
Subject: [PATCH 2/5] Syndiekit
---
.../game/objects/items/storage/uplink_kits.dm | 39 ++++++++++++++
.../code/modules/uplink/uplink_items/job.dm | 52 +++++++++++++++++++
2 files changed, 91 insertions(+)
diff --git a/monkestation/code/game/objects/items/storage/uplink_kits.dm b/monkestation/code/game/objects/items/storage/uplink_kits.dm
index 09b754b22d84..5b5148806f38 100644
--- a/monkestation/code/game/objects/items/storage/uplink_kits.dm
+++ b/monkestation/code/game/objects/items/storage/uplink_kits.dm
@@ -160,6 +160,45 @@
new /obj/item/lighter(src)
new /obj/item/jammer(src)
+/obj/item/storage/box/clonearmy
+ name = "Syndicate clone army kit"
+ desc = "A box containing everything you need to make a clone army. The disk inside cunningly disguised as a DNA data disk is used to give all clones a directive they must follow."
+ icon_state = "syndiebox"
+
+/obj/item/storage/box/clonearmy/PopulateContents()
+ var/static/items_inside = list(
+ /obj/item/disk/clonearmy = 1,
+ /obj/item/stack/sheet/iron = 15,
+ /obj/item/stack/sheet/glass = 4,
+ /obj/item/stack/cable_coil = 1,
+ /obj/item/circuitboard/machine/clonepod/experimental = 1,
+ /obj/item/circuitboard/machine/clonescanner = 1,
+ /obj/item/circuitboard/computer/cloning = 1,
+ /obj/item/stock_parts/manipulator/femto = 2, // The syndicate is so cool they gave you tier four parts. RIP my joke about tier 2 parts.
+ /obj/item/stock_parts/scanning_module/triphasic = 3,
+ /obj/item/stock_parts/micro_laser/quadultra = 1,
+ /obj/item/stock_parts/matter_bin/bluespace = 1,
+ /obj/item/wrench = 1,
+ /obj/item/screwdriver/nuke = 1,
+ /obj/item/multitool = 1, // For those who want space between the cloning console and pod.
+ /obj/item/language_manual/codespeak_manual/unlimited = 1,
+ /obj/item/implanter/radio/syndicate = 1, // So you can communicate with your clones, instead of having random evil clones roaming the halls with no direction.
+ /obj/item/paper/clone_guide = 1,)
+ generate_items_inside(items_inside, src)
+
+/obj/item/paper/clone_guide
+ name = "Clone Army User Manual" // Start and end shamelessly copied from contractor guide. I am not a good writer. This is also ugly.
+ default_raw_text = {"Welcome agent, thank you for purchasing the clone army kit.
\
+