mowing down the experimental cloner copypasta.

This commit is contained in:
Ghommie
2020-07-05 03:04:53 +02:00
parent 3ba077be71
commit 562b57095d
8 changed files with 218 additions and 414 deletions

View File

@@ -69,7 +69,7 @@
/turf/open/floor/plasteel/white, /turf/open/floor/plasteel/white,
/area/ruin/space/has_grav/powered/ancient_shuttle) /area/ruin/space/has_grav/powered/ancient_shuttle)
"j" = ( "j" = (
/obj/machinery/computer/prototype_cloning, /obj/machinery/computer/cloning/prototype,
/obj/machinery/light{ /obj/machinery/light{
dir = 1 dir = 1
}, },

View File

@@ -115,3 +115,7 @@
//these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified. //these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified.
#define PLANT_GENE_REMOVABLE (1<<0) #define PLANT_GENE_REMOVABLE (1<<0)
#define PLANT_GENE_EXTRACTABLE (1<<1) #define PLANT_GENE_EXTRACTABLE (1<<1)
#define CLONEPOD_GET_MIND 1
#define CLONEPOD_POLL_MIND 2
#define CLONEPOD_NO_MIND 3

View File

@@ -26,6 +26,7 @@
var/efficiency var/efficiency
var/datum/mind/clonemind var/datum/mind/clonemind
var/get_clone_mind = CLONEPOD_GET_MIND
var/grab_ghost_when = CLONER_MATURE_CLONE var/grab_ghost_when = CLONER_MATURE_CLONE
var/internal_radio = TRUE var/internal_radio = TRUE
@@ -139,6 +140,7 @@
return FALSE return FALSE
if(mess || attempting) if(mess || attempting)
return FALSE return FALSE
if(get_clone_mind == CLONEPOD_GET_MIND)
clonemind = locate(mindref) in SSticker.minds clonemind = locate(mindref) in SSticker.minds
if(!istype(clonemind)) //not a mind if(!istype(clonemind)) //not a mind
return FALSE return FALSE
@@ -192,8 +194,15 @@
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT) ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT)
H.Unconscious(80) H.Unconscious(80)
if(clonemind)
clonemind.transfer_to(H) clonemind.transfer_to(H)
else if(get_clone_mind == CLONEPOD_POLL_MIND)
var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone? (Don't ERP without permission from the original)", null, null, null, 100, H, POLL_IGNORE_CLONE)
if(LAZYLEN(candidates))
var/mob/C = pick(candidates)
H.key = C.key
if(grab_ghost_when == CLONER_FRESH_CLONE) if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost() H.grab_ghost()
to_chat(H, "<span class='notice'><b>Consciousness slowly creeps over you as your body regenerates.</b><br><i>So this is what cloning feels like?</i></span>") to_chat(H, "<span class='notice'><b>Consciousness slowly creeps over you as your body regenerates.</b><br><i>So this is what cloning feels like?</i></span>")
@@ -549,6 +558,17 @@
. += "cover-on" . += "cover-on"
. += "panel" . += "panel"
//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead
/obj/machinery/clonepod/experimental
name = "experimental cloning pod"
desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations."
icon = 'icons/obj/machines/cloning.dmi'
icon_state = "pod_0"
req_access = null
circuit = /obj/item/circuitboard/machine/clonepod/experimental
internal_radio = FALSE
get_clone_mind = CLONEPOD_POLL_MIND
/* /*
* Manual -- A big ol' manual. * Manual -- A big ol' manual.
*/ */

View File

@@ -8,6 +8,7 @@
circuit = /obj/item/circuitboard/computer/cloning circuit = /obj/item/circuitboard/computer/cloning
req_access = list(ACCESS_HEADS) //ONLY USED FOR RECORD DELETION RIGHT NOW. req_access = list(ACCESS_HEADS) //ONLY USED FOR RECORD DELETION RIGHT NOW.
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning. var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/clonepod_type = /obj/machinery/clonepod
var/list/pods //Linked cloning pods var/list/pods //Linked cloning pods
var/temp = "Inactive" var/temp = "Inactive"
var/scantemp_ckey var/scantemp_ckey
@@ -17,6 +18,7 @@
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything. var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text var/loading = 0 // Nice loading text
var/autoprocess = 0 var/autoprocess = 0
var/use_records = TRUE // Old experimental cloner.
var/list/records = list() var/list/records = list()
light_color = LIGHT_COLOR_BLUE light_color = LIGHT_COLOR_BLUE
@@ -36,23 +38,26 @@
return ..() return ..()
/obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null) /obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null)
if(pods) if(!pods)
return
for(var/P in pods) for(var/P in pods)
var/obj/machinery/clonepod/pod = P var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind) if(pod.occupant && pod.get_clone_mind == CLONEPOD_GET_MIND && pod.clonemind == mind)
return null return null
if(pod.is_operational() && !(pod.occupant || pod.mess)) if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod return pod
/obj/machinery/computer/cloning/proc/HasEfficientPod() /obj/machinery/computer/cloning/proc/HasEfficientPod()
if(pods) if(!pods)
return
for(var/P in pods) for(var/P in pods)
var/obj/machinery/clonepod/pod = P var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5) if(pod.is_operational() && pod.efficiency > 5)
return TRUE return TRUE
/obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null) /obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null)
if(pods) if(!pods)
return
for(var/P in pods) for(var/P in pods)
var/obj/machinery/clonepod/pod = P var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind) if(pod.occupant && pod.clonemind == mind)
@@ -103,12 +108,10 @@
return null return null
/obj/machinery/computer/cloning/proc/findcloner() /obj/machinery/computer/cloning/proc/findcloner()
var/obj/machinery/clonepod/podf = null var/obj/machinery/clonepod/podf
for(var/direction in GLOB.cardinals) for(var/direction in GLOB.cardinals)
podf = locate(clonepod_type, get_step(src, direction))
podf = locate(/obj/machinery/clonepod, get_step(src, direction)) if(podf?.is_operational())
if (!isnull(podf) && podf.is_operational())
AttachCloner(podf) AttachCloner(podf)
/obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod) /obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod)
@@ -132,7 +135,7 @@
else if(istype(W, /obj/item/multitool)) else if(istype(W, /obj/item/multitool))
var/obj/item/multitool/P = W var/obj/item/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod)) if(istype(P.buffer, clonepod_type))
if(get_area(P.buffer) != get_area(src)) if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>") to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null P.buffer = null
@@ -157,6 +160,7 @@
var/dat = "" var/dat = ""
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>" dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
if(use_records)
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL) if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
if(!autoprocess) if(!autoprocess)
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>" dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
@@ -190,18 +194,21 @@
else if(loading) else if(loading)
dat += "[scanner_occupant] => Scanning..." dat += "[scanner_occupant] => Scanning..."
else else
if(use_records)
if(scanner_occupant.ckey != scantemp_ckey) if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan" scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey scantemp_ckey = scanner_occupant.ckey
else
scantemp = "Ready to Clone"
dat += "[scanner_occupant] => [scantemp]" dat += "[scanner_occupant] => [scantemp]"
dat += "</div>" dat += "</div>"
if(scanner_occupant) if(scanner_occupant)
dat += "<a href='byond://?src=[REF(src)];scan=1'>Start Scan</a>" dat += "<a href='byond://?src=[REF(src)];scan=1'>[use_records ? "Start Scan" : "Clone"]</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>" dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else else
dat += "<span class='linkOff'>Start Scan</span>" dat += "<span class='linkOff'>[use_records ? "Start Scan" : "Clone"]</span>"
if(use_records)
// Database // Database
dat += "<h3>Database Functions</h3>" dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0) if (src.records.len && src.records.len > 0)
@@ -290,24 +297,19 @@
autoprocess = FALSE autoprocess = FALSE
STOP_PROCESSING(SSmachines, src) STOP_PROCESSING(SSmachines, src)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational()) else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = "" scantemp = ""
loading = 1 loading = TRUE
src.updateUsrDialog() src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...") say("Initiating scan...")
var/prev_locked = scanner.locked var/prev_locked = scanner.locked
scanner.locked = TRUE scanner.locked = TRUE
spawn(20) addtimer(CALLBACK(src, .proc/finish_scan, scanner.occupant, prev_locked), 2 SECONDS)
src.scan_occupant(scanner.occupant) . = TRUE
loading = 0
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
scanner.locked = prev_locked
//No locking an open scanner. //No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational()) else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
@@ -317,8 +319,17 @@
else else
scanner.locked = FALSE scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
. = TRUE
else if(href_list["view_rec"])
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
. = TRUE
if(. || !use_records)
return
if(href_list["view_rec"])
playsound(src, "terminal_type", 25, 0) playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records) src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record) if(active_record)
@@ -330,6 +341,7 @@
src.menu = 3 src.menu = 3
else else
src.temp = "Record missing." src.temp = "Record missing."
. = TRUE
else if (href_list["del_rec"]) else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3)) if ((!src.active_record) || (src.menu < 3))
@@ -353,8 +365,9 @@
else else
src.temp = "<font class='bad'>Access Denied.</font>" src.temp = "<font class='bad'>Access Denied.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if (href_list["disk"]) //Load or eject. else if (href_list["disk"] && use_records) //Load or eject.
switch(href_list["disk"]) switch(href_list["disk"])
if("load") if("load")
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields) if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
@@ -392,10 +405,7 @@
diskette.name = "data disk - '[src.diskette.fields["name"]]'" diskette.name = "data disk - '[src.diskette.fields["name"]]'"
src.temp = "Save successful." src.temp = "Save successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
. = TRUE
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
else if (href_list["clone"]) else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records) var/datum/data/record/C = find_record("id", href_list["clone"], records)
@@ -415,7 +425,7 @@
else if(pod.occupant) else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>" temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], R.fields["traumas"])) else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], C.fields["traumas"]))
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>" temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C) records.Remove(C)
@@ -429,15 +439,30 @@
else else
temp = "<font class='bad'>Data corruption.</font>" temp = "<font class='bad'>Data corruption.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if (href_list["menu"]) else if (href_list["menu"] && use_records)
src.menu = text2num(href_list["menu"]) menu = text2num(href_list["menu"])
playsound(src, "terminal_type", 25, 0) playsound(src, "terminal_type", 25, 0)
. = TRUE
/obj/machinery/computer/cloning/proc/finish_scan(mob/living/L, prev_locked)
if(!scanner)
return
src.add_fingerprint(usr) src.add_fingerprint(usr)
src.updateUsrDialog() src.updateUsrDialog()
return return
if(use_records)
scan_occupant(L)
else
clone_occupant(L)
loading = FALSE
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
scanner.locked = prev_locked
/obj/machinery/computer/cloning/proc/scan_occupant(occupant) /obj/machinery/computer/cloning/proc/scan_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant) var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna var/datum/dna/dna
@@ -455,30 +480,9 @@
if(isbrain(mob_occupant)) if(isbrain(mob_occupant))
dna = B.stored_dna dna = B.stored_dna
if(!istype(dna)) if(!can_scan(dna, mob_occupant, FALSE, has_bank_account))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if ((!mob_occupant.ckey) || (!mob_occupant.client))
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(SSeconomy.full_ancap && !has_bank_account)
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return return
var/datum/data/record/R = new() var/datum/data/record/R = new()
if(dna.species) if(dna.species)
// We store the instance rather than the path, because some // We store the instance rather than the path, because some
@@ -529,3 +533,78 @@
board.records = records board.records = records
scantemp = "Subject successfully scanned." scantemp = "Subject successfully scanned."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//Used by the experimental cloning computer.
/obj/machinery/computer/cloning/proc/clone_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!can_scan(dna, mob_occupant, TRUE))
return
var/clone_species
if(dna.species)
clone_species = dna.species
else
var/datum/species/rando_race = pick(GLOB.roundstart_races)
clone_species = rando_race.type
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
/obj/machinery/computer/cloning/proc/can_scan(datum/dna/dna, mob/living/mob_occupant, experimental = FALSE, datum/bank_account/account)
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(!experimental)
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if (!experimental)
if(!mob_occupant.ckey || !mob_occupant.client)
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(SSeconomy.full_ancap && !account)
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
return TRUE
//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
/obj/machinery/computer/cloning/prototype
name = "prototype cloning console"
desc = "Used to operate an experimental cloner."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning/prototype
clonepod_type = /obj/machinery/clonepod/experimental

