mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 10:12:45 +00:00
* Allow multiple SStranscore databases * Add key to backup implanter too * Key passing tweak * Fix issue Leshana spotted * Add optimization Leshana spotted * Fixxy more multitranscore bugs
529 lines
18 KiB
Plaintext
529 lines
18 KiB
Plaintext
#define MENU_MAIN 1
|
|
#define MENU_BODY 2
|
|
#define MENU_MIND 3
|
|
|
|
/obj/machinery/computer/transhuman/resleeving
|
|
name = "resleeving control console"
|
|
catalogue_data = list(/datum/category_item/catalogue/information/organization/vey_med,
|
|
/datum/category_item/catalogue/technology/resleeving)
|
|
icon_keyboard = "med_key"
|
|
icon_screen = "dna"
|
|
light_color = "#315ab4"
|
|
circuit = /obj/item/weapon/circuitboard/resleeving_control
|
|
req_access = list(access_heads) //Only used for record deletion right now.
|
|
var/list/pods = null //Linked grower pods.
|
|
var/list/spods = null
|
|
var/list/sleevers = null //Linked resleeving booths.
|
|
var/list/temp = null
|
|
var/menu = MENU_MAIN //Which menu screen to display
|
|
var/datum/transhuman/body_record/active_br = null
|
|
var/datum/transhuman/mind_record/active_mr = null
|
|
var/organic_capable = 1
|
|
var/synthetic_capable = 1
|
|
var/obj/item/weapon/disk/transcore/disk
|
|
var/obj/machinery/clonepod/transhuman/selected_pod
|
|
var/obj/machinery/transhuman/synthprinter/selected_printer
|
|
var/obj/machinery/transhuman/resleever/selected_sleever
|
|
|
|
// Resleeving database this machine interacts with. Blank for default database
|
|
// Needs a matching /datum/transcore_db with key defined in code
|
|
var/db_key
|
|
var/datum/transcore_db/our_db // These persist all round and are never destroyed, just keep a hard ref
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/Initialize()
|
|
. = ..()
|
|
pods = list()
|
|
spods = list()
|
|
sleevers = list()
|
|
our_db = SStranscore.db_by_key(db_key)
|
|
updatemodules()
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/Destroy()
|
|
releasepods()
|
|
return ..()
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/proc/updatemodules()
|
|
releasepods()
|
|
findpods()
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/proc/releasepods()
|
|
for(var/obj/machinery/clonepod/transhuman/P in pods)
|
|
P.connected = null
|
|
P.name = initial(P.name)
|
|
pods.Cut()
|
|
for(var/obj/machinery/transhuman/synthprinter/P in spods)
|
|
P.connected = null
|
|
P.name = initial(P.name)
|
|
spods.Cut()
|
|
for(var/obj/machinery/transhuman/resleever/P in sleevers)
|
|
P.connected = null
|
|
P.name = initial(P.name)
|
|
sleevers.Cut()
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/proc/findpods()
|
|
var/num = 1
|
|
var/area/A = get_area(src)
|
|
for(var/obj/machinery/clonepod/transhuman/P in A.get_contents())
|
|
if(!P.connected)
|
|
pods += P
|
|
P.connected = src
|
|
P.name = "[initial(P.name)] #[num++]"
|
|
for(var/obj/machinery/transhuman/synthprinter/P in A.get_contents())
|
|
if(!P.connected)
|
|
spods += P
|
|
P.connected = src
|
|
P.name = "[initial(P.name)] #[num++]"
|
|
for(var/obj/machinery/transhuman/resleever/P in A.get_contents())
|
|
if(!P.connected)
|
|
sleevers += P
|
|
P.connected = src
|
|
P.name = "[initial(P.name)] #[num++]"
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/attackby(obj/item/W as obj, mob/user as mob)
|
|
if(istype(W, /obj/item/device/multitool))
|
|
var/obj/item/device/multitool/M = W
|
|
var/obj/machinery/clonepod/transhuman/P = M.connecting
|
|
if(istype(P) && !(P in pods))
|
|
pods += P
|
|
P.connected = src
|
|
P.name = "[initial(P.name)] #[pods.len]"
|
|
to_chat(user, "<span class='notice'>You connect [P] to [src].</span>")
|
|
else if(istype(W, /obj/item/weapon/disk/transcore) && !our_db.core_dumped)
|
|
user.unEquip(W)
|
|
disk = W
|
|
disk.forceMove(src)
|
|
to_chat(user, "<span class='notice'>You insert \the [W] into \the [src].</span>")
|
|
if(istype(W, /obj/item/weapon/disk/body_record))
|
|
var/obj/item/weapon/disk/body_record/brDisk = W
|
|
if(!brDisk.stored)
|
|
to_chat(user, "<span class='warning'>\The [W] does not contain a stored body record.</span>")
|
|
return
|
|
user.unEquip(W)
|
|
W.forceMove(get_turf(src)) // Drop on top of us
|
|
active_br = new /datum/transhuman/body_record(brDisk.stored) // Loads a COPY!
|
|
to_chat(user, "<span class='notice'>\The [src] loads the body record from \the [W] before ejecting it.</span>")
|
|
attack_hand(user)
|
|
view_b_rec("view_b_rec", list("ref" = "\ref[active_br]"))
|
|
else
|
|
..()
|
|
return
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/attack_ai(mob/user as mob)
|
|
return attack_hand(user)
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/attack_hand(mob/user as mob)
|
|
user.set_machine(src)
|
|
add_fingerprint(user)
|
|
|
|
if(stat & (BROKEN|NOPOWER))
|
|
return
|
|
|
|
updatemodules()
|
|
tgui_interact(user)
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/ui_assets(mob/user)
|
|
return list(
|
|
get_asset_datum(/datum/asset/cloning),
|
|
get_asset_datum(/datum/asset/cloning/resleeving),
|
|
)
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/tgui_interact(mob/user, datum/tgui/ui = null)
|
|
if(stat & (NOPOWER|BROKEN))
|
|
return
|
|
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "ResleevingConsole", "Resleeving Console")
|
|
ui.open()
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/tgui_data(mob/user)
|
|
var/data[0]
|
|
data["menu"] = menu
|
|
|
|
var/list/temppods[0]
|
|
for(var/obj/machinery/clonepod/transhuman/pod in pods)
|
|
var/status = "idle"
|
|
if(pod.mess)
|
|
status = "mess"
|
|
else if(pod.occupant && !(pod.stat & NOPOWER))
|
|
status = "cloning"
|
|
temppods.Add(list(list(
|
|
"pod" = "\ref[pod]",
|
|
"name" = sanitize(capitalize(pod.name)),
|
|
"biomass" = pod.get_biomass(),
|
|
"status" = status,
|
|
"progress" = (pod.occupant && pod.occupant.stat != DEAD) ? pod.get_completion() : 0
|
|
)))
|
|
data["pods"] = temppods.Copy()
|
|
temppods.Cut()
|
|
|
|
for(var/obj/machinery/transhuman/synthprinter/spod in spods)
|
|
temppods.Add(list(list(
|
|
"spod" = "\ref[spod]",
|
|
"name" = sanitize(capitalize(spod.name)),
|
|
"busy" = spod.busy,
|
|
"steel" = spod.stored_material[DEFAULT_WALL_MATERIAL],
|
|
"glass" = spod.stored_material["glass"]
|
|
)))
|
|
data["spods"] = temppods.Copy()
|
|
temppods.Cut()
|
|
|
|
for(var/obj/machinery/transhuman/resleever/resleever in sleevers)
|
|
temppods.Add(list(list(
|
|
"sleever" = "\ref[resleever]",
|
|
"name" = sanitize(capitalize(resleever.name)),
|
|
"occupied" = !!resleever.occupant,
|
|
"occupant" = resleever.occupant ? resleever.occupant.real_name : "None"
|
|
)))
|
|
data["sleevers"] = temppods.Copy()
|
|
temppods.Cut()
|
|
|
|
data["coredumped"] = our_db.core_dumped
|
|
data["emergency"] = disk
|
|
data["temp"] = temp
|
|
data["selected_pod"] = "\ref[selected_pod]"
|
|
data["selected_printer"] = "\ref[selected_printer]"
|
|
data["selected_sleever"] = "\ref[selected_sleever]"
|
|
|
|
var/bodyrecords_list_ui[0]
|
|
for(var/N in our_db.body_scans)
|
|
var/datum/transhuman/body_record/BR = our_db.body_scans[N]
|
|
bodyrecords_list_ui[++bodyrecords_list_ui.len] = list("name" = N, "recref" = "\ref[BR]")
|
|
data["bodyrecords"] = bodyrecords_list_ui
|
|
|
|
var/mindrecords_list_ui[0]
|
|
for(var/N in our_db.backed_up)
|
|
var/datum/transhuman/mind_record/MR = our_db.backed_up[N]
|
|
mindrecords_list_ui[++mindrecords_list_ui.len] = list("name" = N, "recref" = "\ref[MR]")
|
|
data["mindrecords"] = mindrecords_list_ui
|
|
|
|
data["modal"] = tgui_modal_data(src)
|
|
return data
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/tgui_act(action, params)
|
|
if(..())
|
|
return TRUE
|
|
|
|
. = TRUE
|
|
switch(tgui_modal_act(src, action, params))
|
|
if(TGUI_MODAL_ANSWER)
|
|
// if(params["id"] == "del_rec" && active_record)
|
|
// var/obj/item/weapon/card/id/C = usr.get_active_hand()
|
|
// if(!istype(C) && !istype(C, /obj/item/device/pda))
|
|
// set_temp("ID not in hand.", "danger")
|
|
// return
|
|
// if(check_access(C))
|
|
// records.Remove(active_record)
|
|
// qdel(active_record)
|
|
// set_temp("Record deleted.", "success")
|
|
// menu = MENU_RECORDS
|
|
// else
|
|
// set_temp("Access denied.", "danger")
|
|
return
|
|
|
|
switch(action)
|
|
if("view_b_rec")
|
|
view_b_rec(action, params)
|
|
if("view_m_rec")
|
|
var/ref = params["ref"]
|
|
if(!length(ref))
|
|
return
|
|
active_mr = locate(ref)
|
|
if(istype(active_mr))
|
|
if(isnull(active_mr.ckey))
|
|
qdel(active_mr)
|
|
set_temp("Error: Record corrupt.", "danger")
|
|
else
|
|
var/can_sleeve_active = 1
|
|
if(!LAZYLEN(sleevers))
|
|
can_sleeve_active = 0
|
|
set_temp("Error: Cannot sleeve due to no sleevers.", "danger")
|
|
if(!selected_sleever)
|
|
can_sleeve_active = 0
|
|
set_temp("Error: Cannot sleeve due to no selected sleever.", "danger")
|
|
if(selected_sleever && !selected_sleever.occupant)
|
|
can_sleeve_active = 0
|
|
set_temp("Error: Cannot sleeve due to lack of sleever occupant.", "danger")
|
|
var/list/payload = list(
|
|
activerecord = "\ref[active_mr]",
|
|
realname = sanitize(active_mr.mindname),
|
|
obviously_dead = active_mr.dead_state == MR_DEAD ? "Past-due" : "Current",
|
|
oocnotes = active_mr.mind_oocnotes ? active_mr.mind_oocnotes : "None.",
|
|
can_sleeve_active = can_sleeve_active,
|
|
)
|
|
tgui_modal_message(src, action, "", null, payload)
|
|
else
|
|
active_mr = null
|
|
set_temp("Error: Record missing.", "danger")
|
|
if("coredump")
|
|
if(disk)
|
|
our_db.core_dump(disk)
|
|
sleep(5)
|
|
visible_message("<span class='warning'>\The [src] spits out \the [disk].</span>")
|
|
disk.forceMove(get_turf(src))
|
|
disk = null
|
|
if("ejectdisk")
|
|
disk.forceMove(get_turf(src))
|
|
disk = null
|
|
|
|
if("create")
|
|
if(istype(active_br))
|
|
//Tried to grow a synth but no synth pods.
|
|
if(active_br.synthetic && !spods.len)
|
|
set_temp("Error: No SynthFabs detected.", "danger")
|
|
//Tried to grow an organic but no growpods.
|
|
else if(!active_br.synthetic && !pods.len)
|
|
set_temp("Error: No growpods detected.", "danger")
|
|
//We have the machines. We can rebuild them. Probably.
|
|
else
|
|
//We're cloning a synth.
|
|
if(active_br.synthetic)
|
|
var/obj/machinery/transhuman/synthprinter/spod = selected_printer
|
|
if(!istype(spod))
|
|
set_temp("Error: No SynthFab selected.", "danger")
|
|
return
|
|
|
|
//Already doing someone.
|
|
if(spod.busy)
|
|
set_temp("Error: SynthFab is currently busy.", "danger")
|
|
return
|
|
|
|
//Not enough steel or glass
|
|
else if(spod.stored_material[DEFAULT_WALL_MATERIAL] < spod.body_cost)
|
|
set_temp("Error: Not enough [DEFAULT_WALL_MATERIAL] in SynthFab.", "danger")
|
|
return
|
|
else if(spod.stored_material["glass"] < spod.body_cost)
|
|
set_temp("Error: Not enough glass in SynthFab.", "danger")
|
|
return
|
|
|
|
//Gross pod (broke mid-cloning or something).
|
|
else if(spod.broken)
|
|
set_temp("Error: SynthFab malfunction.", "danger")
|
|
return
|
|
|
|
//Do the cloning!
|
|
else if(spod.print(active_br))
|
|
set_temp("Initiating printing cycle...", "success")
|
|
menu = 1
|
|
else
|
|
set_temp("Initiating printing cycle... Error: Post-initialisation failed. Printing cycle aborted.", "danger")
|
|
return
|
|
|
|
//We're cloning an organic.
|
|
else
|
|
var/obj/machinery/clonepod/transhuman/pod = selected_pod
|
|
if(!istype(pod))
|
|
set_temp("Error: No clonepod selected.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
//Already doing someone.
|
|
if(pod.occupant)
|
|
set_temp("Error: Growpod is currently occupied.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
//Not enough materials.
|
|
else if(pod.get_biomass() < CLONE_BIOMASS)
|
|
set_temp("Error: Not enough biomass.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
//Gross pod (broke mid-cloning or something).
|
|
else if(pod.mess)
|
|
set_temp("Error: Growpod malfunction.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
//Disabled in config.
|
|
else if(!config.revival_cloning)
|
|
set_temp("Error: Unable to initiate growing cycle.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
//Do the cloning!
|
|
else if(pod.growclone(active_br))
|
|
set_temp("Initiating growing cycle...", "success")
|
|
tgui_modal_clear(src)
|
|
else
|
|
set_temp("Initiating growing cycle... Error: Post-initialisation failed. Growing cycle aborted.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
//The body record is broken somehow.
|
|
else
|
|
set_temp("Error: Data corruption.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
if("sleeve")
|
|
if(istype(active_mr))
|
|
if(!sleevers.len)
|
|
set_temp("Error: No sleevers detected.", "danger")
|
|
else
|
|
var/mode = text2num(params["mode"])
|
|
var/override
|
|
var/obj/machinery/transhuman/resleever/sleever = selected_sleever
|
|
if(!istype(sleever))
|
|
set_temp("Error: No resleeving pod selected.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
switch(mode)
|
|
if(1) //Body resleeving
|
|
//No body to sleeve into.
|
|
if(!sleever.occupant)
|
|
set_temp("Error: Resleeving pod is not occupied.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
//OOC body lock thing.
|
|
if(sleever.occupant.resleeve_lock && active_mr.ckey != sleever.occupant.resleeve_lock)
|
|
set_temp("Error: Mind incompatible with body.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
var/list/subtargets = list()
|
|
for(var/mob/living/carbon/human/H in sleever.occupant)
|
|
if(H.resleeve_lock && active_mr.ckey != H.resleeve_lock)
|
|
continue
|
|
subtargets += H
|
|
if(subtargets.len)
|
|
var/oc_sanity = sleever.occupant
|
|
override = input(usr,"Multiple bodies detected. Select target for resleeving of [active_mr.mindname] manually. Sleeving of primary body is unsafe with sub-contents, and is not listed.", "Resleeving Target") as null|anything in subtargets
|
|
if(!override || oc_sanity != sleever.occupant || !(override in sleever.occupant))
|
|
set_temp("Error: Target selection aborted.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
if(2) //Card resleeving
|
|
if(sleever.sleevecards <= 0)
|
|
set_temp("Error: No available cards in resleever.", "danger")
|
|
tgui_modal_clear(src)
|
|
return
|
|
|
|
//Body to sleeve into, but mind is in another living body.
|
|
if(active_mr.mind_ref.current && active_mr.mind_ref.current.stat < DEAD) //Mind is in a body already that's alive
|
|
var/answer = alert(active_mr.mind_ref.current,"Someone is attempting to restore a backup of your mind. Do you want to abandon this body, and move there? You MAY suffer memory loss! (Same rules as CMD apply)","Resleeving","No","Yes")
|
|
|
|
//They declined to be moved.
|
|
if(answer == "No")
|
|
set_temp("Initiating resleeving... Error: Post-initialisation failed. Resleeving cycle aborted.", "danger")
|
|
tgui_modal_clear(src)
|
|
return TRUE
|
|
|
|
//They were dead, or otherwise available.
|
|
sleever.putmind(active_mr,mode,override,db_key = db_key)
|
|
set_temp("Initiating resleeving...")
|
|
tgui_modal_clear(src)
|
|
|
|
if("refresh")
|
|
SStgui.update_uis(src)
|
|
if("selectpod")
|
|
var/ref = params["ref"]
|
|
if(!length(ref))
|
|
return
|
|
var/obj/machinery/clonepod/selected = locate(ref)
|
|
if(istype(selected) && (selected in pods))
|
|
selected_pod = selected
|
|
if("selectprinter")
|
|
var/ref = params["ref"]
|
|
if(!length(ref))
|
|
return
|
|
var/obj/machinery/transhuman/synthprinter/selected = locate(ref)
|
|
if(istype(selected) && (selected in spods))
|
|
selected_printer = selected
|
|
if("selectsleever")
|
|
var/ref = params["ref"]
|
|
if(!length(ref))
|
|
return
|
|
var/obj/machinery/transhuman/resleever/selected = locate(ref)
|
|
if(istype(selected) && (selected in sleevers))
|
|
selected_sleever = selected
|
|
if("menu")
|
|
menu = clamp(text2num(params["num"]), MENU_MAIN, MENU_MIND)
|
|
if("cleartemp")
|
|
temp = null
|
|
else
|
|
return FALSE
|
|
|
|
// In here because only relevant to computer
|
|
/obj/item/weapon/cmo_disk_holder
|
|
name = "cmo emergency packet"
|
|
desc = "A small paper packet with printing on one side. \"Tear open in case of Code Delta or Emergency Evacuation ONLY. Use in any other case is UNLAWFUL.\""
|
|
catalogue_data = list(/datum/category_item/catalogue/technology/resleeving)
|
|
icon = 'icons/vore/custom_items_vr.dmi'
|
|
icon_state = "cmoemergency"
|
|
item_state = "card-id"
|
|
|
|
/obj/item/weapon/cmo_disk_holder/attack_self(var/mob/attacker)
|
|
playsound(src, 'sound/items/poster_ripped.ogg', 50)
|
|
to_chat(attacker, "<span class='warning'>You tear open \the [name].</span>")
|
|
attacker.unEquip(src)
|
|
var/obj/item/weapon/disk/transcore/newdisk = new(get_turf(src))
|
|
attacker.put_in_any_hand_if_possible(newdisk)
|
|
qdel(src)
|
|
|
|
/obj/item/weapon/disk/transcore
|
|
name = "TransCore Dump Disk"
|
|
desc = "It has a small label. \n\
|
|
\"1.INSERT DISK INTO RESLEEVING CONSOLE\n\
|
|
2. BEGIN CORE DUMP PROCEDURE\n\
|
|
3. ENSURE DISK SAFETY WHEN EJECTED\""
|
|
catalogue_data = list(/datum/category_item/catalogue/technology/resleeving)
|
|
icon = 'icons/obj/cloning.dmi'
|
|
icon_state = "harddisk"
|
|
item_state = "card-id"
|
|
w_class = ITEMSIZE_SMALL
|
|
var/list/datum/transhuman/mind_record/stored = list()
|
|
|
|
/**
|
|
* Sets a temporary message to display to the user
|
|
*
|
|
* Arguments:
|
|
* * text - Text to display, null/empty to clear the message from the UI
|
|
* * style - The style of the message: (color name), info, success, warning, danger
|
|
*/
|
|
/obj/machinery/computer/transhuman/resleeving/proc/set_temp(text = "", style = "info", update_now = FALSE)
|
|
temp = list(text = text, style = style)
|
|
if(update_now)
|
|
SStgui.update_uis(src)
|
|
|
|
/obj/machinery/computer/transhuman/resleeving/proc/view_b_rec(action, params)
|
|
var/ref = params["ref"]
|
|
if(!length(ref))
|
|
return
|
|
active_br = locate(ref)
|
|
if(istype(active_br))
|
|
var/can_grow_active = 1
|
|
if(!synthetic_capable && active_br.synthetic) //Disqualified due to being synthetic in an organic only.
|
|
can_grow_active = 0
|
|
set_temp("Error: Cannot grow [active_br.mydna.name] due to lack of synthfabs.", "danger")
|
|
else if(!organic_capable && !active_br.synthetic) //Disqualified for the opposite.
|
|
can_grow_active = 0
|
|
set_temp("Error: Cannot grow [active_br.mydna.name] due to lack of cloners.", "danger")
|
|
else if(!synthetic_capable && !organic_capable) //What have you done??
|
|
can_grow_active = 0
|
|
set_temp("Error: Cannot grow [active_br.mydna.name] due to lack of synthfabs and cloners.", "danger")
|
|
else if(active_br.toocomplex)
|
|
can_grow_active = 0
|
|
set_temp("Error: Cannot grow [active_br.mydna.name] due to species complexity.", "danger")
|
|
var/list/payload = list(
|
|
activerecord = "\ref[active_br]",
|
|
realname = sanitize(active_br.mydna.name),
|
|
species = active_br.speciesname ? active_br.speciesname : active_br.mydna.dna.species,
|
|
sex = active_br.bodygender,
|
|
mind_compat = active_br.locked ? "Low" : "High",
|
|
synthetic = active_br.synthetic,
|
|
oocnotes = active_br.body_oocnotes ? active_br.body_oocnotes : "None",
|
|
can_grow_active = can_grow_active,
|
|
)
|
|
tgui_modal_message(src, action, "", null, payload)
|
|
else
|
|
active_br = null
|
|
set_temp("Error: Record missing.", "danger")
|
|
|
|
#undef MENU_MAIN
|
|
#undef MENU_BODY
|
|
#undef MENU_MIND
|