Files
CHOMPStation2/code/modules/resleeving/machines.dm
Arokha Sieyes 7c3b3c4311 Adds the SleeveMate 3200
**This commit prevents dead people from being backup-implanted!**
But it's fine because you just use this handheld thing to back them up instead and don't waste an implant, and medical starts with 4 so don't freak out. See below.

Adds the SleeveMate 3200 hand-scanner device. This device allows you to scan people to determine several things about them:
- If they have a mind in them
- If they have a client attached
- If their mind matches their body
- If they are alive/conscious

All of that is represented with in-universe messages of course. The real function of it is that it provides several features:
- One-time mind scan: Performs a one-time mind scan for those that don't like getting mind backup implants. This will store that one scan in the database, but you'll forget everything since then if resleeved. This is also useful for resleeving someone who died without an implant, but is not DNR/DNC.
- One-time body scan: Adds someone to the body scan database, or, updates their body scan if they obtained a new body. Useful if someone has used the body designer and switched bodies, as you can update their body scan. You should probably check medical records, and LOOC around before using this to resleeve someone that didn't have a body scan originally, because they may have picked that to avoid resleeving.
- Store Whole Mind: Takes the entire mind from someone, storing it into the SleeveMate 3200, rendering the patient mindless. From there, it can be backed up as many times as needed, deleted, or stored into someone with a Soulcatcher NIFSoft and run live in their VR (so now you don't have to digest/kill people for that).

Four SM3200's start in medical (1 in minimed downstairs, 3 upstairs), R&D can fab more, and they occasionally show up in trash piles for those wanting to be sneaky with a Soulcatcher, but who don't like digesting people.
2017-06-11 13:55:04 -04:00

597 lines
18 KiB
Plaintext

////////////////////////////////
//// Machines required for body printing
//// and decanting into bodies
////////////////////////////////
/////// Grower Pod ///////
/obj/machinery/clonepod/transhuman
name = "grower pod"
circuit = /obj/item/weapon/circuitboard/transhuman_clonepod
/obj/machinery/clonepod/transhuman/growclone(var/datum/transhuman/body_record/current_project)
//Manage machine-specific stuff.
if(mess || attempting)
return 0
attempting = 1 //One at a time!!
locked = 1
eject_wait = 1
spawn(30)
eject_wait = 0
//Get the DNA and generate a new mob
var/datum/dna2/record/R = current_project.mydna
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src, R.dna.species)
if(current_project.locked)
H.resleeve_lock = current_project.ckey
//Fix the external organs
for(var/part in current_project.limb_data)
var/status = current_project.limb_data[part]
if(status == null) continue //Species doesn't have limb? Child of amputated limb?
var/obj/item/organ/external/O = H.organs_by_name[part]
if(!O) continue //Not an organ. Perhaps another amputation removed it already.
if(status == 1) //Normal limbs
continue
else if(status == 0) //Missing limbs
O.remove_rejuv()
else if(status) //Anything else is a manufacturer
O.remove_rejuv() //Don't robotize them, leave them removed so robotics can attach a part.
//Look, this machine can do this because [reasons] okay?!
for(var/part in current_project.organ_data)
var/status = current_project.organ_data[part]
if(status == null) continue //Species doesn't have organ? Child of missing part?
var/obj/item/organ/I = H.internal_organs_by_name[part]
if(!I) continue//Not an organ. Perhaps external conversion changed it already?
if(status == 0) //Normal organ
continue
else if(status == 1) //Assisted organ
I.mechassist()
else if(status == 2) //Mechanical organ
I.robotize()
else if(status == 3) //Digital organ
I.digitize()
occupant = H
//Set the name or generate one
if(!R.dna.real_name)
R.dna.real_name = "clone ([rand(0,999)])"
H.real_name = R.dna.real_name
//Apply DNA
H.dna = R.dna.Clone()
H.original_player = current_project.ckey
//Apply damage
H.adjustCloneLoss(150)
H.Paralyse(4)
H.updatehealth()
//Grower specific mutations
if(heal_level < 60)
randmutb(H)
H.dna.UpdateSE()
H.dna.UpdateUI()
//Update appearance, remake icons
H.UpdateAppearance()
H.sync_organ_dna()
H.regenerate_icons()
//Basically all the VORE stuff
H.ooc_notes = current_project.body_oocnotes
H.flavor_texts = current_project.mydna.flavor.Copy()
H.resize(current_project.sizemult, FALSE)
H.weight = current_project.weight
if(current_project.speciesname)
H.custom_species = current_project.speciesname
//Suiciding var
H.suiciding = 0
//Making double-sure this is not set
H.mind = null
//Machine specific stuff at the end
update_icon()
attempting = 0
return 1
/obj/machinery/clonepod/transhuman/process()
if(stat & NOPOWER)
if(occupant)
locked = 0
go_out()
return
if((occupant) && (occupant.loc == src))
if(occupant.stat == DEAD)
locked = 0
go_out()
connected_message("Clone Rejected: Deceased.")
return
else if(occupant.health < heal_level && occupant.getCloneLoss() > 0)
//Slowly get that clone healed and finished.
occupant.adjustCloneLoss(-2 * heal_rate)
//Premature clones may have brain damage.
occupant.adjustBrainLoss(-(ceil(0.5*heal_rate)))
//So clones don't die of oxyloss in a running pod.
if(occupant.reagents.get_reagent_amount("inaprovaline") < 30)
occupant.reagents.add_reagent("inaprovaline", 60)
//Also heal some oxyloss ourselves because inaprovaline is so bad at preventing it!!
occupant.adjustOxyLoss(-4)
use_power(7500) //This might need tweaking.
return
else if(((occupant.health >= heal_level) || (occupant.health == occupant.maxHealth)) && (!eject_wait))
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
audible_message("\The [src] signals that the growing process is complete.")
connected_message("Growing Process Complete.")
locked = 0
go_out()
return
else if((!occupant) || (occupant.loc != src))
occupant = null
if(locked)
locked = 0
return
return
//Synthetic version
/obj/machinery/transhuman/synthprinter
name = "SynthFab 3000"
desc = "A rapid fabricator for synthetic bodies."
icon = 'icons/obj/machines/synthpod.dmi'
icon_state = "pod_0"
circuit = /obj/item/weapon/circuitboard/transhuman_synthprinter
density = 1
anchored = 1
var/list/stored_material = list(DEFAULT_WALL_MATERIAL = 30000, "glass" = 30000)
var/connected //What console it's done up with
var/busy = 0 //Busy cloning
var/body_cost = 15000 //Cost of a cloned body (metal and glass ea.)
var/max_res_amount = 30000 //Max the thing can hold
var/datum/transhuman/body_record/current_project
var/broken = 0
var/burn_value = 45
var/brute_value = 60
/obj/machinery/transhuman/synthprinter/New()
..()
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
component_parts += new /obj/item/stack/cable_coil(src, 2)
RefreshParts()
update_icon()
/obj/machinery/transhuman/synthprinter/RefreshParts()
//Scanning modules reduce burn rating by 15 each
var/burn_rating = initial(burn_value)
for(var/obj/item/weapon/stock_parts/scanning_module/SM in component_parts)
burn_rating = burn_rating - (SM.rating*15)
burn_value = burn_rating
//Manipulators reduce brute by 10 each
var/brute_rating = initial(burn_value)
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
brute_rating = brute_rating - (M.rating*10)
brute_value = brute_rating
//Matter bins multiply the storage amount by their rating.
var/store_rating = initial(max_res_amount)
for(var/obj/item/weapon/stock_parts/matter_bin/MB in component_parts)
store_rating = store_rating * MB.rating
max_res_amount = store_rating
/obj/machinery/transhuman/synthprinter/process()
if(stat & NOPOWER)
if(busy)
busy = 0
current_project = null
update_icon()
return
if(busy > 0 && busy <= 95)
busy += 5
if(busy >= 100)
make_body()
return
/obj/machinery/transhuman/synthprinter/proc/print(var/datum/transhuman/body_record/BR)
if(!istype(BR) || busy)
return 0
if(stored_material[DEFAULT_WALL_MATERIAL] < body_cost || stored_material["glass"] < body_cost)
return 0
current_project = BR
busy = 5
update_icon()
return 1
/obj/machinery/transhuman/synthprinter/proc/make_body()
//Manage machine-specific stuff
if(!current_project)
busy = 0
update_icon()
return
//Get the DNA and generate a new mob
var/datum/dna2/record/R = current_project.mydna
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src, R.dna.species)
if(current_project.locked)
H.resleeve_lock = current_project.ckey
//Fix the external organs
for(var/part in current_project.limb_data)
var/status = current_project.limb_data[part]
if(status == null) continue //Species doesn't have limb? Child of amputated limb?
var/obj/item/organ/external/O = H.organs_by_name[part]
if(!O) continue //Not an organ. Perhaps another amputation removed it already.
if(status == 1) //Normal limbs
continue
else if(status == 0) //Missing limbs
O.remove_rejuv()
else if(status) //Anything else is a manufacturer
O.robotize(status)
//Then the internal organs
for(var/part in current_project.organ_data)
var/status = current_project.organ_data[part]
if(status == null) continue //Species doesn't have organ? Child of missing part?
var/obj/item/organ/I = H.internal_organs_by_name[part]
if(!I) continue//Not an organ. Perhaps external conversion changed it already?
if(status == 0) //Normal organ
continue
else if(status == 1) //Assisted organ
I.mechassist()
else if(status == 2) //Mechanical organ
I.robotize()
else if(status == 3) //Digital organ
I.digitize()
//Set the name or generate one
if(!R.dna.real_name)
R.dna.real_name = "synth ([rand(0,999)])"
H.real_name = R.dna.real_name
//Apply DNA
H.dna = R.dna.Clone()
H.original_player = current_project.ckey
//Apply damage
H.adjustBruteLoss(brute_value)
H.adjustFireLoss(burn_value)
H.updatehealth()
//Update appearance, remake icons
H.UpdateAppearance()
H.sync_organ_dna()
H.regenerate_icons()
//Basically all the VORE stuff
H.ooc_notes = current_project.body_oocnotes
H.flavor_texts = current_project.mydna.flavor.Copy()
H.resize(current_project.sizemult)
H.weight = current_project.weight
if(current_project.speciesname)
H.custom_species = current_project.speciesname
//Suiciding var
H.suiciding = 0
//Making double-sure this is not set
H.mind = null
//Plonk them here.
H.regenerate_icons()
H.loc = get_turf(src)
//Machine specific stuff at the end
stored_material[DEFAULT_WALL_MATERIAL] -= body_cost
stored_material["glass"] -= body_cost
busy = 0
update_icon()
return 1
/obj/machinery/transhuman/synthprinter/attack_hand(mob/user as mob)
if((busy == 0) || (stat & NOPOWER))
return
user << "Current print cycle is [busy]% complete."
return
/obj/machinery/transhuman/synthprinter/attackby(obj/item/W as obj, mob/user as mob)
src.add_fingerprint(user)
if(busy)
user << "<span class='notice'>\The [src] is busy. Please wait for completion of previous operation.</span>"
return
if(default_deconstruction_screwdriver(user, W))
return
if(default_deconstruction_crowbar(user, W))
return
if(default_part_replacement(user, W))
return
if(panel_open)
user << "<span class='notice'>You can't load \the [src] while it's opened.</span>"
return
if(!istype(W, /obj/item/stack/material))
user << "<span class='notice'>You cannot insert this item into \the [src]!</span>"
return
var/obj/item/stack/material/S = W
if(!(S.material.name in stored_material))
user << "<span class='warning'>\the [src] doesn't accept [S.material]!</span>"
return
var/amnt = S.perunit
if(stored_material[S.material.name] + amnt <= max_res_amount)
if(S && S.amount >= 1)
var/count = 0
while(stored_material[S.material.name] + amnt <= max_res_amount && S.amount >= 1)
stored_material[S.material.name] += amnt
S.use(1)
count++
user << "You insert [count] [S.name] into \the [src]."
else
user << "\the [src] cannot hold more [S.name]."
updateUsrDialog()
return
/obj/machinery/transhuman/synthprinter/update_icon()
..()
icon_state = "pod_0"
if(busy && !(stat & NOPOWER))
icon_state = "pod_1"
else if(broken)
icon_state = "pod_g"
/////// Resleever Pod ///////
/obj/machinery/transhuman/resleever
name = "resleeving pod"
desc = "Used to combine mind and body into one unit."
icon = 'icons/obj/machines/implantchair.dmi'
icon_state = "implantchair"
circuit = /obj/item/weapon/circuitboard/transhuman_resleever
density = 1
opacity = 0
anchored = 1
var/blur_amount
var/confuse_amount
var/mob/living/carbon/human/occupant = null
var/connected = null
var/sleevecards = 2
/obj/machinery/transhuman/resleever/New()
..()
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
component_parts += new /obj/item/stack/cable_coil(src, 2)
RefreshParts()
update_icon()
/obj/machinery/transhuman/resleever/RefreshParts()
var/scan_rating = 0
for(var/obj/item/weapon/stock_parts/scanning_module/SM in component_parts)
scan_rating += SM.rating
confuse_amount = (48 - scan_rating * 8)
var/manip_rating = 0
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
manip_rating += M.rating
blur_amount = (48 - manip_rating * 8)
/obj/machinery/transhuman/resleever/attack_hand(mob/user as mob)
user.set_machine(src)
var/health_text = ""
var/mind_text = ""
if(src.occupant)
if(src.occupant.stat >= DEAD)
health_text = "<FONT color=red>DEAD</FONT>"
else if(src.occupant.health < 0)
health_text = "<FONT color=red>[round(src.occupant.health,0.1)]</FONT>"
else
health_text = "[round(src.occupant.health,0.1)]"
if(src.occupant.mind)
mind_text = "Mind present: [occupant.mind.name]"
else
mind_text = "Mind absent."
var/dat ="<B>Resleever Status</B><BR>"
dat +="<B>Current occupant:</B> [src.occupant ? "<BR>Name: [src.occupant]<BR>Health: [health_text]<BR>" : "<FONT color=red>None</FONT>"]<BR>"
dat +="<B>Mind status:</B> [mind_text]<BR>"
user.set_machine(src)
user << browse(dat, "window=resleever")
onclose(user, "resleever")
/obj/machinery/transhuman/resleever/attackby(obj/item/W as obj, mob/user as mob)
src.add_fingerprint(user)
if(default_deconstruction_screwdriver(user, W))
return
if(default_deconstruction_crowbar(user, W))
return
if(default_part_replacement(user, W))
return
if(istype(W, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = W
if(!ismob(G.affecting))
return
for(var/mob/living/carbon/slime/M in range(1, G.affecting))
if(M.Victim == G.affecting)
usr << "[G.affecting:name] will not fit into the [src.name] because they have a slime latched onto their head."
return
var/mob/M = G.affecting
if(put_mob(M))
qdel(G)
src.updateUsrDialog()
return //Don't call up else we'll get attack messsages
if(istype(W, /obj/item/device/sleevecard))
var/obj/item/device/sleevecard/C = W
user.unEquip(C)
C.removePersonality()
qdel(C)
sleevecards++
to_chat(user,"<span class='notice'>You store \the [C] in \the [src].</span>")
return
return ..()
/obj/machinery/transhuman/resleever/proc/putmind(var/datum/transhuman/mind_record/MR, mode = 1, var/mob/living/carbon/human/override = null)
if((!occupant || !istype(occupant) || occupant.stat >= DEAD) && mode == 1)
return 0
if(mode == 2 && sleevecards) //Card sleeving
var/obj/item/device/sleevecard/card = new /obj/item/device/sleevecard(get_turf(src))
card.sleeveInto(MR)
sleevecards--
return 1
//If we're sleeving a subtarget, briefly swap them to not need to duplicate tons of code.
var/mob/living/carbon/human/original_occupant
if(override)
original_occupant = occupant
occupant = override
//In case they already had a mind!
if(occupant && occupant.mind)
occupant << "<span class='warning'>You feel your mind being overwritten...</span>"
log_and_message_admins("was resleeve-wiped from their body.",occupant.mind)
occupant.ghostize()
//Attach as much stuff as possible to the mob.
for(var/datum/language/L in MR.languages)
occupant.add_language(L.name)
MR.mind_ref.active = 1 //Well, it's about to be.
MR.mind_ref.transfer_to(occupant) //Does mind+ckey+client.
occupant.identifying_gender = MR.id_gender
occupant.ooc_notes = MR.mind_oocnotes
occupant.apply_vore_prefs() //Cheap hack for now to give them SOME bellies.
if(MR.one_time)
var/how_long = round((world.time - MR.last_update)/10/60)
to_chat(occupant,"<span class='danger'>Your mind backup was a 'one-time' backup. \
You will not be able to remember anything since the backup, [how_long] minutes ago.</span>")
//Re-supply a NIF if one was backed up with them.
if(MR.nif_path)
var/obj/item/device/nif/nif = new MR.nif_path(occupant,MR.nif_durability)
for(var/path in MR.nif_software)
new path(nif)
// If it was a custom sleeve (not owned by anyone), update namification sequences
if(!occupant.original_player)
occupant.real_name = occupant.mind.name
occupant.name = occupant.real_name
occupant.dna.real_name = occupant.real_name
//Give them a backup implant
var/obj/item/weapon/implant/backup/new_imp = new()
if(new_imp.implanted(occupant))
new_imp.loc = occupant
new_imp.imp_in = occupant
new_imp.implanted = 1
//Put it in the head! Makes sense.
var/obj/item/organ/external/affected = occupant.get_organ(BP_HEAD)
affected.implants += new_imp
new_imp.part = affected
//Inform them and make them a little dizzy.
if(confuse_amount + blur_amount <= 16)
occupant << "<span class='notice'>You feel a small pain in your head as you're given a new backup implant. Your new body feels comfortable already, however.</span>"
else
occupant << "<span class='warning'>You feel a small pain in your head as you're given a new backup implant. Oh, and a new body. It's disorienting, to say the least.</span>"
occupant.confused = max(occupant.confused, confuse_amount)
occupant.eye_blurry = max(occupant.eye_blurry, blur_amount)
if(occupant.mind && occupant.original_player && ckey(occupant.mind.key) != occupant.original_player)
log_and_message_admins("is now a cross-sleeved character. Body originally belonged to [occupant.real_name]. Mind is now [occupant.mind.name].",occupant)
if(original_occupant)
occupant = original_occupant
return 1
/obj/machinery/transhuman/resleever/proc/go_out(var/mob/M)
if(!( src.occupant ))
return
if (src.occupant.client)
src.occupant.client.eye = src.occupant.client.mob
src.occupant.client.perspective = MOB_PERSPECTIVE
src.occupant.loc = src.loc
src.occupant = null
icon_state = "implantchair"
return
/obj/machinery/transhuman/resleever/proc/put_mob(mob/living/carbon/human/M as mob)
if(!ishuman(M))
usr << "<span class='warning'>\The [src] cannot hold this!</span>"
return
if(src.occupant)
usr << "<span class='warning'>\The [src] is already occupied!</span>"
return
if(M.client)
M.client.perspective = EYE_PERSPECTIVE
M.client.eye = src
M.stop_pulling()
M.loc = src
src.occupant = M
src.add_fingerprint(usr)
icon_state = "implantchair_on"
return 1
/obj/machinery/transhuman/resleever/verb/get_out()
set name = "EJECT Occupant"
set category = "Object"
set src in oview(1)
if(usr.stat != 0)
return
src.go_out(usr)
add_fingerprint(usr)
return
/obj/machinery/transhuman/resleever/verb/move_inside()
set name = "Move INSIDE"
set category = "Object"
set src in oview(1)
if(usr.stat != 0 || stat & (NOPOWER|BROKEN))
return
put_mob(usr)
return