diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm
index 3828392f99e..11393957fc1 100644
--- a/code/__DEFINES/genetics.dm
+++ b/code/__DEFINES/genetics.dm
@@ -111,3 +111,6 @@
#define GENETIC_DAMAGE_STAGE_1 80
#define GENETIC_DAMAGE_STAGE_2 65
#define GENETIC_DAMAGE_STAGE_3 35
+
+#define CLONER_FRESH_CLONE "fresh"
+#define CLONER_MATURE_CLONE "mature"
\ No newline at end of file
diff --git a/code/controllers/Processes/fast_process.dm b/code/controllers/Processes/fast_process.dm
index 85a688c3d12..72ed0e68fee 100644
--- a/code/controllers/Processes/fast_process.dm
+++ b/code/controllers/Processes/fast_process.dm
@@ -6,7 +6,7 @@
/datum/controller/process/fast_process/statProcess()
..()
- stat(null, "[fast_processing.len] fast machines")
+ stat(null, "[fast_processing.len] fast processes")
/datum/controller/process/fast_process/doWork()
for(last_object in fast_processing)
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index a46c02edb2c..f07cd94438d 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -14,7 +14,7 @@
icon = 'icons/obj/cloning.dmi'
icon_state = "pod_0"
req_access = list(access_genetics) //For premature unlocking.
- var/mob/living/occupant
+ var/mob/living/carbon/human/occupant
var/heal_level = 90 //The clone is released once its health reaches this level.
var/locked = 0
var/obj/machinery/computer/cloning/connected = null //So we remember the connected clone machine.
@@ -25,19 +25,34 @@
var/speed_coeff
var/efficiency
+ var/datum/mind/clonemind
+ var/grab_ghost_when = CLONER_MATURE_CLONE
+
+ var/obj/item/device/radio/Radio
+ var/radio_announce = 0
+
+ var/obj/effect/countdown/clonepod/countdown
+
light_color = LIGHT_COLOR_PURE_GREEN
- power_change()
- ..()
- if(!(stat & (BROKEN|NOPOWER)))
- set_light(2)
- else
- set_light(0)
+
+/obj/machinery/clonepod/power_change()
+ ..()
+ if(!(stat & (BROKEN|NOPOWER)))
+ set_light(2)
+ else
+ set_light(0)
/obj/machinery/clonepod/biomass
biomass = CLONE_BIOMASS
/obj/machinery/clonepod/New()
..()
+ countdown = new(src)
+
+ Radio = new /obj/item/device/radio(src)
+ Radio.listening = 0
+ Radio.config(list("Medical" = 0))
+
component_parts = list()
component_parts += new /obj/item/weapon/circuitboard/clonepod(null)
component_parts += new /obj/item/weapon/stock_parts/scanning_module(null)
@@ -67,6 +82,12 @@
/obj/machinery/clonepod/Destroy()
if(connected)
connected.pods -= src
+ if(Radio)
+ qdel(Radio)
+ Radio = null
+ if(countdown)
+ qdel(countdown)
+ countdown = null
return ..()
/obj/machinery/clonepod/RefreshParts()
@@ -97,49 +118,29 @@
name = "data disk - 'God Emperor of Mankind'"
read_only = 1
- New()
- Initialize()
- buf.types=DNA2_BUF_UE|DNA2_BUF_UI
- //data = "066000033000000000AF00330660FF4DB002690"
- //data = "0C80C80C80C80C80C8000000000000161FBDDEF" - Farmer Jeff
- buf.dna.real_name="God Emperor of Mankind"
- buf.dna.unique_enzymes = md5(buf.dna.real_name)
- buf.dna.UI=list(0x066,0x000,0x033,0x000,0x000,0x000,0xAF0,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x033,0x066,0x0FF,0x4DB,0x002,0x690,0x000,0x000)
- //buf.dna.UI=list(0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x000,0x000,0x000,0x000,0x161,0xFBD,0xDEF) // Farmer Jeff
- buf.dna.UpdateUI()
+/obj/item/weapon/disk/data/demo/New()
+ Initialize()
+ buf.types=DNA2_BUF_UE|DNA2_BUF_UI
+ //data = "066000033000000000AF00330660FF4DB002690"
+ //data = "0C80C80C80C80C80C8000000000000161FBDDEF" - Farmer Jeff
+ buf.dna.real_name="God Emperor of Mankind"
+ buf.dna.unique_enzymes = md5(buf.dna.real_name)
+ buf.dna.UI=list(0x066,0x000,0x033,0x000,0x000,0x000,0xAF0,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x033,0x066,0x0FF,0x4DB,0x002,0x690,0x000,0x000)
+ //buf.dna.UI=list(0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x000,0x000,0x000,0x000,0x161,0xFBD,0xDEF) // Farmer Jeff
+ buf.dna.UpdateUI()
/obj/item/weapon/disk/data/monkey
name = "data disk - 'Mr. Muggles'"
read_only = 1
- New()
- Initialize()
- buf.types=DNA2_BUF_SE
- var/list/new_SE=list(0x098,0x3E8,0x403,0x44C,0x39F,0x4B0,0x59D,0x514,0x5FC,0x578,0x5DC,0x640,0x6A4)
- for(var/i=new_SE.len;i<=DNA_SE_LENGTH;i++)
- new_SE += rand(1,1024)
- buf.dna.SE=new_SE
- buf.dna.SetSEValueRange(MONKEYBLOCK,0xDAC, 0xFFF)
-
-
-//Find a dead mob with a brain and client.
-/proc/find_dead_player(var/find_key)
- if(isnull(find_key))
- return
-
- var/mob/selected = null
- for(var/mob/M in player_list)
- //Dead people only thanks!
- if((M.stat != 2) || (!M.client))
- continue
- //They need a brain!
- if(istype(M, /mob/living/carbon/human) && !M.get_int_organ(/obj/item/organ/internal/brain))
- continue
-
- if(M.ckey == find_key)
- selected = M
- break
- return selected
+/obj/item/weapon/disk/data/monkey/New()
+ Initialize()
+ buf.types=DNA2_BUF_SE
+ var/list/new_SE=list(0x098,0x3E8,0x403,0x44C,0x39F,0x4B0,0x59D,0x514,0x5FC,0x578,0x5DC,0x640,0x6A4)
+ for(var/i=new_SE.len;i<=DNA_SE_LENGTH;i++)
+ new_SE += rand(1,1024)
+ buf.dna.SE=new_SE
+ buf.dna.SetSEValueRange(MONKEYBLOCK,0xDAC, 0xFFF)
//Disk stuff.
/obj/item/weapon/disk/data/New()
@@ -173,44 +174,47 @@
healthstring = "ERROR"
return healthstring
-/obj/machinery/clonepod/attack_ai(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/clonepod/attack_hand(mob/user as mob)
- if((isnull(occupant)) || (stat & NOPOWER))
- if(mess)
- go_out()
- return
- if((!isnull(occupant)) && (occupant.stat != 2))
- var/completion = (100 * ((occupant.health + 100) / (heal_level + 100)))
- to_chat(user, "Current clone cycle is [round(completion)]% complete.")
- return
-
//Clonepod
+/obj/machinery/clonepod/examine(mob/user)
+ ..()
+ if(mess)
+ to_chat(user, "It's filled with blood and viscera. You swear you can see it moving...")
+ if(!occupant || stat & (NOPOWER|BROKEN))
+ return
+ if(occupant && occupant.stat != DEAD)
+ to_chat(user, "Current clone cycle is [round(get_completion())]% complete.")
+
+/obj/machinery/clonepod/proc/get_completion()
+ . = (100 * ((occupant.health + 100) / (heal_level + 100)))
+
+/obj/machinery/clonepod/attack_ai(mob/user)
+ return examine(user)
+
+//Radio Announcement
+
+/obj/machinery/clonepod/proc/announce_radio_message(message)
+ if(radio_announce)
+ Radio.autosay(message, name, "Medical", list(z))
+
+
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/proc/growclone(var/datum/dna2/record/R)
+/obj/machinery/clonepod/proc/growclone(datum/dna2/record/R)
if(mess || attempting || panel_open || stat & (NOPOWER|BROKEN))
return 0
- var/datum/mind/clonemind = locate(R.mind)
+ clonemind = locate(R.mind)
if(!istype(clonemind)) //not a mind
return 0
if( clonemind.current && clonemind.current.stat != DEAD ) //mind is associated with a non-dead body
return 0
if(clonemind.active) //somebody is using that mind
- if( ckey(clonemind.key)!=R.ckey )
+ if(ckey(clonemind.key) != R.ckey)
return 0
else
- for(var/mob/M in player_list)
- if(M.ckey == R.ckey)
- if(istype(M, /mob/dead/observer))
- var/mob/dead/observer/G = M
- if(G.can_reenter_corpse)
- break
- if(istype(M, /mob/living/simple_animal))
- if(M in respawnable_list)
- break
- return 0
+ // get_ghost() will fail if they're unable to reenter their body
+ var/mob/dead/observer/G = clonemind.get_ghost()
+ if(!G)
+ return 0
if(biomass >= CLONE_BIOMASS)
biomass -= CLONE_BIOMASS
@@ -219,6 +223,7 @@
attempting = 1 //One at a time!!
locked = 1
+ countdown.start()
eject_wait = 1
spawn(30)
@@ -239,8 +244,16 @@
//Here let's calculate their health so the pod doesn't immediately eject them!!!
H.updatehealth()
- clonemind.transfer_to(H)
- to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?")
+ if(grab_ghost_when == CLONER_FRESH_CLONE)
+ clonemind.transfer_to(H)
+ H.ckey = R.ckey
+ to_chat(H, {"Consciousness slowly creeps over you
+ as your body regenerates.
So this is what cloning
+ feels like?"})
+ else if(grab_ghost_when == CLONER_MATURE_CLONE)
+ to_chat(clonemind.current, {"Your body is
+ beginning to regenerate in a cloning pod. You will
+ become conscious when it is complete."})
// -- Mode/mind specific stuff goes here
callHook("clone", list(H))
@@ -299,20 +312,20 @@
biomass += BIOMASS_MEAT_AMOUNT
show_message = 1
if(show_message)
- visible_message("\The [src] sucks in and processes the nearby biomass.")
+ visible_message("[src] sucks in and processes the nearby biomass.")
if(stat & NOPOWER) //Autoeject if power is lost
if(occupant)
locked = 0
go_out()
- return
+ connected_message("Clone Ejected: Loss of power.")
- if((occupant) && (occupant.loc == src))
- if((occupant.stat == DEAD) || (occupant.suiciding) || !occupant.key) //Autoeject corpses and suiciding dudes.
+ else if((occupant) && (occupant.loc == src))
+ if((occupant.stat == DEAD) || (occupant.suiciding)) //Autoeject corpses and suiciding dudes.
locked = 0
+ announce_radio_message("The cloning of [occupant] has been aborted due to unrecoverable tissue failure.")
go_out()
connected_message("Clone Rejected: Deceased.")
- return
else if(occupant.cloneloss > (100 - heal_level))
occupant.Paralyse(4)
@@ -331,48 +344,40 @@
occupant.adjustOxyLoss(-4)
use_power(7500) //This might need tweaking.
- return
else if((occupant.cloneloss <= (100 - heal_level)) && (!eject_wait))
connected_message("Cloning Process Complete.")
+ announce_radio_message("The cloning cycle of [occupant] is complete.")
locked = 0
go_out()
- return
else if((!occupant) || (occupant.loc != src))
occupant = null
if(locked)
locked = 0
- //use_power(200)
- return
-
- return
+ update_icon()
+ use_power(200)
//Let's unlock this early I guess. Might be too early, needs tweaking.
-/obj/machinery/clonepod/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
- if(istype(W, /obj/item/weapon/screwdriver))
- if(occupant || mess || locked)
- to_chat(user, "The maintenance panel is locked.")
+/obj/machinery/clonepod/attackby(obj/item/weapon/W, mob/user, params)
+ if(!(occupant || mess || locked))
+ if(default_deconstruction_screwdriver(user, "[icon_state]_maintenance", "[initial(icon_state)]", W))
return
- default_deconstruction_screwdriver(user, "[icon_state]_maintenance", "[initial(icon_state)]", W)
- return
if(exchange_parts(user, W))
return
- if(istype(W, /obj/item/weapon/crowbar))
- if(panel_open)
- default_deconstruction_crowbar(W)
+ if(default_deconstruction_crowbar(W))
return
- if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
+ if(W.GetID())
if(!check_access(W))
- to_chat(user, "\red Access Denied.")
+ to_chat(user, "Access Denied.")
return
- if((!locked) || (isnull(occupant)))
+ if (!locked || !occupant)
return
- if((occupant.health < -20) && (occupant.stat != 2))
- to_chat(user, "\red Access Refused.")
+ if(occupant.health < -20 && occupant.stat != DEAD)
+ to_chat(user, "Access Refused. Patient status still unstable.")
return
else
locked = 0
@@ -408,16 +413,15 @@
else
..()
-/obj/machinery/clonepod/emag_act(user as mob)
+/obj/machinery/clonepod/emag_act(user)
if(isnull(occupant))
return
to_chat(user, "You force an emergency ejection.")
locked = 0
go_out()
- return
//Put messages in the connected computer's temp var for display.
-/obj/machinery/clonepod/proc/connected_message(var/message)
+/obj/machinery/clonepod/proc/connected_message(message)
if((isnull(connected)) || (!istype(connected, /obj/machinery/computer/cloning)))
return 0
if(!message)
@@ -434,49 +438,56 @@
if(!usr)
return
- if(usr.stat != 0)
+ if(usr.incapacitated())
return
- go_out(usr)
+ go_out()
add_fingerprint(usr)
- return
-/obj/machinery/clonepod/proc/go_out(user)
+/obj/machinery/clonepod/proc/go_out()
+ if(locked)
+ return
+ countdown.stop()
+
if(mess) //Clean that mess and dump those gibs!
- if(occupant)
- return
mess = 0
gibs(loc)
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
update_icon()
return
- if(!(occupant))
- to_chat(user, "The cloning pod is empty!")
+ if(!occupant)
return
- if(locked)
- to_chat(user, "The cloning pod is locked!")
- return
+ if(grab_ghost_when == CLONER_MATURE_CLONE)
+ clonemind.transfer_to(occupant)
+ occupant.grab_ghost()
+ to_chat(occupant, "There is a bright flash!
\
+ You feel like a new being.")
+ occupant.flash_eyes(visual = 1)
- if(occupant.client)
- occupant.client.eye = occupant.client.mob
- occupant.client.perspective = MOB_PERSPECTIVE
occupant.forceMove(get_turf(src))
eject_wait = 0 //If it's still set somehow.
domutcheck(occupant) //Waiting until they're out before possible notransform.
+ occupant.shock_stage = 0 //Reset Shock
occupant = null
update_icon()
- return
/obj/machinery/clonepod/proc/malfunction()
if(occupant)
connected_message("Critical Error!")
+ announce_radio_message("Critical error! Please contact a Thinktronic Systems technician, as your warranty may be affected.")
mess = 1
- occupant.ghostize()
- qdel(occupant)
- occupant = null
update_icon()
- return
+ if(occupant.mind != clonemind)
+ clonemind.transfer_to(occupant)
+ occupant.grab_ghost() // We really just want to make you suffer.
+ to_chat(occupant, {"Agony blazes across your
+ consciousness as your body is torn apart.
+ Is this what dying is like? Yes it is."})
+ playsound(loc, 'sound/machines/warning-buzzer.ogg', 50, 0)
+ occupant << sound('sound/hallucinations/veryfar_noise.ogg',0,1,50)
+ spawn(40)
+ qdel(occupant)
/obj/machinery/clonepod/update_icon()
..()
@@ -486,11 +497,9 @@
else if(mess && !panel_open)
icon_state = "pod_g"
-/obj/machinery/clonepod/relaymove(mob/user as mob)
- if(user.stat)
- return
- go_out()
- return
+/obj/machinery/clonepod/relaymove(mob/user)
+ if(user.stat == CONSCIOUS)
+ go_out()
/obj/machinery/clonepod/emp_act(severity)
if(prob(100/(severity*efficiency))) malfunction()
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 6f4a373580c..4afe9ba3cff 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -323,19 +323,7 @@
qdel(C)
menu = 1
else
- var/mob/selected = find_dead_player("[C.ckey]")
- if(!selected)
- return
- selected << 'sound/machines/chime.ogg' //probably not the best sound but I think it's reasonable
-
- var/answer = alert(selected,"Do you want to return to life?","Cloning","Yes","No")
- if(answer != "No" && pod.growclone(C))
- temp = "Initiating cloning cycle..."
- records.Remove(C)
- qdel(C)
- menu = 1
- else
- temp = "Initiating cloning cycle...
Error: Post-initialisation failed. Cloning cycle aborted."
+ temp = "[C.name] => Initialisation failure."
else
temp = "Error: Data corruption."
diff --git a/code/modules/countdown/countdown.dm b/code/modules/countdown/countdown.dm
new file mode 100644
index 00000000000..2ef85d6a9d7
--- /dev/null
+++ b/code/modules/countdown/countdown.dm
@@ -0,0 +1,69 @@
+/obj/effect/countdown
+ name = "countdown"
+ desc = "We're leaving together\n\
+ But still it's farewell\n\
+ And maybe we'll come back\n\
+ To earth, who can tell?"
+
+ var/displayed_text
+ var/atom/attached_to
+ color = "#ff0000"
+ var/text_size = 4
+ var/started = 0
+ invisibility = INVISIBILITY_OBSERVER
+ anchored = 1
+ layer = 5
+
+/obj/effect/countdown/New(atom/A)
+ . = ..()
+ attach(A)
+
+/obj/effect/countdown/proc/attach(atom/A)
+ attached_to = A
+ loc = get_turf(A)
+
+/obj/effect/countdown/proc/start()
+ if(!started)
+ fast_processing += src
+ started = 1
+
+/obj/effect/countdown/proc/stop()
+ if(started)
+ maptext = null
+ fast_processing -= src
+ started = 0
+
+/obj/effect/countdown/proc/get_value()
+ // Get the value from our atom
+ return
+
+/obj/effect/countdown/process()
+ if(!attached_to || qdeleted(attached_to))
+ qdel(src)
+ forceMove(get_turf(attached_to))
+ var/new_val = get_value()
+ if(new_val == displayed_text)
+ return
+ displayed_text = new_val
+
+ if(displayed_text)
+ maptext = "[displayed_text]"
+ else
+ maptext = null
+
+/obj/effect/countdown/Destroy()
+ attached_to = null
+ fast_processing -= src
+ return ..()
+
+/obj/effect/countdown/clonepod
+ name = "cloning pod countdown"
+ text_size = 1
+
+/obj/effect/countdown/clonepod/get_value()
+ var/obj/machinery/clonepod/C = attached_to
+ if(!istype(C))
+ return
+ else if(C.occupant)
+ var/completion = round(C.get_completion())
+ return completion
diff --git a/paradise.dme b/paradise.dme
index 9fb76055de9..17f48fd9dba 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1225,6 +1225,7 @@
#include "code\modules\computer3\computers\robot.dm"
#include "code\modules\computer3\computers\security.dm"
#include "code\modules\computer3\computers\welcome.dm"
+#include "code\modules\countdown\countdown.dm"
#include "code\modules\crafting\craft.dm"
#include "code\modules\crafting\guncrafting.dm"
#include "code\modules\crafting\recipes.dm"