Files
2020-02-19 19:48:29 -08:00

887 lines
28 KiB
Plaintext

//Cloning revival method.
//The pod handles the actual cloning while the computer manages the clone profiles
/obj/machinery/computer/cloning
name = "Cloning console"
desc = "Use this console to operate a cloning scanner and pod. There is a slot to insert modules - they can be removed with a screwdriver."
icon = 'icons/obj/computer.dmi'
icon_state = "dna"
req_access = list(access_heads) //Only used for record deletion right now.
object_flags = CAN_REPROGRAM_ACCESS
var/obj/machinery/clone_scanner/scanner = null //Linked scanner. For scanning.
var/obj/machinery/clonepod/pod1 = null //Linked cloning pod.
var/temp = "Initializing System..."
var/menu = 1 //Which menu screen to display
var/list/records = list()
var/datum/data/record/active_record = null
var/obj/item/disk/data/floppy/diskette = null //Mostly so the geneticist can steal somebody's identity while pretending to give them a handy backup profile.
var/held_credit = 5000 // one free clone
var/allow_dead_scanning = 0 //Can the dead be scanned in the cloner?
var/portable = 0 //override new() proc and proximity check, for port-a-clones
var/allow_mind_erasure = 0 // Can you erase minds?
var/mindwipe = 0 //Is mind wiping active?
lr = 1
lg = 0.6
lb = 1
old
icon_state = "old2"
desc = "With the price of cloning pods nowadays it's not unexpected to skimp on the controller."
power_change()
if(status & BROKEN)
icon_state = "old2b"
else
if( powered() )
icon_state = initial(icon_state)
status &= ~NOPOWER
else
SPAWN_DBG(rand(0, 15))
src.icon_state = "old20"
status |= NOPOWER
/obj/item/cloner_upgrade
name = "\improper NecroScan II cloner upgrade module"
desc = "A circuit module designed to improve cloning machine scanning capabilities to the point where even the deceased may be scanned."
icon = 'icons/obj/module.dmi'
icon_state = "cloner_upgrade"
w_class = 1
throwforce = 1
/obj/item/grinder_upgrade
name = "\improper ProBlender X enzymatic reclaimer upgrade module"
desc = "A circuit module designed to improve enzymatic reclaimer capabilities so that the machine will be able to reclaim more matter, faster."
icon = 'icons/obj/module.dmi'
icon_state = "grinder_upgrade"
w_class = 1
throwforce = 1
/obj/machinery/computer/cloning/New()
..()
SPAWN_DBG(5 DECI SECONDS)
if(portable) return
src.scanner = locate(/obj/machinery/clone_scanner, orange(2,src))
src.pod1 = locate(/obj/machinery/clonepod, orange(4,src))
src.temp = ""
if (isnull(src.scanner))
src.temp += " <font color=red>SCNR-ERROR</font>"
if (isnull(src.pod1))
src.temp += " <font color=red>POD1-ERROR</font>"
else
src.pod1.connected = src
if (src.temp == "")
src.temp = "System ready."
return
return
/obj/machinery/computer/cloning/attackby(obj/item/W as obj, mob/user as mob)
if (wagesystem.clones_for_cash && istype(W, /obj/item/spacecash))
var/obj/item/spacecash/cash = W
src.held_credit += cash.amount
cash.amount = 0
user.show_text("<span style=\"color:blue\">You add [cash] to the credit in [src].</span>")
user.u_equip(W)
pool(W)
else if (istype(W, /obj/item/disk/data/floppy))
if (!src.diskette)
user.drop_item()
W.set_loc(src)
src.diskette = W
boutput(user, "You insert [W].")
src.updateUsrDialog()
return
else if (isscrewingtool(W) && ((src.status & BROKEN) || !src.pod1 || !src.scanner))
playsound(src.loc, "sound/items/Screwdriver.ogg", 50, 1)
if(do_after(user, 20))
boutput(user, "<span style=\"color:blue\">The broken glass falls out.</span>")
var/obj/computerframe/A = new /obj/computerframe( src.loc )
if(src.material) A.setMaterial(src.material)
var/obj/item/raw_material/shard/glass/G = unpool(/obj/item/raw_material/shard/glass)
G.set_loc(src.loc)
var/obj/item/circuitboard/cloning/M = new /obj/item/circuitboard/cloning( A )
for (var/obj/C in src)
C.set_loc(src.loc)
M.records = src.records
if (src.allow_dead_scanning)
new /obj/item/cloner_upgrade (src.loc)
src.allow_dead_scanning = 0
if(src.allow_mind_erasure)
new /obj/item/cloneModule/minderaser(src.loc)
src.allow_mind_erasure = 0
if(src.pod1 && src.pod1.BE)
new /obj/item/cloneModule/genepowermodule(src.loc)
src.pod1.BE = null
A.circuit = M
A.state = 3
A.icon_state = "3"
A.anchored = 1
qdel(src)
else if (istype(W, /obj/item/cloner_upgrade))
if (allow_dead_scanning || allow_mind_erasure)
boutput(user, "<span style=\"color:red\">There is already an upgrade installed.</span>")
return
user.visible_message("[user] installs [W] into [src].", "You install [W] into [src].")
src.allow_dead_scanning = 1
user.drop_item()
logTheThing("combat", src, user, "[user] has added clone module ([W]) to ([src]) at [log_loc(user)].")
qdel(W)
else if (istype(W, /obj/item/cloneModule/minderaser))
if(allow_mind_erasure || allow_dead_scanning)
boutput(user, "<span style=\"color:red\">There is already an upgrade installed.</span>")
return
user.visible_message("[user] installs [W] into [src].", "You install [W] into [src].")
src.allow_mind_erasure = 1
user.drop_item()
logTheThing("combat", src, user, "[user] has added clone module ([W]) to ([src]) at [log_loc(user)].")
qdel(W)
else if (istype(W, /obj/item/cloneModule/genepowermodule))
var/obj/item/cloneModule/genepowermodule/module = W
if(module.BE == null)
boutput(user, "<span style=\"color:red\">You need to put an injector into the module before it will work!</span>")
return
if(pod1.BE)
boutput(user,"<span style=\"color:red\">There is already a gene module in this upgrade spot! You can remove it by blowing up the genetics computer and building a new one. Or you could just use a screwdriver, I guess.</span>")
return
src.pod1.BE = module.BE
user.drop_item()
user.visible_message("[user] installs [module] into [src].", "You install [module] into [src].")
logTheThing("combat", src, user, "[user] has added clone module ([W] - [module.BE]) to ([src]) at [log_loc(user)].")
qdel(module)
else
src.attack_hand(user)
return
/obj/machinery/computer/cloning/attack_ai(mob/user as mob)
return attack_hand(user)
/obj/machinery/computer/cloning/attack_hand(mob/user as mob)
user.machine = src
add_fingerprint(user)
if(status & (BROKEN|NOPOWER))
return
var/dat = {"<h3>Cloning System Control</h3>
<font size=-1><a href='byond://?src=\ref[src];refresh=1'>Refresh</a></font>
<br><tt>[temp]</tt><br><hr>"}
switch(src.menu)
if(1) //Scan someone
dat += "<h4>Scanner Functions</h4>"
if (isnull(src.scanner))
dat += "No scanner connected!"
else
if (src.scanner.occupant)
dat += "<a href='byond://?src=\ref[src];scan=1'>Scan - [src.scanner.occupant]</a>"
else
dat += "Scanner unoccupied"
dat += "<br>Lock status: <a href='byond://?src=\ref[src];lock=1'>[src.scanner.locked ? "Locked" : "Unlocked"]</a><BR>"
dat += {"<h4>Cloning Pod Functions</h4>
<a href='byond://?src=\ref[src];menu=5'>Genetic Analysis Mode</a><br>
Status: <B>[pod1 && pod1.gen_analysis ? "Enabled" : "Disabled"]</B>
<h4>Database Functions</h4>
<a href='byond://?src=\ref[src];menu=2'>View Records</a><br>"}
if (src.diskette)
dat += {"<a href='byond://?src=\ref[src];disk=load'>Load from disk</a><br>
<a href='byond://?src=\ref[src];disk=eject'>Eject disk</a><br>"}
if (pod1 && pod1.BE)
dat += "<br><b>Gene power module active</b><br>"
if(src.allow_mind_erasure)
dat += "<a href='byond://?src=\ref[src];menu=6'>Criminal rehabilitation controls</a>"
if(2) //Viewing records
dat += {"<h4>Current records</h4>
<a href='byond://?src=\ref[src];menu=1'>Back</a><br><br>"}
for(var/datum/data/record/R in src.records)
dat += "<a href='byond://?src=\ref[src];view_rec=\ref[R]'>[R.fields["id"]]-[R.fields["name"]]</a><br>"
if(3) //Viewing details of record
dat += {"<h4>Selected Record</h4>
<a href='byond://?src=\ref[src];menu=2'>Back</a><br>"}
if (!src.active_record)
dat += "<font color=red>ERROR: Record not found.</font>"
else
dat += {"<br><font size=1><a href='byond://?src=\ref[src];del_rec=1'>Delete Record</a></font><br>
<b>Name:</b> [src.active_record.fields["name"]]<br>"}
var/obj/item/implant/health/H = locate(src.active_record.fields["imp"])
if ((H) && (istype(H)))
dat += "<b>Health:</b> [H.sensehealth()]<br>"
else
dat += "<font color=red>Unable to locate implant.</font><br>"
if (!isnull(src.diskette))
dat += {"<a href='byond://?src=\ref[src];save_disk=holder'>Save to disk</a><br>"}
else
dat += "<br>" //Keeping a line empty for appearances I guess.
if (wagesystem.clones_for_cash)
dat += "Current machine credit: [src.held_credit]<br>"
dat += {"<a href='byond://?src=\ref[src];clone=\ref[src.active_record]'>Clone</a><br>"}
if(4) //Deleting a record
if (!src.active_record)
src.menu = 2
dat = {"[src.temp]<br>
<h4>Confirm Record Deletion</h4>
<b><a href='byond://?src=\ref[src];del_rec=1'>Yes</a></b><br>
<b><a href='byond://?src=\ref[src];menu=3'>No</a></b>"}
if(5) //Advanced genetics analysis
dat += {"<h4>Advanced Genetic Analysis</h4>
<a href='byond://?src=\ref[src];menu=1'>Back</a><br>
<B>Notice:</B> Enabling this feature will prompt the attached clone pod to analyze the genetic makeup of the subject during cloning.
Data will then be sent to any nearby GeneTek scanners and be used to improve their efficiency. The cloning process will be slightly slower as a result.<BR><BR>"}
if(!pod1.operating)
if(pod1.gen_analysis)
dat += {"Enabled<BR>
<a href='byond://?src=\ref[src];set_analysis=0'>Disable</A><BR>"}
else
dat += {"<a href='byond://?src=\ref[src];set_analysis=1'>Enable</A><BR>
Disabled<BR>"}
else
dat += {"Cannot toggle while cloning pod is active. <BR>
AGA: <B>[pod1.gen_analysis ? "Enabled" : "Disabled"]</B>"}
if(6) // Mind erasure controls
dat += {"<h4>Criminal rehabilitation controls</h4>
<a href='byond://?src=\ref[src];menu=1'>Back</a><br>
<B>Notice:</B> Enabling this feature will enable an experimental criminal rehabilitation routine.<BR><B>Human use is specifically forbidden by the space geneva convention.<B><BR>"}
if(!pod1.operating)
if(pod1.mindwipe)
dat += {"Enabled<BR>
<a href='byond://?src=\ref[src];set_mindwipe=0'>Disable</A><BR>"}
else
dat += {"<a href='byond://?src=\ref[src];set_mindwipe=1'>Enable</A><BR>
Disabled<BR>"}
else
dat += {"Cannot toggle while cloning pod is active. <BR>"}
user.Browse(dat, "window=cloning")
onclose(user, "cloning")
return
/obj/machinery/computer/cloning/Topic(href, href_list)
if(..())
return
if ((href_list["scan"]) && (!isnull(src.scanner)))
src.scan_mob(src.scanner.occupant)
//No locking an open scanner.
else if ((href_list["lock"]) && (!isnull(src.scanner)))
if ((!src.scanner.locked) && (src.scanner.occupant))
src.scanner.locked = 1
else
src.scanner.locked = 0
else if (href_list["view_rec"])
src.active_record = locate(href_list["view_rec"]) in records
if ((isnull(src.active_record.fields["ckey"])) || (src.active_record.fields["ckey"] == ""))
qdel(src.active_record)
src.temp = "ERROR: Record Corrupt"
else
src.menu = 3
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
return
if (src.menu == 3) //If we are viewing a record, confirm deletion
src.temp = "Delete record?"
src.menu = 4
else if (src.menu == 4)
logTheThing("combat", usr, null, "deletes the cloning record [src.active_record.fields["name"]] for player [src.active_record.fields["ckey"]] at [log_loc(src)].")
src.records.Remove(src.active_record)
qdel(src.active_record)
src.temp = "Record deleted."
src.menu = 2
/*
var/obj/item/card/id/C = usr.equipped()
if (istype(C))
if(src.check_access(C))
src.records.Remove(src.active_record)
qdel(src.active_record)
src.temp = "Record deleted."
src.menu = 2
else
src.temp = "Access Denied."
*/
else if (href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
if (src.diskette.data_type == "cloning_record")
var/datum/data/record/R = new /datum/data/record( )
R.fields = src.diskette.data
src.records += R
src.temp = "Load successful, data transferred."
src.diskette.data_type = "corrupt"
src.diskette.data = ""
src.updateUsrDialog()
return
else
src.temp = "Load error."
src.updateUsrDialog()
return
if("eject")
if (!isnull(src.diskette))
src.diskette.set_loc(src.loc)
usr.put_in_hand_or_eject(src.diskette) // try to eject it into the users hand, if we can
src.diskette = null
else if (href_list["save_disk"]) //Save to disk!
if ((isnull(src.diskette)) || (src.diskette.read_only) || (isnull(src.active_record)))
src.temp = "Save error."
src.updateUsrDialog()
return
else if (src.diskette.data_type == "corrupt")
src.temp = "Save error. Disk corruption."
src.updateUsrDialog()
return
src.diskette.data = src.active_record.fields
src.diskette.ue = 1
src.diskette.data_type = "cloning_record"
src.diskette.owner = src.active_record.fields["name"]
src.diskette.name = "data disk - '[src.diskette.owner]'"
src.temp = "Save successful."
else if (href_list["refresh"])
src.updateUsrDialog()
else if (href_list["clone"])
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
// yes, i'm using goto here. this would be less of a cluster if this was a function,
// but i can't be bothered rn. someone else can fix it.
if (!src.pod1)
src.temp = "No cloning pod connected."
goto BailOutOfCloningAttempt
if (src.pod1.occupant)
src.temp = "Cloning pod in use."
goto BailOutOfCloningAttempt
if (src.pod1.mess)
src.temp = "Abnormal reading from cloning pod."
goto BailOutOfCloningAttempt
//Look for that player! They better be dead!
var/datum/data/record/C = locate(href_list["clone"])
if (!istype(C))
src.temp = "Invalid or corrupt record."
goto BailOutOfCloningAttempt
// Get our dead person
var/mob/selected = find_dead_player("[C.fields["ckey"]]")
if (!selected)
src.temp = "Can't clone: Unable to locate mind."
goto BailOutOfCloningAttempt
if (selected.mind && selected.mind.dnr)
// leave the goddamn dnr ghosts alone
src.temp = "Cannot clone: Subject has set DNR."
goto BailOutOfCloningAttempt
else
//for deleting the mob in the afterlife bar if cloning person from there.
var/mob/ALB_selection = selected
if (inafterlifebar(ALB_selection))
boutput(selected, "<span style=\"color:blue\">You are being returned to the land of the living!</span>")
selected = ALB_selection.ghostize()
qdel(ALB_selection)
// at this point selected = the dude we wanna revive.
// we should be good to start cloning.
if (wagesystem.clones_for_cash)
var/datum/data/record/Ba = FindBankAccountByName(C.fields["name"])
var/account_credit = 0
if (Ba && Ba.fields["current_money"])
account_credit = Ba.fields["current_money"]
if ((src.held_credit + account_credit) >= wagesystem.clone_cost)
// try cloning
if (src.pod1.growclone(selected, C.fields["name"], C.fields["mind"], C.fields["holder"], C.fields["abilities"] , C.fields["traits"]))
// deduct some dosh
var/from_account = min(wagesystem.clone_cost, account_credit)
if (from_account > 0)
Ba.fields["current_money"] -= from_account
src.held_credit -= (wagesystem.clone_cost - from_account)
src.temp = "Payment of [wagesystem.clone_cost] credits accepted. [from_account > 0 ? "Deducted [from_account] credits from [C.fields["name"]]'s account.' " : ""][from_account < wagesystem.clone_cost ? "Deducted [wagesystem.clone_cost - from_account] credits from machine credit." : ""] Cloning cycle activated."
src.records.Remove(C)
qdel(C)
src.menu = 1
else
src.temp = "Unknown error when trying to start cloning process."
else
src.temp = "Insufficient funds to begin clone cycle."
else if (src.pod1.growclone(selected, C.fields["name"], C.fields["mind"], C.fields["holder"], C.fields["abilities"] , C.fields["traits"]))
src.temp = "Cloning cycle activated."
src.records.Remove(C)
qdel(C)
src.menu = 1
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
else if (href_list["set_analysis"])
pod1.gen_analysis = text2num(href_list["set_analysis"])
else if (href_list["set_mindwipe"])
pod1.mindwipe = text2num(href_list["set_mindwipe"])
// considered harmful
BailOutOfCloningAttempt
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject as mob)
if ((isnull(subject)) || (!ishuman(subject)))
src.temp = "Error: Unable to locate valid genetic data."
return
if(!allow_dead_scanning && subject.decomp_stage)
src.temp = "Error: Failed to read genetic data from subject.<br>Necrosis of tissue has been detected."
return
if (!subject.bioHolder || subject.bioHolder.HasEffect("husk"))
src.temp = "Error: Extreme genetic degredation present."
return
if (istype(subject.mutantrace, /datum/mutantrace/kudzu))
src.temp = "Error: Incompatible cellular structure."
return
if (subject.mob_flags & IS_BONER)
src.temp = "Error: No tissue mass present.<br>Total ossification of subject detected."
return
var/datum/mind/subjMind = subject.mind
if ((!subjMind) || (!subjMind.key))
if ((subject.ghost && subject.ghost.mind && subject.ghost.mind.key))
subjMind = subject.ghost.mind
else if (subject.last_client && find_dead_player("[subject.last_client.ckey]"))
var/mob/living/carbon/human/virtual/V = find_dead_player("[subject.last_client.ckey]")
if ((istype(V) && V.isghost) || inafterlifebar(V))
subjMind = V.mind
else
src.temp = "Error: Mental interface failure."
return
else
src.temp = "Error: Mental interface failure."
return
if (!isnull(find_record(ckey(subjMind.key))))
src.temp = "Subject already in database."
return
var/datum/data/record/R = new /datum/data/record( )
R.fields["ckey"] = ckey(subjMind.key)
R.fields["name"] = subject.real_name
R.fields["id"] = copytext(md5(subject.real_name), 2, 6)
var/datum/bioHolder/H = new/datum/bioHolder(null)
H.CopyOther(subject.bioHolder)
R.fields["holder"] = H
R.fields["abilities"] = null
if (subject.abilityHolder)
var/datum/abilityHolder/A = subject.abilityHolder.deepCopy()
R.fields["abilities"] = A
R.fields["traits"] = list()
if(subject.traitHolder && subject.traitHolder.traits.len)
R.fields["traits"] = subject.traitHolder.traits.Copy()
//Add an implant if needed
var/obj/item/implant/health/imp = locate(/obj/item/implant/health, subject)
if (isnull(imp))
imp = new /obj/item/implant/health(subject)
imp.implanted = 1
imp.owner = subject
subject.implant.Add(imp)
// imp.implanted = subject // this isn't how this works with new implants sheesh
R.fields["imp"] = "\ref[imp]"
//Update it if needed
else
R.fields["imp"] = "\ref[imp]"
if (!isnull(subjMind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = subjMind
src.records += R
src.temp = "Subject successfully scanned."
JOB_XP(usr, "Medical Doctor", 10)
//Find a specific record by key.
/obj/machinery/computer/cloning/proc/find_record(var/find_key)
var/selected_record = null
for(var/datum/data/record/R in src.records)
if (R.fields["ckey"] == find_key)
selected_record = R
break
return selected_record
/obj/machinery/computer/cloning/power_change()
if(status & BROKEN)
icon_state = "commb"
else
if( powered() )
icon_state = initial(icon_state)
status &= ~NOPOWER
else
SPAWN_DBG(rand(0, 15))
src.icon_state = "c_unpowered"
status |= NOPOWER
//New loading/storing records is a todo while I determine how it should work.
/obj/machinery/computer/cloning/proc
load_record()
if (!src.diskette || !src.diskette.root)
return -1
return 0
save_record()
if (!src.diskette || !src.diskette.root)
return -1
return 0
//Find a dead mob with a brain and client.
/proc/find_dead_player(var/find_key, needbrain=0)
if (isnull(find_key))
return
for(var/mob/M in mobs)
//Dead people only thanks!
if (!(isdead(M) || isVRghost(M) || inafterlifebar(M)) || (!M.client))
continue
//They need a brain!
if (needbrain && ishuman(M) && !M:brain)
continue
if (M.ckey == find_key)
return M
return null
#define PROCESS_IDLE 0
#define PROCESS_STRIP 1
#define PROCESS_MINCE 2
/obj/machinery/clone_scanner
name = "cloning machine scanner"
desc = "Some sort of weird machine that you stuff people into to scan their genetic DNA for cloning."
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "scanner_0"
density = 1
mats = 15
var/locked = 0
var/mob/occupant = null
anchored = 1.0
soundproofing = 10
event_handler_flags = USE_FLUID_ENTER | USE_CANPASS
// In case someone wants a perfectly safe device. For some weird reason.
var/can_meat_grind = 1
//Double functionality as a meat grinder
var/list/obj/machinery/clonepod/pods
// How long to run
var/process_timer = 0
var/timer_length = 0
// Automatically strip the target of their equipment
var/auto_strip = 1
// Check if the target is a living human before mincing
var/mince_safety = 1
// How far away to find clone pods
var/pod_range = 4
// What we are working on at the moment
var/active_process = PROCESS_IDLE
// If we should start the mincer after the stripper (lol)
var/automatic_sequence = 0
// Our ID for mapping
var/id = ""
// If upgraded or not
var/upgraded = 0
allow_drop()
return 0
New()
..()
src.create_reagents(100)
relaymove(mob/user as mob, dir)
eject_occupant(user)
MouseDrop_T(mob/living/target, mob/user)
if (!istype(target) || isAI(user))
return
if (get_dist(src,user) > 1)
return
if (target == user)
move_mob_inside(target)
else if (can_operate(user))
user.a_intent = INTENT_GRAB
user.drop_item()
target.attack_hand(user)
SPAWN_DBG(user.combat_click_delay + 2)
if (can_operate(user))
if (istype(user.equipped(), /obj/item/grab))
src.attackby(user.equipped(), user)
return
proc/can_operate(var/mob/M)
if (!isalive(M))
return
if (get_dist(src,M) > 1)
return 0
if (M.getStatusDuration("paralysis") || M.getStatusDuration("stunned") || M.getStatusDuration("weakened"))
return 0
if (src.occupant)
boutput(M, "<span style=\"color:blue\"><B>The scanner is already occupied!</B></span>")
return
.= 1
verb/move_inside()
set src in oview(1)
set category = "Local"
move_mob_inside(usr)
return
proc/move_mob_inside(var/mob/M)
if (!can_operate(M)) return
M.pulling = null
M.set_loc(src)
src.occupant = M
src.icon_state = "scanner_1"
for(var/obj/O in src)
O.loc = src.loc
src.add_fingerprint(usr)
playsound(src.loc, "sound/machines/sleeper_close.ogg", 50, 1)
attack_hand(mob/user as mob)
..()
eject_occupant(user)
MouseDrop(mob/user as mob)
if (can_operate(user))
eject_occupant(user)
else
..()
verb/eject()
set src in oview(1)
set category = "Local"
eject_occupant(usr)
return
verb/eject_occupant(var/mob/user)
if (!isalive(user))
return
src.go_out()
add_fingerprint(user)
attackby(var/obj/item/grab/G as obj, user as mob)
if ((!( istype(G, /obj/item/grab) ) || !( ismob(G.affecting) )))
return
if (src.occupant)
boutput(user, "<span style=\"color:blue\"><B>The scanner is already occupied!</B></span>")
return
var/mob/M = G.affecting
M.set_loc(src)
src.occupant = M
src.icon_state = "scanner_1"
playsound(src.loc, "sound/machines/sleeper_close.ogg", 50, 1)
for(var/obj/O in src)
O.set_loc(src.loc)
src.add_fingerprint(user)
qdel(G)
return
proc/go_out()
if ((!( src.occupant ) || src.locked))
return
for(var/obj/O in src)
O.set_loc(src.loc)
src.occupant.set_loc(src.loc)
src.occupant = null
src.icon_state = "scanner_0"
playsound(src.loc, "sound/machines/sleeper_open.ogg", 50, 1)
return
proc/set_lock(var/lock_status)
if(lock_status && !locked)
locked = 1
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
bo(occupant, "<span style='color:red'>\The [src] locks shut!</span>")
else if(!lock_status && locked)
locked = 0
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
bo(occupant, "<span style='color:blue'>\The [src] unlocks!</span>")
CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if (air_group || (height==0))
return 1
..()
// Meat grinder functionality.
proc/find_pods()
if (!islist(src.pods))
src.pods = list()
if (!isnull(src.id) && genResearch && islist(genResearch.clonepods) && genResearch.clonepods.len)
for (var/obj/machinery/clonepod/pod in genResearch.clonepods)
if (pod.id == src.id && !src.pods.Find(pod))
src.pods += pod
DEBUG_MESSAGE("[src] adds pod [log_loc(pod)] (ID [src.id]) in genResearch.clonepods")
else
for (var/obj/machinery/clonepod/pod in orange(src.pod_range))
if (!src.pods.Find(pod))
src.pods += pod
DEBUG_MESSAGE("[src] adds pod [log_loc(pod)] in orange([src.pod_range])")
process()
switch(active_process)
if(PROCESS_IDLE)
UnsubscribeProcess()
process_timer = 0
return
if(PROCESS_MINCE)
do_mince()
if(PROCESS_STRIP)
do_strip()
proc/report_progress()
switch(active_process)
if(PROCESS_IDLE)
. = "Idle."
if(PROCESS_MINCE)
. = "Reclamation process [round(process_timer/timer_length)*100] % complete..."
if(PROCESS_STRIP)
. = "In progress..."
proc/start_mince()
active_process = PROCESS_MINCE
timer_length = 15 + rand(-5, 5)
process_timer = timer_length
set_lock(1)
bo(occupant, "<span style='color:red;font-weight:bold'>A whirling blade slowly begins descending upon you!</span>")
playsound(get_turf(src), 'sound/machines/mixer.ogg', 50, 1)
SubscribeToProcess()
proc/start_strip()
active_process = PROCESS_STRIP
set_lock(1)
bo(occupant, "<span style='color:red'>Hatches open and tiny, grabby claws emerge!</span>")
SubscribeToProcess()
proc/do_mince()
if (process_timer-- < 1)
active_process = PROCESS_IDLE
src.occupant.death(1)
src.occupant.ghostize()
qdel(src.occupant)
DEBUG_MESSAGE("[src].reagents.total_volume on completion of cycle: [src.reagents.total_volume]")
if (islist(src.pods) && pods.len && src.reagents.total_volume)
for (var/obj/machinery/clonepod/pod in src.pods)
src.reagents.trans_to(pod, (src.reagents.total_volume / max(pods.len, 1))) // give an equal amount of reagents to each pod that happens to be around
DEBUG_MESSAGE("[src].reagents.trans_to([pod] [log_loc(pod)], [src.reagents.total_volume]/[max(pods.len, 1)])")
process_timer = 0
active_process = PROCESS_IDLE
set_lock(0)
automatic_sequence = 0
return
var/mult = src.upgraded ? 2 : 1
src.reagents.add_reagent("blood", 2 * mult)
src.reagents.add_reagent("meat_slurry", 2 * mult)
if (prob(2))
src.reagents.add_reagent("beff", 1 * mult)
// Mess with the occupant
var/damage = round(200 / timer_length) + rand(1, 10)
src.occupant.TakeDamage(zone="All", brute=damage)
bleed(occupant, damage * 2, 0)
if(prob(50))
playsound(get_turf(src), 'sound/machines/mixer.ogg', 50, 1)
if(prob(30))
SPAWN_DBG(3 DECI SECONDS)
playsound(src.loc, pick('sound/impact_sounds/Flesh_Stab_1.ogg', \
'sound/impact_sounds/Slimy_Hit_3.ogg', \
'sound/impact_sounds/Slimy_Hit_4.ogg', \
'sound/impact_sounds/Flesh_Break_1.ogg', \
'sound/impact_sounds/Flesh_Tear_1.ogg', \
'sound/impact_sounds/Generic_Snap_1.ogg', \
'sound/impact_sounds/Generic_Hit_1.ogg'), 100, 5)
proc/do_strip()
//Remove one item each cycle
var/obj/item/to_remove
if(src.occupant)
to_remove = occupant.unequip_random()
if(to_remove)
if(prob(70))
bo(occupant, "<span style='color:red'>\The arms [pick("snatch", "grab", "steal", "remove", "nick", "blag")] your [to_remove.name]!</span>")
playsound(get_turf(src), "sound/misc/rustle[rand(1,5)].ogg", 50, 1)
to_remove.set_loc(src.loc)
else
if(automatic_sequence)
start_mince()
else
set_lock(0)
active_process = PROCESS_IDLE
#undef PROCESS_IDLE
#undef PROCESS_STRIP
#undef PROCESS_MINCE