Bioprinter refactor and nanoUI-ification (#9021)

* Good hunk of work on bioprinter refactoring

* and now I sleep

* strongDMM, update maps

* compile tgui bundle

* testing refinements

* Convert to nano

* Slice out the tgui bits
This commit is contained in:
Ava
2023-03-23 18:25:42 -08:00
committed by GitHub
parent 46c088f9e8
commit 8ede4b4c79
8 changed files with 250 additions and 285 deletions
+5
View File
@@ -451,3 +451,8 @@ GLOBAL_LIST_INIT(all_volume_channels, list(
#endif
#define DOCK_ATTEMPT_TIMEOUT 200 //how long in ticks we wait before assuming the docking controller is broken or blown up.
// Syringe usage modes.
#define SYRINGE_DRAW 0
#define SYRINGE_INJECT 1
#define SYRINGE_BROKEN 2
+202 -278
View File
@@ -1,32 +1,47 @@
// GENERIC PRINTER - DO NOT USE THIS OBJECT.
// Flesh and robot printers are defined below this object.
/obj/machinery/organ_printer
name = "organ printer"
desc = "It's a machine that prints organs."
/// Prints organs by consuming biomass from an inserted container.
/obj/machinery/bioprinter
name = "bioprinter"
desc = "This is a growth chamber capable of quickly producing fresh body parts to fuel your inner mad scientist (or to perform transplants with, if you're boring like that.) Blood samples and biomass go in, kidneys come out."
description_info = "Consumes specialized biomass from an inserted container. More can be made through chemistry, but it requires a lot of phoron."
description_fluff = "Bioprinting new body parts can take days or even weeks, depending on the thing in question. However, some printers - like this one - can be built to run on a specialized phoron-based feedstock, allowing surrogate organs and appendages to be assembled in a matter of seconds. Printing in this way is insanely expensive, though, which prevents it from enjoying the ubiquity that slower machines do."
icon = 'icons/obj/surgery.dmi'
icon_state = "bioprinter"
anchored = 1
density = 1
anchored = TRUE
density = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 40
active_power_usage = 300
circuit = /obj/item/circuitboard/bioprinter
var/obj/item/reagent_containers/container = null // This is the beaker that holds all of the biomass
/// The reagent used by this bioprinter as fuel to produce things.
var/biomass_id = "biomass"
/// The container that biomass will be drawn from; without one, the machine cannot function.
var/obj/item/reagent_containers/container = null
var/print_delay = 100
var/base_print_delay = 100 // For Adminbus reasons
var/printing
var/loaded_dna //Blood sample for DNA hashing.
var/malfunctioning = FALSE // May cause rejection, or the printing of some alien limb instead!
/// How long in deciseconds it takes to print an organ. This is updated dynamically by parts.
var/print_delay = 10 SECONDS
/// The base time it takes for an organ to be printed. Should be type-specific, can be varedited for adminbus.
var/base_print_delay = 10 SECONDS
/// Printing an organ uses a stoppable timer; this variable references that timer's ID.
/// Checking if this variable is null or not is used to determine whether or not the printer is actually printing.
var/print_timer
/// Data from a loaded blood sample, copied directly from the `data` list of `/datum/reagent/blood`.
var/loaded_dna
var/complex_organs = FALSE // Can it print more 'complex' organs?
/// Organs printed by this machine might be from a different species, or cause rejection.
/// Caused by using very high-rating parts (i.e. precursor tech.)
var/malfunctioning = FALSE
/// Allows the printer to create "complex" organs, like the brain and larynx.
/// Granted by using high-quality parts.
var/complex_organs = FALSE
/// Allows the printer to create "anomalous" organs that it shouldn't usually be able to.
/// Granted by using very high-rating parts, like `malfunctioning` is.
var/anomalous_organs = FALSE
var/anomalous_organs = FALSE // Can it print anomalous organs?
// These should be subtypes of /obj/item/organ
// Costs roughly 20u Phoron (1 sheet) per internal organ, limbs are 60u for limb and extremity
/// A list of all the products that this bioprinter can produce by default.
/// 1 unit of biomass (the default fuel) costs 1 unit of phoron,
/// so each organ costs roughly 20u of phoron (1 sheet) and each limb costs 40u of phoron (2 sheets).
var/list/products = list(
"Heart" = list(/obj/item/organ/internal/heart, 20),
"Lungs" = list(/obj/item/organ/internal/lungs, 20),
@@ -44,336 +59,245 @@
"Hand, Right" = list(/obj/item/organ/external/hand/right, 20)
)
/// Dynamically included with `products` if `complex_organs` is true.
var/list/complex_products = list(
"Brain" = list(/obj/item/organ/internal/brain, 60),
"Larynx" = list(/obj/item/organ/internal/voicebox, 20),
"Head" = list(/obj/item/organ/external/head, 40)
)
/// Dynamically included with `products` if `anomalous_organs` is true.
/// Anything in this list will appear with a purple name in the UI, instead of the default blue.
var/list/anomalous_products = list(
"Lymphatic Complex" = list(/obj/item/organ/internal/immunehub, 120),
"Respiration Nexus" = list(/obj/item/organ/internal/lungs/replicant/mending, 80),
"Adrenal Valve Cluster" = list(/obj/item/organ/internal/heart/replicant/rage, 80)
)
/obj/machinery/organ_printer/attackby(var/obj/item/O, var/mob/user)
if(default_deconstruction_screwdriver(user, O))
/obj/machinery/bioprinter/Initialize()
. = ..()
default_apply_parts()
/obj/machinery/bioprinter/full/Initialize()
. = ..()
container = new /obj/item/reagent_containers/glass/bottle/biomass(src)
/obj/machinery/bioprinter/dismantle()
var/turf/T = get_turf(src)
if (T && container)
container.forceMove(T)
container = null
return ..()
/obj/machinery/bioprinter/attackby(obj/item/I, mob/user)
if (default_deconstruction_screwdriver(user, I))
updateUsrDialog()
return
if(default_deconstruction_crowbar(user, O))
if (default_deconstruction_crowbar(user, I))
return
if(default_part_replacement(user, O))
if (default_part_replacement(user, I))
return
if(default_unfasten_wrench(user, O, 20))
if (default_unfasten_wrench(user, I, 20))
return
if (istype(I, /obj/item/reagent_containers/syringe))
var/obj/item/reagent_containers/syringe/S = I
var/datum/reagent/blood/sample = S.reagents.get_reagent("blood")
if (!sample?.data)
to_chat(user, SPAN_WARNING("\The [I] doesn't contain a valid blood sample."))
return
loaded_dna = sample.data
S.reagents.clear_reagents()
S.mode = SYRINGE_DRAW
S.update_icon()
user.visible_message(
SPAN_NOTICE("\The [user] fills \the [src] with a blood sample."),
SPAN_NOTICE("You inject \the [src] with a blood sample from \the [I].")
)
SSnanoui.update_uis(src)
return
if (istype(I, /obj/item/reagent_containers/glass))
if (container)
to_chat(user, SPAN_WARNING("\The [src] already has a container loaded."))
return
var/obj/item/reagent_containers/glass/G = I
if (!do_after(user, 1 SECOND))
return
user.visible_message(
SPAN_NOTICE("\The [user] loads \the [G] into \the [src]."),
SPAN_NOTICE("You load \the [G] into \the [src].")
)
user.drop_from_inventory(G)
G.forceMove(src)
container = G
SSnanoui.update_uis(src)
return
return ..()
/obj/machinery/organ_printer/update_icon()
/obj/machinery/bioprinter/update_icon()
cut_overlays()
if(panel_open)
if (panel_open)
add_overlay("bioprinter_panel_open")
if(printing)
if (print_timer != null)
add_overlay("bioprinter_working")
/obj/machinery/organ_printer/Initialize()
. = ..()
default_apply_parts()
/obj/machinery/organ_printer/examine(var/mob/user)
. = ..()
var/biomass = get_biomass_volume()
if(biomass)
. += "<span class='notice'>It is loaded with [biomass] units of biomass.</span>"
else
. += "<span class='notice'>It is not loaded with any biomass.</span>"
/obj/machinery/organ_printer/RefreshParts()
// Print Delay updating
/obj/machinery/bioprinter/RefreshParts()
print_delay = base_print_delay
var/manip_rating = 0
for(var/obj/item/stock_parts/manipulator/manip in component_parts)
manip_rating += manip.rating
print_delay -= (manip.rating-1)*10
print_delay = max(0,print_delay)
for(var/obj/item/stock_parts/manipulator/M in component_parts)
manip_rating += M.rating
print_delay -= (M.rating - 1) * 1 SECOND
print_delay = max(0, print_delay)
// Update the capabilities of the bioprinter based on its rating divided by half.
// 3 = can print complex organs
// 4 = can print anomalous organs
// 5 = 30% chance to malfunction when printing
manip_rating = round(manip_rating / 2)
if(manip_rating >= 5)
malfunctioning = TRUE
else
malfunctioning = initial(malfunctioning)
if(manip_rating >= 3)
complex_organs = TRUE
if(manip_rating >= 4)
anomalous_organs = TRUE
if(manip_rating >= 5)
malfunctioning = TRUE
else
complex_organs = initial(complex_organs)
anomalous_organs = initial(anomalous_organs)
malfunctioning = initial(malfunctioning)
complex_organs = manip_rating >= 3
anomalous_organs = manip_rating >= 4
malfunctioning = manip_rating >= 5
. = ..()
/obj/machinery/organ_printer/attack_hand(mob/user)
if(stat & (BROKEN|NOPOWER))
/obj/machinery/bioprinter/attack_hand(mob/user)
if (stat & (BROKEN|NOPOWER))
return
if(panel_open)
to_chat(user, "<span class='warning'>Close the panel first!</span>")
else if (panel_open)
to_chat(user, SPAN_WARNING("Close the panel first!"))
return
ui_interact(user)
if(printing)
to_chat(user, "<span class='notice'>\The [src] is busy!</span>")
return
/obj/machinery/bioprinter/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, master_ui, datum/topic_state/state)
var/list/data = build_ui_data()
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open = force_open)
if (!ui)
ui = new(user, src, ui_key, "bioprinter.tmpl", capitalize(name), 500, 650)
ui.set_initial_data(data)
ui.open()
if(container)
var/response = alert(user, "What do you want to do?", "Bioprinter Menu", "Print Limbs", "Cancel")
if(response == "Print Limbs")
printing_menu(user)
else
to_chat(user, "<span class='warning'>\The [src] can't operate without a reagent reservoir!</span>")
/obj/machinery/bioprinter/proc/build_ui_data()
var/data[0]
/obj/machinery/organ_printer/proc/printing_menu(mob/user)
var/list/possible_list = list()
data["biomassContainer"] = container
data["biomassVolume"] = get_biomass_volume()
data["biomassMax"] = container?.reagents.maximum_volume
possible_list |= products
data["printTime"] = print_delay
data["isPrinting"] = print_timer != null
if(complex_organs)
possible_list |= complex_products
data["dna"] = loaded_dna
data["dnaHash"] = loaded_dna?["blood_DNA"]
// This is pretty hacky, but it seems like the blood sample doesn't otherwise keep its species data handy
var/mob/living/carbon/human/donor = loaded_dna?["donor"]
data["dnaSpecies"] = donor?.species ? donor.species.name : "N/A"
if(anomalous_organs)
possible_list |= anomalous_products
var/list/valid_products = list()
valid_products |= products
if (complex_organs)
valid_products |= complex_products
if (anomalous_organs)
valid_products |= anomalous_products
var/choice = input("What would you like to print?") as null|anything in possible_list
var/products_data[0]
for (var/O in valid_products)
products_data[++products_data.len] = list(
"name" = O,
"cost" = valid_products[O][2],
"canPrint" = (get_biomass_volume() >= valid_products[O][2]) && loaded_dna,
"anomalous" = anomalous_products.Find(O)
)
data["products"] = products_data
if(!choice || printing || (stat & (BROKEN|NOPOWER)))
return
return data
if(!can_print(choice, possible_list[choice][2]))
return
container.reagents.remove_reagent("biomass", possible_list[choice][2])
update_use_power(USE_POWER_ACTIVE)
printing = 1
/obj/machinery/bioprinter/Topic(href, href_list, datum/topic_state/state)
if (..())
return TRUE
if (href_list["ejectBeaker"])
if (container)
container.forceMove(get_turf(src))
if (usr.Adjacent(src))
usr.put_in_active_hand(container)
container = null
if (href_list["flushDNA"])
if (loaded_dna)
loaded_dna = null
visible_message(SPAN_NOTICE("\The [src] whirrs and discards its most recent DNA sample."))
if (href_list["printOrgan"])
var/organ_name = href_list["printOrgan"]
var/list/all_products = products + complex_products + anomalous_products
var/product_entry = all_products[organ_name]
var/atom/product_path = product_entry?[1]
if (product_entry && product_path && get_biomass_volume() >= product_entry[2])
container.reagents.remove_reagent(biomass_id, product_entry[2])
playsound(src, "switch", 30)
visible_message(SPAN_NOTICE("\The [src] fills with fluid and begins to print \a [initial(product_path.name)]."))
print_timer = addtimer(CALLBACK(src, .proc/print_organ, product_entry[1]), print_delay, TIMER_STOPPABLE)
set_active(TRUE)
if (href_list["cancelPrint"])
if (print_timer)
playsound(src, "switch", 30)
playsound(src, 'sound/effects/squelch1.ogg', 40, TRUE)
visible_message(SPAN_WARNING("\The [src] gurgles as it cancels its current task and discards the pulpy biomass."))
deltimer(print_timer)
print_timer = null
set_active(FALSE)
SSnanoui.update_uis(src)
update_icon()
visible_message("<span class='notice'>\The [src] begins churning.</span>")
sleep(print_delay)
update_use_power(USE_POWER_IDLE)
printing = 0
/// Updates power usage in accordance with `active` and forces an icon update.
/obj/machinery/bioprinter/proc/set_active(active)
update_use_power(active ? USE_POWER_ACTIVE : USE_POWER_IDLE)
update_icon()
if(!choice || !src || (stat & (BROKEN|NOPOWER)))
return
print_organ(possible_list[choice][1])
return
/obj/machinery/organ_printer/verb/eject_beaker()
set name = "Eject Beaker"
set category = "Object"
set src in oview(1)
if(usr.stat != 0)
return
add_fingerprint(usr)
remove_beaker()
return
// Does exactly what it says it does
// Returns 1 if it succeeds, 0 if it fails. Added in case someone wants to add messages to the user.
/obj/machinery/organ_printer/proc/remove_beaker()
if(container)
container.forceMove(get_turf(src))
container = null
return 1
return 0
// Checks for reagents, then reports how much biomass it has in it
/obj/machinery/organ_printer/proc/get_biomass_volume()
/// Returns the amount of usable biomass that this printer has.
/// 0 will be returned if no container is loaded.
/obj/machinery/bioprinter/proc/get_biomass_volume()
var/biomass_count = 0
if(container && container.reagents)
for(var/datum/reagent/R in container.reagents.reagent_list)
if(R.id == "biomass")
biomass_count += R.volume
if (container?.reagents)
biomass_count += container.reagents.get_reagent_amount(biomass_id)
return biomass_count
/obj/machinery/organ_printer/proc/can_print(var/choice, var/masscount = 0)
var/biomass = get_biomass_volume()
if(biomass < masscount)
visible_message("<span class='notice'>\The [src] displays a warning: 'Not enough biomass. [biomass] stored and [masscount] needed.'</span>")
return 0
if(!loaded_dna || !loaded_dna["donor"])
visible_message("<span class='info'>\The [src] displays a warning: 'No DNA saved. Insert a blood sample.'</span>")
return 0
return 1
/obj/machinery/organ_printer/proc/print_organ(var/choice)
var/new_organ = choice
var/obj/item/organ/O = new new_organ(get_turf(src))
O.status |= ORGAN_CUT_AWAY
/// Prints an organ of typepath `choice`, with DNA and species set to that of `loaded_dna["donor"]`.
/// If `malfunctioning` is true, has a 30% chance to mess it up as well.
/// Returns a reference to the new organ.
/obj/machinery/bioprinter/proc/print_organ(atom/choice)
var/mob/living/carbon/human/C = loaded_dna["donor"]
var/obj/item/organ/O = new choice(get_turf(src))
O.status |= ORGAN_CUT_AWAY
O.set_dna(C.dna)
O.species = C.species
var/malfunctioned = FALSE
if(malfunctioning && prob(30)) // Alien Tech is a hell of a drug.
if (malfunctioning && prob(30)) // Alien Tech is a hell of a drug.
malfunctioned = TRUE
var/possible_species = list(SPECIES_HUMAN, SPECIES_VOX, SPECIES_SKRELL, SPECIES_ZADDAT, SPECIES_UNATHI, SPECIES_GOLEM, SPECIES_SHADOW)
var/new_species = pick(possible_species)
if(!GLOB.all_species[new_species])
if (!GLOB.all_species[new_species])
new_species = SPECIES_HUMAN
O.species = GLOB.all_species[new_species]
if(istype(O, /obj/item/organ/external) && !malfunctioned)
if (istype(O, /obj/item/organ/external) && !malfunctioned)
var/obj/item/organ/external/E = O
E.sync_colour_to_human(C)
O.pixel_x = rand(-6.0, 6)
O.pixel_y = rand(-6.0, 6)
if(O.species)
// This is a very hacky way of doing of what organ/New() does if it has an owner
if (O.species)
// This is a very hacky way of doing of what organ/Initialize() does if it has an owner
O.w_class = max(O.w_class + mob_size_difference(O.species.mob_size, MOB_MEDIUM), 1)
print_timer = null
playsound(src, 'sound/machines/kitchen/microwave/microwave-end.ogg', 50, TRUE)
visible_message(SPAN_NOTICE("\The [src] dings and spits out \a [O.name]."))
set_active(FALSE)
SSnanoui.update_uis(src)
return O
// END GENERIC PRINTER
// CIRCUITS
/obj/item/circuitboard/bioprinter
name = "bioprinter circuit"
build_path = /obj/machinery/organ_printer/flesh
build_path = /obj/machinery/bioprinter
board_type = new /datum/frame/frame_types/machine
origin_tech = list(TECH_DATA = 3, TECH_BIO = 3)
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 2)
// FLESH ORGAN PRINTER
/obj/machinery/organ_printer/flesh
name = "bioprinter"
desc = "It's a machine that prints replacement organs."
icon_state = "bioprinter"
circuit = /obj/item/circuitboard/bioprinter
/obj/machinery/organ_printer/flesh/full/Initialize()
. = ..()
container = new /obj/item/reagent_containers/glass/bottle/biomass(src)
/obj/machinery/organ_printer/flesh/dismantle()
var/turf/T = get_turf(src)
if(T)
if(container)
container.forceMove(T)
container = null
return ..()
/obj/machinery/organ_printer/flesh/print_organ(var/choice)
var/obj/item/organ/O = ..()
playsound(src, 'sound/machines/ding.ogg', 50, 1)
visible_message("<span class='info'>\The [src] dings, then spits out \a [O].</span>")
return O
/obj/machinery/organ_printer/flesh/attackby(obj/item/W, mob/user)
// DNA sample from syringe.
if(istype(W,/obj/item/reagent_containers/syringe)) //TODO: Make this actually empty the syringe
var/obj/item/reagent_containers/syringe/S = W
var/datum/reagent/blood/injected = locate() in S.reagents.reagent_list //Grab some blood
if(injected && injected.data)
loaded_dna = injected.data
S.reagents.remove_reagent("blood", injected.volume)
to_chat(user, "<span class='info'>You scan the blood sample into the bioprinter.</span>")
return
else if(istype(W,/obj/item/reagent_containers/glass))
var/obj/item/reagent_containers/glass/G = W
if(container)
to_chat(user, "<span class='warning'>\The [src] already has a container loaded!</span>")
return
else if(do_after(user, 1 SECOND))
user.visible_message("[user] has loaded \the [G] into \the [src].", "You load \the [G] into \the [src].")
container = G
user.drop_item()
G.forceMove(src)
return
return ..()
// END FLESH ORGAN PRINTER
/* Roboprinter is made obsolete by the system already in place and mapped into Robotics
/obj/item/circuitboard/roboprinter
name = "roboprinter circuit"
build_path = /obj/machinery/organ_printer/robot
board_type = new /datum/frame/frame_types/machine
origin_tech = list(TECH_DATA = 3, TECH_BIO = 3)
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 2)
// ROBOT ORGAN PRINTER
// Still Requires DNA, /obj/machinery/pros_fab is better for limbs
/obj/machinery/organ_printer/robot
name = "prosthetic organ fabricator"
desc = "It's a machine that prints prosthetic organs."
icon_state = "roboprinter"
circuit = /obj/item/circuitboard/roboprinter
var/matter_amount_per_sheet = 10
var/matter_type = MAT_STEEL
/obj/machinery/organ_printer/robot/full/Initialize()
. = ..()
stored_matter = max_stored_matter
/obj/machinery/organ_printer/robot/dismantle()
if(stored_matter >= matter_amount_per_sheet)
new /obj/item/stack/material/steel(get_turf(src), FLOOR(stored_matter/matter_amount_per_sheet, 1))
return ..()
/obj/machinery/organ_printer/robot/print_organ(var/choice)
var/obj/item/organ/O = ..()
O.robotize()
O.status |= ORGAN_CUT_AWAY // robotize() resets status to 0
playsound(src, 'sound/machines/ding.ogg', 50, 1)
audible_message("<span class='info'>\The [src] dings, then spits out \a [O].</span>")
return O
/obj/machinery/organ_printer/robot/attackby(var/obj/item/W, var/mob/user)
if(istype(W, /obj/item/stack/material) && W.get_material_name() == matter_type)
if((max_stored_matter-stored_matter) < matter_amount_per_sheet)
to_chat(user, "<span class='warning'>\The [src] is too full.</span>")
return
var/obj/item/stack/S = W
var/space_left = max_stored_matter - stored_matter
var/sheets_to_take = min(S.amount, FLOOR(space_left/matter_amount_per_sheet, 1))
if(sheets_to_take <= 0)
to_chat(user, "<span class='warning'>\The [src] is too full.</span>")
return
stored_matter = min(max_stored_matter, stored_matter + (sheets_to_take*matter_amount_per_sheet))
to_chat(user, "<span class='info'>\The [src] processes \the [W]. Levels of stored matter now: [stored_matter]</span>")
S.use(sheets_to_take)
return
else if(istype(W,/obj/item/reagent_containers/syringe)) //TODO: Make this actuall empty the syringe
var/obj/item/reagent_containers/syringe/S = W
var/datum/reagent/blood/injected = locate() in S.reagents.reagent_list //Grab some blood
if(injected && injected.data)
loaded_dna = injected.data
to_chat(user, "<span class='info'>You scan the blood sample into the bioprinter.</span>")
return
return ..()
// END ROBOT ORGAN PRINTER
*/
@@ -1,9 +1,6 @@
////////////////////////////////////////////////////////////////////////////////
/// Syringes.
////////////////////////////////////////////////////////////////////////////////
#define SYRINGE_DRAW 0
#define SYRINGE_INJECT 1
#define SYRINGE_BROKEN 2
/obj/item/reagent_containers/syringe
name = "syringe"
+1 -1
View File
@@ -27115,7 +27115,7 @@
dir = 1;
pixel_y = -24
},
/obj/machinery/organ_printer/flesh/full,
/obj/machinery/bioprinter/full,
/turf/simulated/floor/tiled/neutral,
/area/surface/station/medical/cloning)
"mjM" = (
+1 -1
View File
@@ -79504,7 +79504,7 @@
/obj/effect/floor_decal/corner/purple/border{
dir = 1
},
/obj/machinery/organ_printer/flesh/full,
/obj/machinery/bioprinter/full,
/turf/simulated/floor/tiled/white,
/area/medical/genetics_cloning)
"cRS" = (
@@ -194,7 +194,7 @@
/turf/simulated/floor/tiled/white,
/area/submap/Blackshuttledown)
"aF" = (
/obj/machinery/organ_printer/flesh,
/obj/machinery/bioprinter,
/obj/effect/floor_decal/corner/green/border{
dir = 5;
icon_state = "bordercolor"
@@ -197,7 +197,7 @@
/turf/simulated/floor/tiled/white,
/area/submap/Blackshuttledown)
"aF" = (
/obj/machinery/organ_printer/flesh,
/obj/machinery/bioprinter,
/obj/effect/floor_decal/corner/green/border{
dir = 5;
icon_state = "bordercolor"
+39
View File
@@ -0,0 +1,39 @@
{{if data.isPrinting}}
<div class="notice">
Printing in progress...
<div class="floatRight">
{{:helper.link("Cancel", "cancel", { 'cancelPrint': 1 })}}
</div>
</div>
{{/if}}
{{:helper.link("Flush DNA Sample", "trash", { 'flushDNA': 1 }, data.dna && !data.isPrinting ? null : 'disabled')}}
{{:helper.link("Eject Container", "eject", { 'ejectBeaker': 1 }, data.biomassContainer && !data.isPrinting ? null : 'disabled')}}
<br/><br/>
{{if !data.biomassContainer}}
<span class="bad">No biomass container inserted.</span>
{{else}}
<b>Stored biomass:</b> {{:data.biomassVolume}}/{{:data.biomassMax}}
{{/if}}
<br/>
{{if !data.dna}}
<span class="bad">No DNA sample inserted.</span>
{{else}}
<b>DNA hash:</b> {{:data.dnaHash}}<br/>
<b>DNA species:</b> {{:data.dnaSpecies}}
{{/if}}
<br/>
<b>Time to print:</b> {{:data.printTime / 10}} seconds
<hr/>
{{for data.products}}
<div class="item">
<div class="itemLabel">
{{:value.name}}
</div>
<div>
{{:helper.string('{0}/{1}', value.cost < data.biomassVolume ? value.cost : data.biomassVolume, value.cost)}}
<div class="floatRight">
{{:helper.link("Print", null, { "printOrgan" : value.name }, value.canPrint && !data.isPrinting ? null : 'disabled')}}
</div>
</div>
</div>
{{/for}}