")
if(is_operational() && mob_occupant)
if(mob_occupant.stat != DEAD)
. += "Current clone cycle is [round(get_completion())]% complete."
/obj/machinery/clonepod/return_air()
// We want to simulate the clone not being in contact with
// the atmosphere, so we'll put them in a constant pressure
// nitrogen. They don't need to breathe while cloning anyway.
var/static/datum/gas_mixture/immutable/cloner/GM //global so that there's only one instance made for all cloning pods
if(!GM)
GM = new
return GM
/obj/machinery/clonepod/proc/get_completion()
. = FALSE
var/mob/living/mob_occupant = occupant
if(mob_occupant)
. = (100 * ((mob_occupant.health + 100) / (heal_level + 100)))
/obj/machinery/clonepod/attack_ai(mob/user)
return examine(user)
//Start growing a human clone in the pod!
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, blood_type, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance, list/traumas, fatness) //GS13 EDIT
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
if(get_clone_mind == CLONEPOD_GET_MIND)
clonemind = locate(mindref) in SSticker.minds
if(!istype(clonemind)) //not a mind
return FALSE
if(!QDELETED(clonemind.current))
if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
return FALSE
if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
return FALSE
if(AmBloodsucker(clonemind.current)) //If the mind is a bloodsucker
return FALSE
if(clonemind.active) //somebody is using that mind
if( ckey(clonemind.key)!=ckey )
return FALSE
else
// get_ghost() will fail if they're unable to reenter their body
var/mob/dead/observer/G = clonemind.get_ghost()
if(!G)
return FALSE
if(G.suiciding) // The ghost came from a body that is suiciding.
return FALSE
if(clonemind.damnation_type) //Can't clone the damned.
INVOKE_ASYNC(src, PROC_REF(horrifyingsound))
mess = TRUE
update_icon()
return FALSE
current_insurance = insurance
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)
H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) //100% bad mutation. Can be cured with mutadone.
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
//Get the clone body ready
maim_clone(H)
ADD_TRAIT(H, TRAIT_MUTATION_STASIS, CLONING_POD_TRAIT)
ADD_TRAIT(H, TRAIT_STABLEHEART, CLONING_POD_TRAIT)
ADD_TRAIT(H, TRAIT_STABLELIVER, CLONING_POD_TRAIT)
ADD_TRAIT(H, TRAIT_EMOTEMUTE, CLONING_POD_TRAIT)
ADD_TRAIT(H, TRAIT_MUTE, CLONING_POD_TRAIT)
ADD_TRAIT(H, TRAIT_NOBREATH, CLONING_POD_TRAIT)
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT)
H.Unconscious(80)
if(clonemind)
clonemind.transfer_to(H)
// GS13 EDIT START
if(fatness)
H.fatness_real = fatness
// GS13 EDIT END
else if(get_clone_mind == CLONEPOD_POLL_MIND)
poll_for_mind(H, clonename)
if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost()
to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?")
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), "Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.")
if(H)
H.faction |= factions
for(var/V in quirks)
var/datum/quirk/Q = new V(H)
Q.on_clone(quirks[V])
for(var/t in traumas)
var/datum/brain_trauma/BT = t
var/datum/brain_trauma/cloned_trauma = BT.on_clone()
if(cloned_trauma)
H.gain_trauma(cloned_trauma, BT.resilience)
H.set_cloned_appearance()
H.give_genitals(TRUE)
H.suiciding = FALSE
attempting = FALSE
return TRUE
/obj/machinery/clonepod/proc/poll_for_mind(mob/living/carbon/human/H, clonename)
set waitfor = FALSE
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
//Grow clones to maturity then kick them out. FREELOADERS
/obj/machinery/clonepod/process()
var/mob/living/mob_occupant = occupant
if(!is_operational()) //Autoeject if power is lost
if(mob_occupant)
go_out()
mob_occupant.copy_from_prefs_vr()
connected_message("Clone Ejected: Loss of power.")
else if(mob_occupant && (mob_occupant.loc == src))
if(SSeconomy.full_ancap)
if(!current_insurance)
go_out()
connected_message("Clone Ejected: No bank account.")
if(internal_radio)
SPEAK("The cloning of [mob_occupant.real_name] has been terminated due to no bank account to draw payment from.")
else if(!current_insurance.adjust_money(-fair_market_price))
go_out()
connected_message("Clone Ejected: Out of Money.")
if(internal_radio)
SPEAK("The cloning of [mob_occupant.real_name] has been ended prematurely due to being unable to pay.")
else
var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
if(D)
D.adjust_money(fair_market_price)
if(mob_occupant && (mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes. connected_message("Clone Rejected: Deceased.")
if(internal_radio)
SPEAK("The cloning has been \
aborted due to unrecoverable tissue failure.")
go_out()
mob_occupant.copy_from_prefs_vr()
else if(mob_occupant && mob_occupant.cloneloss > (100 - heal_level))
mob_occupant.Unconscious(80)
var/dmg_mult = CONFIG_GET(number/damage_multiplier)
//Slowly get that clone healed and finished.
mob_occupant.adjustCloneLoss(-((speed_coeff / 2) * dmg_mult))
var/progress = CLONE_INITIAL_DAMAGE - mob_occupant.getCloneLoss()
// To avoid the default cloner making incomplete clones
progress += (100 - MINIMUM_HEAL_LEVEL)
var/milestone = CLONE_INITIAL_DAMAGE / flesh_number
var/installed = flesh_number - unattached_flesh.len
if((progress / milestone) >= installed)
// attach some flesh
var/obj/item/I = pick_n_take(unattached_flesh)
if(isorgan(I))
var/obj/item/organ/O = I
O.organ_flags &= ~ORGAN_FROZEN
O.Insert(mob_occupant)
else if(isbodypart(I))
var/obj/item/bodypart/BP = I
BP.attach_limb(mob_occupant)
use_power(7500) //This might need tweaking.
else if((mob_occupant && mob_occupant.cloneloss <= (100 - heal_level)))
connected_message("Cloning Process Complete.")
if(internal_radio)
SPEAK("The cloning cycle is complete.")
// If the cloner is upgraded to debugging high levels, sometimes
// organs and limbs can be missing.
for(var/i in unattached_flesh)
if(isorgan(i))
var/obj/item/organ/O = i
O.organ_flags &= ~ORGAN_FROZEN
O.Insert(mob_occupant)
else if(isbodypart(i))
var/obj/item/bodypart/BP = i
BP.attach_limb(mob_occupant)
go_out()
mob_occupant.copy_from_prefs_vr()
else if (!mob_occupant || mob_occupant.loc != src)
occupant = null
use_power(200)
update_icon()
//Let's unlock this early I guess. Might be too early, needs tweaking.
/obj/machinery/clonepod/attackby(obj/item/W, mob/user, params)
if(!(occupant || mess))
if(default_deconstruction_screwdriver(user, "[icon_state]_maintenance", "[initial(icon_state)]",W))
return
if(default_deconstruction_crowbar(W))
return
if(W.tool_behaviour == TOOL_MULTITOOL)
if(istype(W.buffer, /obj/machinery/computer/cloning))
if(get_area(W.buffer) != get_area(src))
to_chat(user, "-% Cannot link machines across power zones. Buffer cleared %-")
W.buffer = null
return
to_chat(user, "-% Successfully linked [W.buffer] with [src] %-")
var/obj/machinery/computer/cloning/comp = W.buffer
if(connected)
connected.DetachCloner(src)
comp.AttachCloner(src)
else
W.buffer = src
to_chat(user, "-% Successfully stored [REF(W.buffer)] [W.buffer] in buffer %-")
return
var/mob/living/mob_occupant = occupant
if(W.GetID())
if(!check_access(W))
to_chat(user, "Access Denied.")
return
if(!(mob_occupant || mess))
to_chat(user, "Error: Pod has no occupant.")
return
else
connected_message("Emergency Ejection")
SPEAK("An emergency ejection of the current clone has occurred. Survival not guaranteed.")
to_chat(user, "You force an emergency ejection. ")
go_out()
mob_occupant.copy_from_prefs_vr()
else
return ..()
/obj/machinery/clonepod/emag_act(mob/user)
. = ..()
if(!occupant)
return
to_chat(user, "You corrupt the genetic compiler.")
malfunction()
return TRUE
//Put messages in the connected computer's temp var for display.
/obj/machinery/clonepod/proc/connected_message(message)
if ((isnull(connected)) || (!istype(connected, /obj/machinery/computer/cloning)))
return FALSE
if (!message)
return FALSE
connected.temp = message
connected.updateUsrDialog()
return TRUE
/obj/machinery/clonepod/proc/go_out()
countdown.stop()
var/mob/living/mob_occupant = occupant
var/turf/T = get_turf(src)
if(mess) //Clean that mess and dump those gibs!
for(var/obj/fl in unattached_flesh)
fl.forceMove(T)
if(istype(fl, /obj/item/organ))
var/obj/item/organ/O = fl
O.organ_flags &= ~ORGAN_FROZEN
unattached_flesh.Cut()
mess = FALSE
if(mob_occupant)
mob_occupant.spawn_gibs()
audible_message("You hear a splat.")
update_icon()
return
if(!mob_occupant)
return
current_insurance = null
REMOVE_TRAIT(mob_occupant, TRAIT_STABLEHEART, CLONING_POD_TRAIT)
REMOVE_TRAIT(mob_occupant, TRAIT_MUTATION_STASIS, CLONING_POD_TRAIT)
REMOVE_TRAIT(mob_occupant, TRAIT_STABLELIVER, CLONING_POD_TRAIT)
REMOVE_TRAIT(mob_occupant, TRAIT_EMOTEMUTE, CLONING_POD_TRAIT)
REMOVE_TRAIT(mob_occupant, TRAIT_MUTE, CLONING_POD_TRAIT)
REMOVE_TRAIT(mob_occupant, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT)
REMOVE_TRAIT(mob_occupant, TRAIT_NOBREATH, CLONING_POD_TRAIT)
if(grab_ghost_when == CLONER_MATURE_CLONE)
mob_occupant.grab_ghost()
to_chat(occupant, "There is a bright flash!
You feel like a new being.")
mob_occupant.flash_act()
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_ON_CLONE]
if(policy)
to_chat(occupant, policy)
occupant.log_message("revived using cloning.", LOG_GAME)
mob_occupant.adjustOrganLoss(ORGAN_SLOT_BRAIN, mob_occupant.getCloneLoss())
occupant.forceMove(T)
update_icon()
mob_occupant.domutcheck(1) //Waiting until they're out before possible monkeyizing. The 1 argument forces powers to manifest.
for(var/fl in unattached_flesh)
qdel(fl)
unattached_flesh.Cut()
occupant = null
/obj/machinery/clonepod/proc/malfunction()
var/mob/living/mob_occupant = occupant
if(mob_occupant)
connected_message("Critical Error!")
SPEAK("Critical error! Please contact a Thinktronic Systems \
technician, as your warranty may be affected.")
mess = TRUE
maim_clone(mob_occupant) //Remove every bit that's grown back so far to drop later, also destroys bits that haven't grown yet
update_icon()
if(mob_occupant.mind != clonemind)
clonemind.transfer_to(mob_occupant)
mob_occupant.grab_ghost() // We really just want to make you suffer.
flash_color(mob_occupant, flash_color="#960000", flash_time=100)
to_chat(mob_occupant, "Agony blazes across your consciousness as your body is torn apart.
Is this what dying is like? Yes it is.")
playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 50, 0)
SEND_SOUND(mob_occupant, sound('sound/hallucinations/veryfar_noise.ogg',0,1,50))
QDEL_IN(mob_occupant, 40)
/obj/machinery/clonepod/relaymove(mob/user)
container_resist(user)
/obj/machinery/clonepod/container_resist(mob/living/user)
if(user.stat == CONSCIOUS)
go_out()
/obj/machinery/clonepod/emp_act(severity)
. = ..()
if (!(. & EMP_PROTECT_SELF))
var/mob/living/mob_occupant = occupant
if(mob_occupant && prob((25+severity/1.34)/efficiency))
connected_message(Gibberish("EMP-caused Accidental Ejection", 0))
SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of, ERROR: John Doe, prematurely." ,0))
mob_occupant.copy_from_prefs_vr()
go_out()
/obj/machinery/clonepod/ex_act(severity, target, origin)
..()
if(!QDELETED(src))
go_out()
/obj/machinery/clonepod/handle_atom_del(atom/A)
if(A == occupant)
occupant = null
countdown.stop()
/obj/machinery/clonepod/proc/horrifyingsound()
for(var/i in 1 to 5)
playsound(loc,pick('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg'), 100, rand(0.95,1.05))
sleep(1)
sleep(10)
playsound(loc,'sound/hallucinations/wail.ogg',100,1)
/obj/machinery/clonepod/deconstruct(disassembled = TRUE)
if(occupant)
go_out()
..()
/obj/machinery/clonepod/proc/maim_clone(mob/living/carbon/human/H)
if(!unattached_flesh)
unattached_flesh = list()
else
for(var/fl in unattached_flesh)
qdel(fl)
unattached_flesh.Cut()
H.setCloneLoss(CLONE_INITIAL_DAMAGE) //Yeah, clones start with very low health, not with random, because why would they start with random health
// In addition to being cellularly damaged, they also have no limbs or internal organs.
// Applying brainloss is done when the clone leaves the pod, so application of traumas can happen.
// based on the level of damage sustained.
if(!HAS_TRAIT(H, TRAIT_NODISMEMBER))
var/static/list/zones = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
for(var/zone in zones)
var/obj/item/bodypart/BP = H.get_bodypart(zone)
if(BP)
BP.drop_limb()
BP.forceMove(src)
unattached_flesh += BP
for(var/o in H.internal_organs)
var/obj/item/organ/organ = o
if(!istype(organ) || (organ.organ_flags & ORGAN_VITAL))
continue
organ.organ_flags |= ORGAN_FROZEN
organ.Remove(TRUE)
organ.forceMove(src)
unattached_flesh += organ
flesh_number = unattached_flesh.len
/obj/machinery/clonepod/update_icon_state()
if(mess)
icon_state = "pod_g"
else if(occupant)
icon_state = "pod_1"
else
icon_state = "pod_0"
if(panel_open)
icon_state = "pod_0_maintenance"
/obj/machinery/clonepod/update_overlays()
. = ..()
if(mess)
var/mutable_appearance/gib1 = mutable_appearance(CRYOMOBS, "gibup")
var/mutable_appearance/gib2 = mutable_appearance(CRYOMOBS, "gibdown")
gib1.pixel_y = 27 + round(sin(world.time) * 3)
gib1.pixel_x = round(sin(world.time * 3))
gib2.pixel_y = 27 + round(cos(world.time) * 3)
gib2.pixel_x = round(cos(world.time * 3))
. += gib2
. += gib1
else if(occupant)
var/mutable_appearance/occupant_overlay
var/completion = (flesh_number - unattached_flesh.len) / flesh_number
if(unattached_flesh.len <= 0)
occupant_overlay = mutable_appearance(occupant.icon, occupant.icon_state)
occupant_overlay.copy_overlays(occupant)
. += "cover-on"
else
occupant_overlay = mutable_appearance(CRYOMOBS, "clone_meat")
var/matrix/tform = matrix()
tform.Scale(completion)
tform.Turn(cos(world.time * 2) * 3)
occupant_overlay.transform = tform
occupant_overlay.appearance_flags = NONE
occupant_overlay.dir = SOUTH
occupant_overlay.pixel_y = 27 + round(sin(world.time) * 3)
occupant_overlay.pixel_x = round(sin(world.time * 3))
. += occupant_overlay
. += "cover-on"
. += "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.
*/
/obj/item/paper/guides/jobs/medical/cloning
name = "paper - 'H-87 Cloning Apparatus Manual"
info = {"Getting Started
Congratulations, your station has purchased the H-87 industrial cloning device!
Using the H-87 is almost as simple as brain surgery! Simply insert the target humanoid into the scanning chamber and select the scan option to create a new profile!
That's all there is to it!
Notice, cloning system cannot scan inorganic life or small primates. Scan may fail if subject has suffered extreme brain damage.
Clone profiles may be viewed through the profiles menu. Scanning implants a complementary HEALTH MONITOR IMPLANT into the subject, which may be viewed from each profile.
Profile Deletion has been restricted to \[Station Head\] level access.
Cloning from a profile
Cloning is as simple as pressing the CLONE option at the bottom of the desired profile.
Per your company's EMPLOYEE PRIVACY RIGHTS agreement, the H-87 has been blocked from cloning crewmembers while they are still alive.
The provided CLONEPOD SYSTEM will produce the desired clone. Standard clone maturation times (With SPEEDCLONE technology) are roughly 90 seconds.
The cloning pod may be unlocked early with any \[Medical Researcher\] ID after initial maturation is complete.
Please note that resulting clones may have a small DEVELOPMENTAL DEFECT as a result of genetic drift.
Profile Management
The H-87 (as well as your station's standard genetics machine) can accept STANDARD DATA DISKETTES.
These diskettes are used to transfer genetic information between machines and profiles.
A load/save dialog will become available in each profile if a disk is inserted.
A good diskette is a great way to counter aforementioned genetic drift!
This technology produced under license from Thinktronic Systems, LTD."}
#undef CLONE_INITIAL_DAMAGE
#undef SPEAK
#undef MINIMUM_HEAL_LEVEL