View File

@@ -1,298 +0,0 @@
//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead
/obj/machinery/clonepod/experimental
name = "experimental cloning pod"
desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations."
icon = 'icons/obj/machines/cloning.dmi'
icon_state = "pod_0"
req_access = null
circuit = /obj/item/circuitboard/machine/clonepod/experimental
internal_radio = FALSE
//Start growing a human clone in the pod!
/obj/machinery/clonepod/experimental/growclone(ckey, clonename, ui, mutation_index, mindref, blood_type, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance, list/traumas)
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
attempting = TRUE //One at a time!!
countdown.start()
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
if(efficiency > 2)
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
H.dna.remove_mutation_group(unclean_mutations)
if(efficiency > 5 && prob(20))
H.easy_randmut(POSITIVE)
if(efficiency < 3 && prob(50))
var/mob/M = H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
if(ismob(M))
H = M
H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment.
occupant = H
if(!clonename) //to prevent null names
clonename = "clone ([rand(1,999)])"
H.real_name = clonename
icon_state = "pod_1"
//Get the clone body ready
maim_clone(H)
ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning")
ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning")
ADD_TRAIT(H, TRAIT_MUTE, "cloning")
ADD_TRAIT(H, TRAIT_NOBREATH, "cloning")
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H)
if(LAZYLEN(candidates))
var/mob/C = pick(candidates)
H.key = C.key
if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost()
to_chat(H, "<span class='notice'><b>Consciousness slowly creeps over you as your body regenerates.</b><br><i>So this is what cloning feels like?</i></span>")
if(grab_ghost_when == CLONER_MATURE_CLONE)
H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
to_chat(H.get_ghost(TRUE), "<span class='notice'>Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.</span>")
if(H)
H.faction |= factions
H.set_cloned_appearance()
H.suiciding = FALSE
attempting = FALSE
return TRUE
//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"
desc = "Used to operate an experimental cloner."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/prototype_cloning
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/list/pods //Linked experimental cloning pods
var/temp = "Inactive"
var/scantemp = "Ready to Scan"
var/loading = FALSE // Nice loading text
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/prototype_cloning/Initialize()
. = ..()
updatemodules(TRUE)
/obj/machinery/computer/prototype_cloning/Destroy()
if(pods)
for(var/P in pods)
DetachCloner(P)
pods = null
return ..()
/obj/machinery/computer/prototype_cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/experimental/pod = P
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/prototype_cloning/proc/updatemodules(findfirstcloner)
scanner = findscanner()
if(findfirstcloner && !LAZYLEN(pods))
findcloner()
/obj/machinery/computer/prototype_cloning/proc/findscanner()
var/obj/machinery/dna_scannernew/scannerf = null
// Loop through every direction
for(var/direction in GLOB.cardinals)
// Try to find a scanner in that direction
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, direction))
// If found and operational, return the scanner
if (!isnull(scannerf) && scannerf.is_operational())
return scannerf
// If no scanner was found, it will return null
return null
/obj/machinery/computer/prototype_cloning/proc/findcloner()
var/obj/machinery/clonepod/experimental/podf = null
for(var/direction in GLOB.cardinals)
podf = locate(/obj/machinery/clonepod/experimental, get_step(src, direction))
if (!isnull(podf) && podf.is_operational())
AttachCloner(podf)
/obj/machinery/computer/prototype_cloning/proc/AttachCloner(obj/machinery/clonepod/experimental/pod)
if(!pod.connected)
pod.connected = src
LAZYADD(pods, pod)
/obj/machinery/computer/prototype_cloning/proc/DetachCloner(obj/machinery/clonepod/experimental/pod)
pod.connected = null
LAZYREMOVE(pods, pod)
/obj/machinery/computer/prototype_cloning/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/multitool))
var/obj/item/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod/experimental))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/clonepod/experimental/pod = P.buffer
if(pod.connected)
pod.connected.DetachCloner(pod)
AttachCloner(pod)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-</font color>")
return
else
return ..()
/obj/machinery/computer/prototype_cloning/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/prototype_cloning/interact(mob/user)
user.set_machine(src)
add_fingerprint(user)
if(..())
return
updatemodules(TRUE)
var/dat = ""
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
if (isnull(src.scanner) || !LAZYLEN(pods))
dat += "<h3>Modules</h3>"
//dat += "<a href='byond://?src=[REF(src)];relmodules=1'>Reload Modules</a>"
if (isnull(src.scanner))
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
if (!LAZYLEN(pods))
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
// Scan-n-Clone
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
dat += "<h3>Cloning</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
scantemp = "Ready to Clone"
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=[REF(src)];clone=1'>Clone</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Clone</span>"
var/datum/browser/popup = new(user, "cloning", "Prototype Cloning System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/prototype_cloning/Topic(href, href_list)
if(..())
return
if(loading)
return
else if ((href_list["clone"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = TRUE
updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
spawn(20)
clone_occupant(scanner.occupant)
loading = FALSE
updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
if ((!scanner.locked) && (scanner.occupant))
scanner.locked = TRUE
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
add_fingerprint(usr)
updateUsrDialog()
return
/obj/machinery/computer/prototype_cloning/proc/clone_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
var/clone_species
if(dna.species)
clone_species = dna.species
else
var/datum/species/rando_race = pick(GLOB.roundstart_races)
clone_species = rando_race.type
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)

View File

@@ -116,9 +116,9 @@
build_path = /obj/machinery/computer/cloning build_path = /obj/machinery/computer/cloning
var/list/records = list() var/list/records = list()
/obj/item/circuitboard/computer/prototype_cloning /obj/item/circuitboard/computer/cloning/prototype
name = "Prototype Cloning (Computer Board)" name = "Prototype Cloning (Computer Board)"
build_path = /obj/machinery/computer/prototype_cloning build_path = /obj/machinery/computer/cloning/prototype
/obj/item/circuitboard/computer/arcade/battle /obj/item/circuitboard/computer/arcade/battle
name = "Arcade Battle (Computer Board)" name = "Arcade Battle (Computer Board)"

View File

@@ -63,7 +63,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
startHunger = M.nutrition startHunger = M.nutrition
if(pollStarted == FALSE) if(pollStarted == FALSE)
pollStarted = TRUE pollStarted = TRUE
candies = pollGhostCandidates("Do you want and agree to play as a clone of [M], respect their character and not engage in ERP without permission from the original?", ignore_category = POLL_IGNORE_CLONE) candies = pollGhostCandidates("Do you want to play as [clonename]'s defective clone? (Don't ERP without permission from the original)", ignore_category = POLL_IGNORE_CLONE)
log_reagent("FERMICHEM: [M] ckey: [M.key] has taken SDGF, and ghosts have been polled.") log_reagent("FERMICHEM: [M] ckey: [M.key] has taken SDGF, and ghosts have been polled.")
if(20 to INFINITY) if(20 to INFINITY)
if(LAZYLEN(candies) && playerClone == FALSE) //If there's candidates, clone the person and put them in there! if(LAZYLEN(candies) && playerClone == FALSE) //If there's candidates, clone the person and put them in there!

View File

@@ -743,7 +743,6 @@
#include "code\game\machinery\dna_scanner.dm" #include "code\game\machinery\dna_scanner.dm"
#include "code\game\machinery\doppler_array.dm" #include "code\game\machinery\doppler_array.dm"
#include "code\game\machinery\droneDispenser.dm" #include "code\game\machinery\droneDispenser.dm"
#include "code\game\machinery\exp_cloner.dm"
#include "code\game\machinery\firealarm.dm" #include "code\game\machinery\firealarm.dm"
#include "code\game\machinery\flasher.dm" #include "code\game\machinery\flasher.dm"
#include "code\game\machinery\gulag_item_reclaimer.dm" #include "code\game\machinery\gulag_item_reclaimer.dm"