mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-24 20:47:10 +01:00
Merge pull request #13738 from dearmochi/tgui-medical
[TGUI] Medical Machines
This commit is contained in:
@@ -92,3 +92,8 @@
|
||||
// Firelock states
|
||||
#define FD_OPEN 1
|
||||
#define FD_CLOSED 2
|
||||
|
||||
// Computer login types
|
||||
#define LOGIN_TYPE_NORMAL 1
|
||||
#define LOGIN_TYPE_AI 2
|
||||
#define LOGIN_TYPE_ROBOT 3
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// TGUI defines
|
||||
#define TGUI_MODAL_INPUT_MAX_LENGTH 1024
|
||||
#define TGUI_MODAL_INPUT_MAX_LENGTH_NAME 64 // Names for generally anything don't go past 32, let alone 64.
|
||||
|
||||
#define TGUI_MODAL_OPEN 1
|
||||
#define TGUI_MODAL_DELEGATE 2
|
||||
#define TGUI_MODAL_ANSWER 3
|
||||
#define TGUI_MODAL_CLOSE 4
|
||||
+343
-403
@@ -7,6 +7,11 @@
|
||||
|
||||
#define NEGATE_MUTATION_THRESHOLD 30 // Occupants with over ## percent radiation threshold will not gain mutations
|
||||
|
||||
#define PAGE_UI "ui"
|
||||
#define PAGE_SE "se"
|
||||
#define PAGE_BUFFER "buffer"
|
||||
#define PAGE_REJUVENATORS "rejuvenators"
|
||||
|
||||
//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
|
||||
/datum/dna2/record
|
||||
var/datum/dna/dna = null
|
||||
@@ -161,6 +166,7 @@
|
||||
occupant = usr
|
||||
icon_state = "scanner_occupied"
|
||||
add_fingerprint(usr)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/dna_scannernew/MouseDrop_T(atom/movable/O, mob/user)
|
||||
if(!istype(O))
|
||||
@@ -214,6 +220,7 @@
|
||||
return
|
||||
|
||||
beaker = I
|
||||
SStgui.update_uis(src)
|
||||
I.forceMove(src)
|
||||
user.visible_message("[user] adds \a [I] to \the [src]!", "You add \a [I] to \the [src]!")
|
||||
return
|
||||
@@ -260,6 +267,7 @@
|
||||
M.forceMove(src)
|
||||
occupant = M
|
||||
icon_state = "scanner_occupied"
|
||||
SStgui.update_uis(src)
|
||||
|
||||
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
|
||||
if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
|
||||
@@ -281,6 +289,7 @@
|
||||
occupant.forceMove(loc)
|
||||
occupant = null
|
||||
icon_state = "scanner_open"
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/dna_scannernew/force_eject_occupant()
|
||||
go_out(null, TRUE)
|
||||
@@ -296,6 +305,7 @@
|
||||
occupant = null
|
||||
updateUsrDialog()
|
||||
update_icon()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
// Checks if occupants can be irradiated/mutated - prevents exploits where wearing full rad protection would still let you gain mutations
|
||||
/obj/machinery/dna_scannernew/proc/radiation_check()
|
||||
@@ -333,12 +343,11 @@
|
||||
var/injector_ready = FALSE //Quick fix for issue 286 (screwdriver the screen twice to restore injector) -Pete
|
||||
var/obj/machinery/dna_scannernew/connected = null
|
||||
var/obj/item/disk/data/disk = null
|
||||
var/selected_menu_key = null
|
||||
var/selected_menu_key = PAGE_UI
|
||||
anchored = TRUE
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 10
|
||||
active_power_usage = 400
|
||||
var/waiting_for_user_input = 0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/disk/data)) //INSERT SOME diskS
|
||||
@@ -347,7 +356,7 @@
|
||||
I.forceMove(src)
|
||||
disk = I
|
||||
to_chat(user, "You insert [I].")
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src()
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
@@ -399,35 +408,18 @@
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/**
|
||||
* The ui_interact proc is used to open and update Nano UIs
|
||||
* If ui_interact is not used then the UI will not update correctly
|
||||
* ui_interact is currently defined for /atom/movable
|
||||
*
|
||||
* @param user /mob The mob who is interacting with this ui
|
||||
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
|
||||
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
/obj/machinery/computer/scan_consolenew/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
if(user == connected.occupant)
|
||||
return
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "dna_modifier.tmpl", "DNA Modifier Console", 660, 700)
|
||||
// open the new ui window
|
||||
ui = new(user, src, ui_key, "DNAModifier", name, 660, 700, master_ui, state)
|
||||
ui.open()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/ui_data(mob/user, datum/topic_state/state)
|
||||
/obj/machinery/computer/scan_consolenew/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["selectedMenuKey"] = selected_menu_key
|
||||
data["locked"] = connected.locked
|
||||
@@ -501,9 +493,12 @@
|
||||
for(var/datum/reagent/R in connected.beaker.reagents.reagent_list)
|
||||
data["beakerVolume"] += R.volume
|
||||
|
||||
// Transfer modal information if there is one
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/Topic(href, href_list)
|
||||
/obj/machinery/computer/scan_consolenew/tgui_act(action, params)
|
||||
if(..())
|
||||
return FALSE // don't update uis
|
||||
if(!istype(usr.loc, /turf))
|
||||
@@ -512,405 +507,350 @@
|
||||
return FALSE // don't update uis
|
||||
if(irradiating) // Make sure that it isn't already irradiating someone...
|
||||
return FALSE // don't update uis
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
add_fingerprint(usr)
|
||||
|
||||
if(href_list["selectMenuKey"])
|
||||
selected_menu_key = href_list["selectMenuKey"]
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["toggleLock"])
|
||||
if((connected && connected.occupant))
|
||||
connected.locked = !(connected.locked)
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["pulseRadiation"])
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
if(!connected.occupant)
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
if(connected.radiation_check())
|
||||
return TRUE
|
||||
|
||||
if(prob(95))
|
||||
if(prob(75))
|
||||
randmutb(connected.occupant)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
else
|
||||
if(prob(95))
|
||||
randmutg(connected.occupant)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["radiationDuration"])
|
||||
if(text2num(href_list["radiationDuration"]) > 0)
|
||||
if(radiation_duration < 20)
|
||||
radiation_duration += 2
|
||||
else
|
||||
if(radiation_duration > 2)
|
||||
radiation_duration -= 2
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["radiationIntensity"])
|
||||
if(text2num(href_list["radiationIntensity"]) > 0)
|
||||
if(radiation_intensity < 10)
|
||||
radiation_intensity++
|
||||
else
|
||||
if(radiation_intensity > 1)
|
||||
radiation_intensity--
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
if(href_list["changeUITarget"] && text2num(href_list["changeUITarget"]) > 0)
|
||||
if(selected_ui_target < 15)
|
||||
selected_ui_target++
|
||||
selected_ui_target_hex = selected_ui_target
|
||||
switch(selected_ui_target)
|
||||
if(10)
|
||||
selected_ui_target_hex = "A"
|
||||
if(11)
|
||||
selected_ui_target_hex = "B"
|
||||
if(12)
|
||||
selected_ui_target_hex = "C"
|
||||
if(13)
|
||||
selected_ui_target_hex = "D"
|
||||
if(14)
|
||||
selected_ui_target_hex = "E"
|
||||
if(15)
|
||||
selected_ui_target_hex = "F"
|
||||
else
|
||||
selected_ui_target = 0
|
||||
selected_ui_target_hex = 0
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["changeUITarget"] && text2num(href_list["changeUITarget"]) < 1)
|
||||
if(selected_ui_target > 0)
|
||||
selected_ui_target--
|
||||
selected_ui_target_hex = selected_ui_target
|
||||
switch(selected_ui_target)
|
||||
if(10)
|
||||
selected_ui_target_hex = "A"
|
||||
if(11)
|
||||
selected_ui_target_hex = "B"
|
||||
if(12)
|
||||
selected_ui_target_hex = "C"
|
||||
if(13)
|
||||
selected_ui_target_hex = "D"
|
||||
if(14)
|
||||
selected_ui_target_hex = "E"
|
||||
else
|
||||
selected_ui_target = 15
|
||||
selected_ui_target_hex = "F"
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["selectUIBlock"] && href_list["selectUISubblock"]) // This chunk of code updates selected block / sub-block based on click
|
||||
var/select_block = text2num(href_list["selectUIBlock"])
|
||||
var/select_subblock = text2num(href_list["selectUISubblock"])
|
||||
if((select_block <= DNA_UI_LENGTH) && (select_block >= 1))
|
||||
selected_ui_block = select_block
|
||||
if((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
|
||||
selected_ui_subblock = select_subblock
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["pulseUIRadiation"])
|
||||
var/block = connected.occupant.dna.GetUISubBlock(selected_ui_block, selected_ui_subblock)
|
||||
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
if(!connected.occupant)
|
||||
return TRUE
|
||||
|
||||
if(prob((80 + (radiation_duration / 2))))
|
||||
var/radiation = (radiation_intensity + radiation_duration)
|
||||
connected.occupant.apply_effect(radiation,IRRADIATE,0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return TRUE
|
||||
|
||||
block = miniscrambletarget(num2text(selected_ui_target), radiation_intensity, radiation_duration)
|
||||
connected.occupant.dna.SetUISubBlock(selected_ui_block, selected_ui_subblock, block)
|
||||
connected.occupant.UpdateAppearance()
|
||||
else
|
||||
var/radiation = ((radiation_intensity * 2) + radiation_duration)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
if(connected.radiation_check())
|
||||
return TRUE
|
||||
|
||||
if(prob(20 + radiation_intensity))
|
||||
randmutb(connected.occupant)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
connected.occupant.UpdateAppearance()
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
if(href_list["injectRejuvenators"])
|
||||
if(!connected.occupant)
|
||||
return FALSE
|
||||
var/inject_amount = round(text2num(href_list["injectRejuvenators"]), 5) // round to nearest 5
|
||||
if(inject_amount < 0) // Since the user can actually type the commands himself, some sanity checking
|
||||
inject_amount = 0
|
||||
if(inject_amount > 50)
|
||||
inject_amount = 50
|
||||
connected.beaker.reagents.trans_to(connected.occupant, inject_amount)
|
||||
connected.beaker.reagents.reaction(connected.occupant)
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
if(href_list["selectSEBlock"] && href_list["selectSESubblock"]) // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes)
|
||||
var/select_block = text2num(href_list["selectSEBlock"])
|
||||
var/select_subblock = text2num(href_list["selectSESubblock"])
|
||||
if((select_block <= DNA_SE_LENGTH) && (select_block >= 1))
|
||||
selected_se_block = select_block
|
||||
if((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
|
||||
selected_se_subblock = select_subblock
|
||||
//testing("User selected block [selected_se_block] (sent [select_block]), subblock [selected_se_subblock] (sent [select_block]).")
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["pulseSERadiation"])
|
||||
var/block = connected.occupant.dna.GetSESubBlock(selected_se_block, selected_se_subblock)
|
||||
//var/original_block=block
|
||||
//testing("Irradiating SE block [selected_se_block]:[selected_se_subblock] ([block])...")
|
||||
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
if(connected.occupant)
|
||||
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
|
||||
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return 1
|
||||
|
||||
var/real_SE_block=selected_se_block
|
||||
block = miniscramble(block, radiation_intensity, radiation_duration)
|
||||
if(prob(20))
|
||||
if(selected_se_block > 1 && selected_se_block < DNA_SE_LENGTH/2)
|
||||
real_SE_block++
|
||||
else if(selected_se_block > DNA_SE_LENGTH/2 && selected_se_block < DNA_SE_LENGTH)
|
||||
real_SE_block--
|
||||
|
||||
//testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
|
||||
connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return 1
|
||||
|
||||
if(prob(80 - radiation_duration))
|
||||
//testing("Random bad mut!")
|
||||
randmutb(connected.occupant)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
//testing("Random identity mut!")
|
||||
connected.occupant.UpdateAppearance()
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["ejectBeaker"])
|
||||
if(connected.beaker)
|
||||
var/obj/item/reagent_containers/glass/B = connected.beaker
|
||||
B.forceMove(connected.loc)
|
||||
connected.beaker = null
|
||||
if(tgui_act_modal(action, params))
|
||||
return TRUE
|
||||
|
||||
if(href_list["ejectOccupant"])
|
||||
connected.eject_occupant(usr)
|
||||
return TRUE
|
||||
|
||||
// Transfer Buffer Management
|
||||
if(href_list["bufferOption"])
|
||||
var/bufferOption = href_list["bufferOption"]
|
||||
|
||||
// These bufferOptions do not require a bufferId
|
||||
if(bufferOption == "wipeDisk")
|
||||
if((isnull(disk)) || (disk.read_only))
|
||||
//temphtml = "Invalid disk. Please try again."
|
||||
return FALSE
|
||||
|
||||
disk.buf = null
|
||||
//temphtml = "Data saved."
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "ejectDisk")
|
||||
if(!disk)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("selectMenuKey")
|
||||
var/key = params["key"]
|
||||
if(!(key in list(PAGE_UI, PAGE_SE, PAGE_BUFFER, PAGE_REJUVENATORS)))
|
||||
return
|
||||
disk.forceMove(get_turf(src))
|
||||
disk = null
|
||||
return TRUE
|
||||
|
||||
// All bufferOptions from here on require a bufferId
|
||||
if(!href_list["bufferId"])
|
||||
return FALSE
|
||||
|
||||
var/bufferId = text2num(href_list["bufferId"])
|
||||
|
||||
if(bufferId < 1 || bufferId > 3)
|
||||
return FALSE // Not a valid buffer id
|
||||
|
||||
if(bufferOption == "saveUI")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_UI // DNA2_BUF_UE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name=connected.occupant.name
|
||||
databuf.name = "Unique Identifier"
|
||||
buffers[bufferId] = databuf
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "saveUIAndUE")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name=connected.occupant.dna.real_name
|
||||
databuf.name = "Unique Identifier + Unique Enzymes"
|
||||
buffers[bufferId] = databuf
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "saveSE")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_SE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name = connected.occupant.dna.real_name
|
||||
databuf.name = "Structural Enzymes"
|
||||
buffers[bufferId] = databuf
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "clear")
|
||||
buffers[bufferId] = new /datum/dna2/record()
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "changeLabel")
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
var/text = sanitize(input(usr, "New Label:", "Edit Label", buf.name) as text|null)
|
||||
buf.name = text
|
||||
buffers[bufferId] = buf
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "transfer")
|
||||
if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna)
|
||||
return TRUE
|
||||
|
||||
irradiating = 2
|
||||
selected_menu_key = key
|
||||
if("toggleLock")
|
||||
if(connected && connected.occupant)
|
||||
connected.locked = !(connected.locked)
|
||||
if("pulseRadiation")
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
sleep(2 SECONDS)
|
||||
SStgui.update_uis(src)
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
var/radiation = (rand(20,50) / connected.damage_coeff)
|
||||
if(!connected.occupant)
|
||||
return
|
||||
|
||||
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return TRUE
|
||||
return
|
||||
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
|
||||
if((buf.types & DNA2_BUF_UI))
|
||||
if((buf.types & DNA2_BUF_UE))
|
||||
connected.occupant.real_name = buf.dna.real_name
|
||||
connected.occupant.name = buf.dna.real_name
|
||||
connected.occupant.UpdateAppearance(buf.dna.UI.Copy())
|
||||
else if(buf.types & DNA2_BUF_SE)
|
||||
connected.occupant.dna.SE = buf.dna.SE.Copy()
|
||||
connected.occupant.dna.UpdateSE()
|
||||
domutcheck(connected.occupant, connected)
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "createInjector")
|
||||
if(injector_ready && !waiting_for_user_input)
|
||||
|
||||
var/success = 1
|
||||
var/obj/item/dnainjector/I = new /obj/item/dnainjector
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
buf = buf.copy()
|
||||
if(href_list["createBlockInjector"])
|
||||
waiting_for_user_input=1
|
||||
var/list/selectedbuf
|
||||
if(buf.types & DNA2_BUF_SE)
|
||||
selectedbuf=buf.dna.SE
|
||||
else
|
||||
selectedbuf=buf.dna.UI
|
||||
var/blk = input(usr,"Select Block","Block") as null|anything in all_dna_blocks(selectedbuf)
|
||||
success = setInjectorBlock(I,blk,buf)
|
||||
if(prob(95))
|
||||
if(prob(75))
|
||||
randmutb(connected.occupant)
|
||||
else
|
||||
I.buf = buf
|
||||
waiting_for_user_input = 0
|
||||
if(success)
|
||||
I.forceMove(loc)
|
||||
I.name += " ([buf.name])"
|
||||
if(connected)
|
||||
I.damage_coeff = connected.damage_coeff
|
||||
injector_ready = FALSE
|
||||
spawn(300)
|
||||
injector_ready = TRUE
|
||||
return TRUE
|
||||
randmuti(connected.occupant)
|
||||
else
|
||||
if(prob(95))
|
||||
randmutg(connected.occupant)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
if("radiationDuration")
|
||||
radiation_duration = clamp(text2num(params["value"]), 1, 20)
|
||||
if("radiationIntensity")
|
||||
radiation_intensity = clamp(text2num(params["value"]), 1, 10)
|
||||
////////////////////////////////////////////////////////
|
||||
if("changeUITarget")
|
||||
selected_ui_target = clamp(text2num(params["value"]), 1, 15)
|
||||
selected_ui_target_hex = num2text(selected_ui_target, 1, 16)
|
||||
if("selectUIBlock") // This chunk of code updates selected block / sub-block based on click
|
||||
var/select_block = text2num(params["block"])
|
||||
var/select_subblock = text2num(params["subblock"])
|
||||
if(!select_block || !select_subblock)
|
||||
return
|
||||
|
||||
if(bufferOption == "loadDisk")
|
||||
if((isnull(disk)) || (!disk.buf))
|
||||
//temphtml = "Invalid disk. Please try again."
|
||||
return FALSE
|
||||
selected_ui_block = clamp(select_block, 1, DNA_UI_LENGTH)
|
||||
selected_ui_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
|
||||
if("pulseUIRadiation")
|
||||
var/block = connected.occupant.dna.GetUISubBlock(selected_ui_block, selected_ui_subblock)
|
||||
|
||||
buffers[bufferId] = disk.buf.copy()
|
||||
//temphtml = "Data loaded."
|
||||
return TRUE
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
|
||||
if(bufferOption == "saveDisk")
|
||||
if((isnull(disk)) || (disk.read_only))
|
||||
//temphtml = "Invalid disk. Please try again."
|
||||
return FALSE
|
||||
SStgui.update_uis(src)
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
disk.buf = buf.copy()
|
||||
disk.name = "data disk - '[buf.dna.real_name]'"
|
||||
//temphtml = "Data saved."
|
||||
return TRUE
|
||||
if(!connected.occupant)
|
||||
return
|
||||
|
||||
if(prob((80 + (radiation_duration / 2))))
|
||||
var/radiation = (radiation_intensity + radiation_duration)
|
||||
connected.occupant.apply_effect(radiation,IRRADIATE,0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return
|
||||
|
||||
block = miniscrambletarget(num2text(selected_ui_target), radiation_intensity, radiation_duration)
|
||||
connected.occupant.dna.SetUISubBlock(selected_ui_block, selected_ui_subblock, block)
|
||||
connected.occupant.UpdateAppearance()
|
||||
else
|
||||
var/radiation = ((radiation_intensity * 2) + radiation_duration)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
if(connected.radiation_check())
|
||||
return
|
||||
|
||||
if(prob(20 + radiation_intensity))
|
||||
randmutb(connected.occupant)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
connected.occupant.UpdateAppearance()
|
||||
////////////////////////////////////////////////////////
|
||||
if("injectRejuvenators")
|
||||
if(!connected.occupant || !connected.beaker)
|
||||
return
|
||||
var/inject_amount = clamp(round(text2num(params["amount"]), 5), 0, 50) // round to nearest 5 and clamp to 0-50
|
||||
if(!inject_amount)
|
||||
return
|
||||
connected.beaker.reagents.trans_to(connected.occupant, inject_amount)
|
||||
connected.beaker.reagents.reaction(connected.occupant)
|
||||
////////////////////////////////////////////////////////
|
||||
if("selectSEBlock") // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes)
|
||||
var/select_block = text2num(params["block"])
|
||||
var/select_subblock = text2num(params["subblock"])
|
||||
if(!select_block || !select_subblock)
|
||||
return
|
||||
|
||||
selected_se_block = clamp(select_block, 1, DNA_SE_LENGTH)
|
||||
selected_se_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
|
||||
if("pulseSERadiation")
|
||||
var/block = connected.occupant.dna.GetSESubBlock(selected_se_block, selected_se_subblock)
|
||||
//var/original_block=block
|
||||
//testing("Irradiating SE block [selected_se_block]:[selected_se_subblock] ([block])...")
|
||||
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
|
||||
SStgui.update_uis(src)
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
if(connected.occupant)
|
||||
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
|
||||
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return 1
|
||||
|
||||
var/real_SE_block=selected_se_block
|
||||
block = miniscramble(block, radiation_intensity, radiation_duration)
|
||||
if(prob(20))
|
||||
if(selected_se_block > 1 && selected_se_block < DNA_SE_LENGTH/2)
|
||||
real_SE_block++
|
||||
else if(selected_se_block > DNA_SE_LENGTH/2 && selected_se_block < DNA_SE_LENGTH)
|
||||
real_SE_block--
|
||||
|
||||
//testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
|
||||
connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return
|
||||
|
||||
if(prob(80 - radiation_duration))
|
||||
//testing("Random bad mut!")
|
||||
randmutb(connected.occupant)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
//testing("Random identity mut!")
|
||||
connected.occupant.UpdateAppearance()
|
||||
if("ejectBeaker")
|
||||
if(connected.beaker)
|
||||
var/obj/item/reagent_containers/glass/B = connected.beaker
|
||||
B.forceMove(connected.loc)
|
||||
connected.beaker = null
|
||||
if("ejectOccupant")
|
||||
connected.eject_occupant()
|
||||
// Transfer Buffer Management
|
||||
if("bufferOption")
|
||||
var/bufferOption = params["option"]
|
||||
var/bufferId = text2num(params["id"])
|
||||
if(bufferId < 1 || bufferId > 3) // Not a valid buffer id
|
||||
return
|
||||
|
||||
var/datum/dna2/record/buffer = buffers[bufferId]
|
||||
switch(bufferOption)
|
||||
if("saveUI")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_UI // DNA2_BUF_UE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name=connected.occupant.name
|
||||
databuf.name = "Unique Identifier"
|
||||
buffers[bufferId] = databuf
|
||||
if("saveUIAndUE")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name=connected.occupant.dna.real_name
|
||||
databuf.name = "Unique Identifier + Unique Enzymes"
|
||||
buffers[bufferId] = databuf
|
||||
if("saveSE")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_SE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name = connected.occupant.dna.real_name
|
||||
databuf.name = "Structural Enzymes"
|
||||
buffers[bufferId] = databuf
|
||||
if("clear")
|
||||
buffers[bufferId] = new /datum/dna2/record()
|
||||
if("changeLabel")
|
||||
tgui_modal_input(src, "changeBufferLabel", "Please enter the new buffer label:", null, list("id" = bufferId), buffer.name, TGUI_MODAL_INPUT_MAX_LENGTH_NAME)
|
||||
if("transfer")
|
||||
if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna)
|
||||
return
|
||||
|
||||
irradiating = 2
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
|
||||
SStgui.update_uis(src)
|
||||
sleep(2 SECONDS)
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
var/radiation = (rand(20,50) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return
|
||||
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
|
||||
if((buf.types & DNA2_BUF_UI))
|
||||
if((buf.types & DNA2_BUF_UE))
|
||||
connected.occupant.real_name = buf.dna.real_name
|
||||
connected.occupant.name = buf.dna.real_name
|
||||
connected.occupant.UpdateAppearance(buf.dna.UI.Copy())
|
||||
else if(buf.types & DNA2_BUF_SE)
|
||||
connected.occupant.dna.SE = buf.dna.SE.Copy()
|
||||
connected.occupant.dna.UpdateSE()
|
||||
domutcheck(connected.occupant, connected)
|
||||
if("createInjector")
|
||||
if(!injector_ready)
|
||||
return
|
||||
if(text2num(params["block"]) > 0)
|
||||
var/list/choices = all_dna_blocks((buffer.types & DNA2_BUF_SE) ? buffer.dna.SE : buffer.dna.UI)
|
||||
tgui_modal_choice(src, "createInjectorBlock", "Please select the block to create an injector from:", null, list("id" = bufferId), null, choices)
|
||||
else
|
||||
create_injector(bufferId, TRUE)
|
||||
if("loadDisk")
|
||||
if(isnull(disk) || disk.read_only)
|
||||
return
|
||||
buffers[bufferId] = disk.buf.copy()
|
||||
if("saveDisk")
|
||||
if(isnull(disk) || disk.read_only)
|
||||
return
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
disk.buf = buf.copy()
|
||||
disk.name = "data disk - '[buf.dna.real_name]'"
|
||||
if("wipeDisk")
|
||||
if(isnull(disk) || disk.read_only)
|
||||
return
|
||||
disk.buf = null
|
||||
if("ejectDisk")
|
||||
if(!disk)
|
||||
return
|
||||
disk.forceMove(get_turf(src))
|
||||
disk = null
|
||||
|
||||
/**
|
||||
* Creates a blank injector with the name of the buffer at the given buffer_id
|
||||
*
|
||||
* Arguments:
|
||||
* * buffer_id - The ID of the buffer
|
||||
* * copy_buffer - Whether the injector should copy the buffer contents
|
||||
*/
|
||||
/obj/machinery/computer/scan_consolenew/proc/create_injector(buffer_id, copy_buffer = FALSE)
|
||||
if(buffer_id < 1 || buffer_id > length(buffers))
|
||||
return
|
||||
|
||||
// Cooldown
|
||||
injector_ready = FALSE
|
||||
addtimer(CALLBACK(src, .proc/injector_cooldown_finish), 30 SECONDS)
|
||||
|
||||
// Create it
|
||||
var/datum/dna2/record/buf = buffers[buffer_id]
|
||||
var/obj/item/dnainjector/I = new()
|
||||
I.forceMove(loc)
|
||||
I.name += " ([buf.name])"
|
||||
if(copy_buffer)
|
||||
I.buf = buf.copy()
|
||||
if(connected)
|
||||
I.damage_coeff = connected.damage_coeff
|
||||
return I
|
||||
|
||||
/**
|
||||
* Called when the injector creation cooldown finishes
|
||||
*/
|
||||
/obj/machinery/computer/scan_consolenew/proc/injector_cooldown_finish()
|
||||
injector_ready = TRUE
|
||||
|
||||
/**
|
||||
* Called in tgui_act() to process modal actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The action passed by tgui
|
||||
* * params - The params passed by tgui
|
||||
*/
|
||||
/obj/machinery/computer/scan_consolenew/proc/tgui_act_modal(action, params)
|
||||
. = TRUE
|
||||
var/id = params["id"] // The modal's ID
|
||||
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
var/answer = params["answer"]
|
||||
switch(id)
|
||||
if("createInjectorBlock")
|
||||
var/buffer_id = text2num(arguments["id"])
|
||||
if(buffer_id < 1 || buffer_id > length(buffers))
|
||||
return
|
||||
var/datum/dna2/record/buf = buffers[buffer_id]
|
||||
var/obj/item/dnainjector/I = create_injector(buffer_id)
|
||||
setInjectorBlock(I, answer, buf.copy())
|
||||
if("changeBufferLabel")
|
||||
var/buffer_id = text2num(arguments["id"])
|
||||
if(buffer_id < 1 || buffer_id > length(buffers))
|
||||
return
|
||||
var/datum/dna2/record/buf = buffers[buffer_id]
|
||||
buf.name = answer
|
||||
buffers[buffer_id] = buf
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
|
||||
#undef PAGE_UI
|
||||
#undef PAGE_SE
|
||||
#undef PAGE_BUFFER
|
||||
#undef PAGE_REJUVENATORS
|
||||
|
||||
/////////////////////////// DNA MACHINES
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/sleeper/attack_ghost(mob/user)
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/sleeper/attack_hand(mob/user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
@@ -135,17 +135,17 @@
|
||||
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/sleeper/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "sleeper.tmpl", "Sleeper", 550, 770)
|
||||
ui = new(user, src, ui_key, "Sleeper", "Sleeper", 550, 775)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/sleeper/ui_data(mob/user, datum/topic_state/state)
|
||||
/obj/machinery/sleeper/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["amounts"] = amounts
|
||||
data["hasOccupant"] = occupant ? 1 : 0
|
||||
var/occupantData[0]
|
||||
var/crisis = 0
|
||||
@@ -210,9 +210,13 @@
|
||||
if(beaker)
|
||||
data["isBeakerLoaded"] = 1
|
||||
if(beaker.reagents)
|
||||
data["beakerMaxSpace"] = beaker.reagents.maximum_volume
|
||||
data["beakerFreeSpace"] = round(beaker.reagents.maximum_volume - beaker.reagents.total_volume)
|
||||
else
|
||||
data["beakerMaxSpace"] = 0
|
||||
data["beakerFreeSpace"] = 0
|
||||
else
|
||||
data["isBeakerLoaded"] = FALSE
|
||||
|
||||
var/chemicals[0]
|
||||
for(var/re in possible_chems)
|
||||
@@ -234,51 +238,52 @@
|
||||
if(temp.id in occupant.reagents.overdose_list())
|
||||
overdosing = 1
|
||||
|
||||
// Because I don't know how to do this on the nano side
|
||||
pretty_amount = round(reagent_amount, 0.05)
|
||||
|
||||
chemicals.Add(list(list("title" = temp.name, "id" = temp.id, "commands" = list("chemical" = temp.id), "occ_amount" = reagent_amount, "pretty_amount" = pretty_amount, "injectable" = injectable, "overdosing" = overdosing, "od_warning" = caution)))
|
||||
data["chemicals"] = chemicals
|
||||
return data
|
||||
|
||||
/obj/machinery/sleeper/Topic(href, href_list)
|
||||
if(!controls_inside && usr == occupant)
|
||||
return 0
|
||||
|
||||
/obj/machinery/sleeper/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
return
|
||||
if(!controls_inside && usr == occupant)
|
||||
return
|
||||
if(panel_open)
|
||||
to_chat(usr, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return 0
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon/ai)))
|
||||
if(href_list["chemical"])
|
||||
if(occupant)
|
||||
if(occupant.stat == DEAD)
|
||||
to_chat(usr, "<span class='danger'>This person has no life for to preserve anymore. Take [occupant.p_them()] to a department capable of reanimating them.</span>")
|
||||
else if(occupant.health > min_health || (href_list["chemical"] in emergency_chems))
|
||||
inject_chemical(usr,href_list["chemical"],text2num(href_list["amount"]))
|
||||
else
|
||||
to_chat(usr, "<span class='danger'>This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!</span>")
|
||||
|
||||
if(href_list["removebeaker"])
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("chemical")
|
||||
if(!occupant)
|
||||
return
|
||||
if(occupant.stat == DEAD)
|
||||
to_chat(usr, "<span class='danger'>This person has no life to preserve anymore. Take [occupant.p_them()] to a department capable of reanimating them.</span>")
|
||||
return
|
||||
var/chemical = params["chemid"]
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!length(chemical) || amount <= 0)
|
||||
return
|
||||
if(occupant.health > min_health || (chemical in emergency_chems))
|
||||
inject_chemical(usr, chemical, amount)
|
||||
else
|
||||
to_chat(usr, "<span class='danger'>This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!</span>")
|
||||
if("removebeaker")
|
||||
remove_beaker()
|
||||
|
||||
if(href_list["togglefilter"])
|
||||
if("togglefilter")
|
||||
toggle_filter()
|
||||
|
||||
if(href_list["ejectify"])
|
||||
if("ejectify")
|
||||
eject()
|
||||
|
||||
if(href_list["auto_eject_dead_on"])
|
||||
if("auto_eject_dead_on")
|
||||
auto_eject_dead = TRUE
|
||||
|
||||
if(href_list["auto_eject_dead_off"])
|
||||
if("auto_eject_dead_off")
|
||||
auto_eject_dead = FALSE
|
||||
|
||||
add_fingerprint(usr)
|
||||
return 1
|
||||
else
|
||||
return FALSE
|
||||
add_fingerprint(usr)
|
||||
|
||||
/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/reagent_containers/glass))
|
||||
@@ -290,6 +295,7 @@
|
||||
beaker = I
|
||||
I.forceMove(src)
|
||||
user.visible_message("[user] adds \a [I] to [src]!", "You add \a [I] to [src]!")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
else
|
||||
@@ -328,6 +334,7 @@
|
||||
to_chat(M, "<span class='boldnotice'>You feel cool air surround you. You go numb as your senses turn inward.</span>")
|
||||
add_fingerprint(user)
|
||||
qdel(G)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
return ..()
|
||||
@@ -374,9 +381,11 @@
|
||||
occupant = null
|
||||
updateUsrDialog()
|
||||
update_icon()
|
||||
SStgui.update_uis(src)
|
||||
if(A == beaker)
|
||||
beaker = null
|
||||
updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/sleeper/emp_act(severity)
|
||||
if(filtering)
|
||||
@@ -394,7 +403,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/sleeper/proc/toggle_filter()
|
||||
if(filtering)
|
||||
if(filtering || !beaker)
|
||||
filtering = 0
|
||||
else
|
||||
filtering = 1
|
||||
@@ -410,29 +419,28 @@
|
||||
// eject trash the occupant dropped
|
||||
for(var/atom/movable/A in contents - component_parts - list(beaker))
|
||||
A.forceMove(loc)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/sleeper/force_eject_occupant()
|
||||
go_out()
|
||||
|
||||
/obj/machinery/sleeper/proc/inject_chemical(mob/living/user as mob, chemical, amount)
|
||||
/obj/machinery/sleeper/proc/inject_chemical(mob/living/user, chemical, amount)
|
||||
if(!(chemical in possible_chems))
|
||||
to_chat(user, "<span class='notice'>The sleeper does not offer that chemical!</span>")
|
||||
return
|
||||
if(!(amount in amounts))
|
||||
return
|
||||
|
||||
if(occupant)
|
||||
if(occupant.reagents)
|
||||
if(occupant.reagents.get_reagent_amount(chemical) + amount <= max_chem)
|
||||
occupant.reagents.add_reagent(chemical, amount)
|
||||
return
|
||||
else
|
||||
to_chat(user, "You can not inject any more of this chemical.")
|
||||
return
|
||||
else
|
||||
to_chat(user, "The patient rejects the chemicals!")
|
||||
return
|
||||
else
|
||||
to_chat(user, "There's no occupant in the sleeper!")
|
||||
return
|
||||
|
||||
/obj/machinery/sleeper/verb/eject()
|
||||
set name = "Eject Sleeper"
|
||||
@@ -459,6 +467,7 @@
|
||||
filtering = 0
|
||||
beaker.forceMove(usr.loc)
|
||||
beaker = null
|
||||
SStgui.update_uis(src)
|
||||
add_fingerprint(usr)
|
||||
return
|
||||
|
||||
@@ -511,6 +520,7 @@
|
||||
add_fingerprint(user)
|
||||
if(user.pulling == L)
|
||||
user.stop_pulling()
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -547,6 +557,7 @@
|
||||
for(var/obj/O in src)
|
||||
qdel(O)
|
||||
add_fingerprint(usr)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
icon_state = "body_scanner_1"
|
||||
add_fingerprint(user)
|
||||
qdel(TYPECAST_YOUR_SHIT)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
return ..()
|
||||
@@ -127,12 +128,13 @@
|
||||
occupant = H
|
||||
icon_state = "bodyscanner"
|
||||
add_fingerprint(user)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/bodyscanner/attack_ai(user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/bodyscanner/attack_ghost(user)
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/bodyscanner/attack_hand(user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
@@ -145,7 +147,7 @@
|
||||
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/bodyscanner/relaymove(mob/user)
|
||||
if(user.incapacitated())
|
||||
@@ -171,6 +173,7 @@
|
||||
// eject trash the occupant dropped
|
||||
for(var/atom/movable/A in contents - component_parts)
|
||||
A.forceMove(loc)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/bodyscanner/force_eject_occupant()
|
||||
go_out()
|
||||
@@ -192,17 +195,16 @@
|
||||
new /obj/effect/gibspawner/generic(get_turf(loc)) //I REPLACE YOUR TECHNOLOGY WITH FLESH!
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/bodyscanner/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/bodyscanner/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "adv_med.tmpl", "Body Scanner", 690, 600)
|
||||
ui = new(user, src, ui_key, "BodyScanner", "Body Scanner", 690, 600)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/bodyscanner/ui_data(mob/user, datum/topic_state/state)
|
||||
/obj/machinery/bodyscanner/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["occupied"] = occupant ? 1 : 0
|
||||
data["occupied"] = occupant ? TRUE : FALSE
|
||||
|
||||
var/occupantData[0]
|
||||
if(occupant)
|
||||
@@ -236,9 +238,9 @@
|
||||
occupantData["hasBorer"] = occupant.has_brain_worms()
|
||||
|
||||
var/bloodData[0]
|
||||
bloodData["hasBlood"] = 0
|
||||
bloodData["hasBlood"] = FALSE
|
||||
if(!(NO_BLOOD in occupant.dna.species.species_traits))
|
||||
bloodData["hasBlood"] = 1
|
||||
bloodData["hasBlood"] = TRUE
|
||||
bloodData["volume"] = occupant.blood_volume
|
||||
bloodData["percent"] = round(((occupant.blood_volume / BLOOD_VOLUME_NORMAL)*100))
|
||||
bloodData["pulse"] = occupant.get_pulse(GETPULSE_TOOL)
|
||||
@@ -282,19 +284,19 @@
|
||||
if(E.status & ORGAN_BROKEN)
|
||||
organStatus["broken"] = E.broken_description
|
||||
if(E.is_robotic())
|
||||
organStatus["robotic"] = 1
|
||||
organStatus["robotic"] = TRUE
|
||||
if(E.status & ORGAN_SPLINTED)
|
||||
organStatus["splinted"] = 1
|
||||
organStatus["splinted"] = TRUE
|
||||
if(E.status & ORGAN_DEAD)
|
||||
organStatus["dead"] = 1
|
||||
organStatus["dead"] = TRUE
|
||||
|
||||
organData["status"] = organStatus
|
||||
|
||||
if(istype(E, /obj/item/organ/external/chest) && occupant.is_lung_ruptured())
|
||||
organData["lungRuptured"] = 1
|
||||
organData["lungRuptured"] = TRUE
|
||||
|
||||
if(E.internal_bleeding)
|
||||
organData["internalBleeding"] = 1
|
||||
organData["internalBleeding"] = TRUE
|
||||
|
||||
extOrganData.Add(list(organData))
|
||||
|
||||
@@ -319,27 +321,33 @@
|
||||
|
||||
occupantData["blind"] = (BLINDNESS in occupant.mutations)
|
||||
occupantData["colourblind"] = (COLOURBLIND in occupant.mutations)
|
||||
occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations)
|
||||
occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations)
|
||||
|
||||
data["occupant"] = occupantData
|
||||
return data
|
||||
|
||||
/obj/machinery/bodyscanner/Topic(href, href_list)
|
||||
/obj/machinery/bodyscanner/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(href_list["ejectify"])
|
||||
eject()
|
||||
|
||||
if(href_list["print_p"])
|
||||
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
|
||||
P.info = "<CENTER><B>Body Scan - [href_list["name"]]</B></CENTER><BR>"
|
||||
P.info += "<b>Time of scan:</b> [station_time_timestamp()]<br><br>"
|
||||
P.info += "[generate_printing_text()]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Body Scan - [href_list["name"]]"
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("ejectify")
|
||||
eject()
|
||||
if("print_p")
|
||||
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
|
||||
var/name = occupant ? occupant.name : "Unknown"
|
||||
P.info = "<CENTER><B>Body Scan - [name]</B></CENTER><BR>"
|
||||
P.info += "<b>Time of scan:</b> [station_time_timestamp()]<br><br>"
|
||||
P.info += "[generate_printing_text()]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Body Scan - [name]"
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/bodyscanner/proc/generate_printing_text()
|
||||
var/dat = ""
|
||||
|
||||
@@ -40,8 +40,7 @@
|
||||
add_fingerprint(user)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/operating/attack_hand(mob/user)
|
||||
if(..(user))
|
||||
@@ -52,16 +51,15 @@
|
||||
|
||||
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)//ui is mostly copy pasta from the sleeper ui
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/computer/operating/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "op_computer.tmpl", "Patient Monitor", 650, 455)
|
||||
ui = new(user, src, ui_key, "OperatingComputer", "Patient Monitor", 650, 455, master_ui, state)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/operating/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/computer/operating/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
var/mob/living/carbon/human/occupant
|
||||
if(table)
|
||||
@@ -136,38 +134,43 @@
|
||||
return data
|
||||
|
||||
|
||||
/obj/machinery/computer/operating/Topic(href, href_list)
|
||||
/obj/machinery/computer/operating/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["verboseOn"])
|
||||
verbose=1
|
||||
if(href_list["verboseOff"])
|
||||
verbose=0
|
||||
if(href_list["healthOn"])
|
||||
healthAnnounce=1
|
||||
if(href_list["healthOff"])
|
||||
healthAnnounce=0
|
||||
if(href_list["critOn"])
|
||||
crit=1
|
||||
if(href_list["critOff"])
|
||||
crit=0
|
||||
if(href_list["oxyOn"])
|
||||
oxy=1
|
||||
if(href_list["oxyOff"])
|
||||
oxy=0
|
||||
if(href_list["oxy_adj"]!=0)
|
||||
oxyAlarm=oxyAlarm+text2num(href_list["oxy_adj"])
|
||||
if(href_list["choiceOn"])
|
||||
choice=1
|
||||
if(href_list["choiceOff"])
|
||||
choice=0
|
||||
if(href_list["health_adj"]!=0)
|
||||
healthAlarm=healthAlarm+text2num(href_list["health_adj"])
|
||||
return
|
||||
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("verboseOn")
|
||||
verbose = TRUE
|
||||
if("verboseOff")
|
||||
verbose = FALSE
|
||||
if("healthOn")
|
||||
healthAnnounce = TRUE
|
||||
if("healthOff")
|
||||
healthAnnounce = FALSE
|
||||
if("critOn")
|
||||
crit = TRUE
|
||||
if("critOff")
|
||||
crit = FALSE
|
||||
if("oxyOn")
|
||||
oxy = TRUE
|
||||
if("oxyOff")
|
||||
oxy = FALSE
|
||||
if("oxy_adj")
|
||||
oxyAlarm = clamp(text2num(params["new"]), -100, 100)
|
||||
if("choiceOn")
|
||||
choice = TRUE
|
||||
if("choiceOff")
|
||||
choice = FALSE
|
||||
if("health_adj")
|
||||
healthAlarm = clamp(text2num(params["new"]), -100, 100)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/operating/process()
|
||||
|
||||
@@ -178,6 +181,7 @@
|
||||
atom_say("New patient detected, loading stats")
|
||||
victim = table.victim
|
||||
atom_say("[victim.real_name], [victim.dna.blood_type] blood, [victim.stat ? "Non-Responsive" : "Awake"]")
|
||||
SStgui.update_uis(src)
|
||||
if(nextTick < world.time)
|
||||
nextTick=world.time + OP_COMPUTER_COOLDOWN
|
||||
if(crit && victim.health <= -50 )
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#define MENU_MAIN 1
|
||||
#define MENU_RECORDS 2
|
||||
|
||||
/obj/machinery/computer/cloning
|
||||
name = "cloning console"
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
@@ -6,11 +9,11 @@
|
||||
circuit = /obj/item/circuitboard/cloning
|
||||
req_access = list(ACCESS_HEADS) //Only used for record deletion right now.
|
||||
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
|
||||
var/list/pods = list() //Linked cloning pods.
|
||||
var/temp = ""
|
||||
var/scantemp = "Scanner ready."
|
||||
var/menu = 1 //Which menu screen to display
|
||||
var/list/records = list()
|
||||
var/list/pods = null //Linked cloning pods.
|
||||
var/list/temp = null
|
||||
var/list/scantemp = null
|
||||
var/menu = MENU_MAIN //Which menu screen to display
|
||||
var/list/records = null
|
||||
var/datum/dna2/record/active_record = null
|
||||
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
|
||||
var/loading = 0 // Nice loading text
|
||||
@@ -24,6 +27,9 @@
|
||||
|
||||
/obj/machinery/computer/cloning/Initialize()
|
||||
..()
|
||||
pods = list()
|
||||
records = list()
|
||||
set_scan_temp("Scanner ready.", "good")
|
||||
updatemodules()
|
||||
|
||||
/obj/machinery/computer/cloning/Destroy()
|
||||
@@ -91,7 +97,7 @@
|
||||
W.loc = src
|
||||
src.diskette = W
|
||||
to_chat(user, "You insert [W].")
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
else if(istype(W, /obj/item/multitool))
|
||||
var/obj/item/multitool/M = W
|
||||
@@ -117,19 +123,21 @@
|
||||
return
|
||||
|
||||
updatemodules()
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/cloning/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
/obj/machinery/computer/cloning/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
// Set up the Nano UI
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
var/datum/asset/cloning/assets = get_asset_datum(/datum/asset/cloning)
|
||||
assets.send(user)
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "cloning_console.tmpl", "Cloning Console UI", 640, 520)
|
||||
ui = new(user, src, ui_key, "CloningConsole", "Cloning Console", 640, 520)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/cloning/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/computer/cloning/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["menu"] = src.menu
|
||||
data["scanner"] = sanitize("[src.scanner]")
|
||||
@@ -143,7 +151,18 @@
|
||||
if(pod.efficiency > 5)
|
||||
canpodautoprocess = 1
|
||||
|
||||
tempods.Add(list(list("pod" = "\ref[pod]", "name" = sanitize(capitalize(pod.name)), "biomass" = pod.biomass)))
|
||||
var/status = "idle"
|
||||
if(pod.mess)
|
||||
status = "mess"
|
||||
else if(pod.occupant && !(pod.stat & NOPOWER))
|
||||
status = "cloning"
|
||||
tempods.Add(list(list(
|
||||
"pod" = "\ref[pod]",
|
||||
"name" = sanitize(capitalize(pod.name)),
|
||||
"biomass" = pod.biomass,
|
||||
"status" = status,
|
||||
"progress" = (pod.occupant && pod.occupant.stat != DEAD) ? pod.get_completion() : 0
|
||||
)))
|
||||
data["pods"] = tempods
|
||||
|
||||
data["loading"] = loading
|
||||
@@ -168,188 +187,190 @@
|
||||
temprecords.Add(list(list("record" = "\ref[R]", "realname" = sanitize(tempRealName))))
|
||||
data["records"] = temprecords
|
||||
|
||||
if(src.menu == 3)
|
||||
if(src.active_record)
|
||||
data["activerecord"] = "\ref[src.active_record]"
|
||||
var/obj/item/implant/health/H = null
|
||||
if(src.active_record.implant)
|
||||
H = locate(src.active_record.implant)
|
||||
if(selected_pod && (selected_pod in pods) && selected_pod.biomass >= CLONE_BIOMASS)
|
||||
data["podready"] = 1
|
||||
else
|
||||
data["podready"] = 0
|
||||
|
||||
if((H) && (istype(H)))
|
||||
data["health"] = H.sensehealth()
|
||||
data["realname"] = sanitize(src.active_record.dna.real_name)
|
||||
data["unidentity"] = src.active_record.dna.uni_identity
|
||||
data["strucenzymes"] = src.active_record.dna.struc_enzymes
|
||||
if(selected_pod && (selected_pod in pods) && selected_pod.biomass >= CLONE_BIOMASS)
|
||||
data["podready"] = 1
|
||||
else
|
||||
data["podready"] = 0
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/cloning/Topic(href, href_list)
|
||||
/obj/machinery/computer/cloning/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(loading)
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(href_list["scan"] && scanner && scanner.occupant)
|
||||
scantemp = "Scanner ready."
|
||||
|
||||
loading = 1
|
||||
|
||||
spawn(20)
|
||||
if(can_brainscan() && scan_mode)
|
||||
scan_mob(scanner.occupant, scan_brain = 1)
|
||||
else
|
||||
scan_mob(scanner.occupant)
|
||||
|
||||
loading = 0
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
if(href_list["task"])
|
||||
switch(href_list["task"])
|
||||
if("autoprocess")
|
||||
autoprocess = 1
|
||||
SSnanoui.update_uis(src)
|
||||
if("stopautoprocess")
|
||||
autoprocess = 0
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
//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"])
|
||||
if(istype(src.active_record,/datum/dna2/record))
|
||||
if((isnull(src.active_record.ckey)))
|
||||
qdel(src.active_record)
|
||||
src.temp = "<span class=\"bad\">Error: Record corrupt.</span>"
|
||||
else
|
||||
src.menu = 3
|
||||
else
|
||||
src.active_record = null
|
||||
src.temp = "<span class=\"bad\">Error: Record missing.</span>"
|
||||
|
||||
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 = "Please confirm that you want to delete the record?"
|
||||
src.menu = 4
|
||||
|
||||
else if(src.menu == 4)
|
||||
var/obj/item/card/id/C = usr.get_active_hand()
|
||||
if(istype(C)||istype(C, /obj/item/pda))
|
||||
if(src.check_access(C))
|
||||
src.records.Remove(src.active_record)
|
||||
qdel(src.active_record)
|
||||
src.temp = "Record deleted."
|
||||
src.menu = 2
|
||||
. = TRUE
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
if(params["id"] == "del_rec" && active_record)
|
||||
var/obj/item/card/id/C = usr.get_active_hand()
|
||||
if(!istype(C) && !istype(C, /obj/item/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
|
||||
src.temp = "<span class=\"bad\">Error: Access denied.</span>"
|
||||
|
||||
else if(href_list["disk"]) //Load or eject.
|
||||
switch(href_list["disk"])
|
||||
if("load")
|
||||
if((isnull(src.diskette)) || isnull(src.diskette.buf))
|
||||
src.temp = "<span class=\"bad\">Error: The disk's data could not be read.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
if(isnull(src.active_record))
|
||||
src.temp = "<span class=\"bad\">Error: No active record was found.</span>"
|
||||
src.menu = 1
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
|
||||
src.active_record = src.diskette.buf.copy()
|
||||
|
||||
src.temp = "Load successful."
|
||||
|
||||
if("eject")
|
||||
if(!isnull(src.diskette))
|
||||
src.diskette.loc = src.loc
|
||||
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 = "<span class=\"bad\">Error: The data could not be saved.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_temp("Access denied.", "danger")
|
||||
return
|
||||
|
||||
// DNA2 makes things a little simpler.
|
||||
src.diskette.buf=src.active_record.copy()
|
||||
src.diskette.buf.types=0
|
||||
switch(href_list["save_disk"]) //Save as Ui/Ui+Ue/Se
|
||||
if("ui")
|
||||
src.diskette.buf.types=DNA2_BUF_UI
|
||||
if("ue")
|
||||
src.diskette.buf.types=DNA2_BUF_UI|DNA2_BUF_UE
|
||||
if("se")
|
||||
src.diskette.buf.types=DNA2_BUF_SE
|
||||
src.diskette.name = "data disk - '[src.active_record.dna.real_name]'"
|
||||
src.temp = "Save \[[href_list["save_disk"]]\] successful."
|
||||
switch(action)
|
||||
if("scan")
|
||||
if(!scanner || !scanner.occupant || loading)
|
||||
return
|
||||
set_scan_temp("Scanner ready.", "good")
|
||||
loading = TRUE
|
||||
|
||||
else if(href_list["refresh"])
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["selectpod"])
|
||||
var/obj/machinery/clonepod/selected = locate(href_list["selectpod"])
|
||||
if(istype(selected) && (selected in pods))
|
||||
selected_pod = selected
|
||||
|
||||
else if(href_list["clone"])
|
||||
var/datum/dna2/record/C = locate(href_list["clone"])
|
||||
//Look for that player! They better be dead!
|
||||
if(istype(C))
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!pods.len)
|
||||
temp = "<span class=\"bad\">Error: No cloning pod detected.</span>"
|
||||
else
|
||||
var/obj/machinery/clonepod/pod = selected_pod
|
||||
var/cloneresult
|
||||
if(!selected_pod)
|
||||
temp = "<span class=\"bad\">Error: No cloning pod selected.</span>"
|
||||
else if(pod.occupant)
|
||||
temp = "<span class=\"bad\">Error: The cloning pod is currently occupied.</span>"
|
||||
else if(pod.biomass < CLONE_BIOMASS)
|
||||
temp = "<span class=\"bad\">Error: Not enough biomass.</span>"
|
||||
else if(pod.mess)
|
||||
temp = "<span class=\"bad\">Error: The cloning pod is malfunctioning.</span>"
|
||||
else if(!config.revival_cloning)
|
||||
temp = "<span class=\"bad\">Error: Unable to initiate cloning cycle.</span>"
|
||||
spawn(20)
|
||||
if(can_brainscan() && scan_mode)
|
||||
scan_mob(scanner.occupant, scan_brain = TRUE)
|
||||
else
|
||||
cloneresult = pod.growclone(C)
|
||||
if(cloneresult)
|
||||
if(cloneresult > 0)
|
||||
temp = "Initiating cloning cycle..."
|
||||
records.Remove(C)
|
||||
qdel(C)
|
||||
menu = 1
|
||||
scan_mob(scanner.occupant)
|
||||
loading = FALSE
|
||||
SStgui.update_uis(src)
|
||||
if("autoprocess")
|
||||
autoprocess = text2num(params["on"]) > 0
|
||||
if("lock")
|
||||
if(isnull(scanner) || !scanner.occupant) //No locking an open scanner.
|
||||
return
|
||||
scanner.locked = !scanner.locked
|
||||
if("view_rec")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
active_record = locate(ref)
|
||||
if(istype(active_record))
|
||||
if(isnull(active_record.ckey))
|
||||
qdel(active_record)
|
||||
set_temp("Error: Record corrupt.", "danger")
|
||||
else
|
||||
var/obj/item/implant/health/H = null
|
||||
if(active_record.implant)
|
||||
H = locate(active_record.implant)
|
||||
var/list/payload = list(
|
||||
activerecord = "\ref[active_record]",
|
||||
health = (H && istype(H)) ? H.sensehealth() : "",
|
||||
realname = sanitize(active_record.dna.real_name),
|
||||
unidentity = active_record.dna.uni_identity,
|
||||
strucenzymes = active_record.dna.struc_enzymes,
|
||||
)
|
||||
tgui_modal_message(src, action, "", null, payload)
|
||||
else
|
||||
active_record = null
|
||||
set_temp("Error: Record missing.", "danger")
|
||||
if("del_rec")
|
||||
if(!active_record)
|
||||
return
|
||||
tgui_modal_boolean(src, action, "Please confirm that you want to delete the record by holding your ID and pressing Delete:", yes_text = "Delete", no_text = "Cancel")
|
||||
if("disk") // Disk management.
|
||||
if(!length(params["option"]))
|
||||
return
|
||||
switch(params["option"])
|
||||
if("load")
|
||||
if(isnull(diskette) || isnull(diskette.buf))
|
||||
set_temp("Error: The disk's data could not be read.", "danger")
|
||||
return
|
||||
else if(isnull(active_record))
|
||||
set_temp("Error: No active record was found.", "danger")
|
||||
menu = MENU_MAIN
|
||||
return
|
||||
|
||||
active_record = diskette.buf.copy()
|
||||
set_temp("Successfully loaded from disk.", "success")
|
||||
if("save")
|
||||
if(isnull(diskette) || diskette.read_only || isnull(active_record))
|
||||
set_temp("Error: The data could not be saved.", "danger")
|
||||
return
|
||||
|
||||
// DNA2 makes things a little simpler.
|
||||
var/types
|
||||
switch(params["savetype"]) // Save as Ui/Ui+Ue/Se
|
||||
if("ui")
|
||||
types = DNA2_BUF_UI
|
||||
if("ue")
|
||||
types = DNA2_BUF_UI|DNA2_BUF_UE
|
||||
if("se")
|
||||
types = DNA2_BUF_SE
|
||||
else
|
||||
set_temp("Error: Invalid save format.", "danger")
|
||||
return
|
||||
diskette.buf = active_record.copy()
|
||||
diskette.buf.types = types
|
||||
diskette.name = "data disk - '[active_record.dna.real_name]'"
|
||||
set_temp("Successfully saved to disk.", "success")
|
||||
if("eject")
|
||||
if(!isnull(diskette))
|
||||
diskette.loc = loc
|
||||
diskette = null
|
||||
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("clone")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
var/datum/dna2/record/C = locate(ref)
|
||||
//Look for that player! They better be dead!
|
||||
if(istype(C))
|
||||
tgui_modal_clear(src)
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!length(pods))
|
||||
set_temp("Error: No cloning pod detected.", "danger")
|
||||
else
|
||||
var/obj/machinery/clonepod/pod = selected_pod
|
||||
var/cloneresult
|
||||
if(!selected_pod)
|
||||
set_temp("Error: No cloning pod selected.", "danger")
|
||||
else if(pod.occupant)
|
||||
set_temp("Error: The cloning pod is currently occupied.", "danger")
|
||||
else if(pod.biomass < CLONE_BIOMASS)
|
||||
set_temp("Error: Not enough biomass.", "danger")
|
||||
else if(pod.mess)
|
||||
set_temp("Error: The cloning pod is malfunctioning.", "danger")
|
||||
else if(!config.revival_cloning)
|
||||
set_temp("Error: Unable to initiate cloning cycle.", "danger")
|
||||
else
|
||||
temp = "[C.name] => <font class='bad'>Initialisation failure.</font>"
|
||||
|
||||
cloneresult = pod.growclone(C)
|
||||
if(cloneresult)
|
||||
set_temp("Initiating cloning cycle...", "success")
|
||||
records.Remove(C)
|
||||
qdel(C)
|
||||
menu = MENU_MAIN
|
||||
else
|
||||
set_temp("Error: Initialisation failure.", "danger")
|
||||
else
|
||||
set_temp("Error: Data corruption.", "danger")
|
||||
if("menu")
|
||||
menu = clamp(text2num(params["num"]), MENU_MAIN, MENU_RECORDS)
|
||||
if("toggle_mode")
|
||||
if(loading)
|
||||
return
|
||||
if(can_brainscan())
|
||||
scan_mode = !scan_mode
|
||||
else
|
||||
scan_mode = FALSE
|
||||
if("eject")
|
||||
if(usr.incapacitated() || !scanner || loading)
|
||||
return
|
||||
scanner.eject_occupant(usr)
|
||||
scanner.add_fingerprint(usr)
|
||||
if("cleartemp")
|
||||
temp = null
|
||||
else
|
||||
temp = "<span class=\"bad\">Error: Data corruption.</span>"
|
||||
|
||||
else if(href_list["menu"])
|
||||
src.menu = text2num(href_list["menu"])
|
||||
temp = ""
|
||||
scantemp = "Scanner ready."
|
||||
else if(href_list["toggle_mode"])
|
||||
if(can_brainscan())
|
||||
scan_mode = !scan_mode
|
||||
else
|
||||
scan_mode = 0
|
||||
return FALSE
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
|
||||
/obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject as mob, var/scan_brain = 0)
|
||||
if(stat & NOPOWER)
|
||||
@@ -360,46 +381,46 @@
|
||||
return
|
||||
if(isnull(subject) || (!(ishuman(subject))) || (!subject.dna))
|
||||
if(isalien(subject))
|
||||
scantemp = "<span class=\"bad\">Error: Xenomorphs are not scannable.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Xenomorphs are not scannable.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
// can add more conditions for specific non-human messages here
|
||||
else
|
||||
scantemp = "<span class=\"bad\">Error: Subject species is not scannable.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject species is not scannable.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if(subject.get_int_organ(/obj/item/organ/internal/brain))
|
||||
var/obj/item/organ/internal/brain/Brn = subject.get_int_organ(/obj/item/organ/internal/brain)
|
||||
if(istype(Brn))
|
||||
if(NO_SCAN in Brn.dna.species.species_traits)
|
||||
scantemp = "<span class=\"bad\">Error: [Brn.dna.species.name_plural] are not scannable.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("[Brn.dna.species.name_plural] are not scannable.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if(!subject.get_int_organ(/obj/item/organ/internal/brain))
|
||||
scantemp = "<span class=\"bad\">Error: No brain detected in subject.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("No brain detected in subject.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if(subject.suiciding)
|
||||
scantemp = "<span class=\"bad\">Error: Subject has committed suicide and is not scannable.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject has committed suicide and is not scannable.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if((!subject.ckey) || (!subject.client))
|
||||
scantemp = "<span class=\"bad\">Error: Subject's brain is not responding. Further attempts after a short delay may succeed.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject's brain is not responding. Further attempts after a short delay may succeed.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if((NOCLONE in subject.mutations) && src.scanner.scan_level < 2)
|
||||
scantemp = "<span class=\"bad\">Error: Subject has incompatible genetic mutations.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject has incompatible genetic mutations.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if(!isnull(find_record(subject.ckey)))
|
||||
scantemp = "Subject already in database."
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject already in database.")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
for(var/obj/machinery/clonepod/pod in pods)
|
||||
if(pod.occupant && pod.clonemind == subject.mind)
|
||||
scantemp = "Subject already getting cloned."
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject already getting cloned.")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
subject.dna.check_integrity()
|
||||
@@ -434,8 +455,8 @@
|
||||
R.mind = "\ref[subject.mind]"
|
||||
|
||||
src.records += R
|
||||
scantemp = "Subject successfully scanned. " + extra_info
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject successfully scanned. [extra_info]", "good")
|
||||
SStgui.update_uis(src)
|
||||
|
||||
//Find a specific record by key.
|
||||
/obj/machinery/computer/cloning/proc/find_record(var/find_key)
|
||||
@@ -451,3 +472,30 @@
|
||||
|
||||
/obj/machinery/computer/cloning/proc/can_brainscan()
|
||||
return (scanner && scanner.scan_level > 3)
|
||||
|
||||
/**
|
||||
* 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/cloning/proc/set_temp(text = "", style = "info", update_now = FALSE)
|
||||
temp = list(text = text, style = style)
|
||||
if(update_now)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Sets a temporary scan message to display to the user
|
||||
*
|
||||
* Arguments:
|
||||
* * text - Text to display, null/empty to clear the message from the UI
|
||||
* * color - The color of the message: (color name)
|
||||
*/
|
||||
/obj/machinery/computer/cloning/proc/set_scan_temp(text = "", color = "", update_now = FALSE)
|
||||
scantemp = list(text = text, color = color)
|
||||
if(update_now)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
#undef MENU_MAIN
|
||||
#undef MENU_RECORDS
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#define MED_DATA_MAIN 1 // Main menu
|
||||
#define MED_DATA_R_LIST 2 // Record list
|
||||
#define MED_DATA_MAINT 3 // Records maintenance
|
||||
#define MED_DATA_RECORD 4 // Record
|
||||
#define MED_DATA_V_DATA 5 // Virus database
|
||||
#define MED_DATA_MEDBOT 6 // Medbot monitor
|
||||
|
||||
#define FIELD(N, V, E) list(field = N, value = V, edit = E)
|
||||
#define MED_FIELD(N, V, E, LB) list(field = N, value = V, edit = E, line_break = LB)
|
||||
|
||||
/obj/machinery/computer/med_data //TODO:SANITY
|
||||
name = "medical records console"
|
||||
desc = "This can be used to check medical records."
|
||||
@@ -18,11 +20,45 @@
|
||||
var/screen = null
|
||||
var/datum/data/record/active1 = null
|
||||
var/datum/data/record/active2 = null
|
||||
var/temp = null
|
||||
var/list/temp = null
|
||||
var/printing = null
|
||||
// The below are used to make modal generation more convenient
|
||||
var/static/list/field_edit_questions
|
||||
var/static/list/field_edit_choices
|
||||
|
||||
light_color = LIGHT_COLOR_DARKBLUE
|
||||
|
||||
/obj/machinery/computer/med_data/Initialize()
|
||||
..()
|
||||
field_edit_questions = list(
|
||||
// General
|
||||
"sex" = "Please select new sex:",
|
||||
"age" = "Please input new age:",
|
||||
"fingerprint" = "Please input new fingerprint hash:",
|
||||
"p_stat" = "Please select new physical status:",
|
||||
"m_stat" = "Please select new mental status:",
|
||||
// Medical
|
||||
"blood_type" = "Please select new blood type:",
|
||||
"b_dna" = "Please input new DNA:",
|
||||
"mi_dis" = "Please input new minor disabilities:",
|
||||
"mi_dis_d" = "Please summarize minor disabilities:",
|
||||
"ma_dis" = "Please input new major disabilities:",
|
||||
"ma_dis_d" = "Please summarize major disabilities:",
|
||||
"alg" = "Please input new allergies:",
|
||||
"alg_d" = "Please summarize allergies:",
|
||||
"cdi" = "Please input new current diseases:",
|
||||
"cdi_d" = "Please summarize current diseases:",
|
||||
"notes" = "Please input new important notes:",
|
||||
)
|
||||
field_edit_choices = list(
|
||||
// General
|
||||
"sex" = list("Male", "Female"),
|
||||
"p_stat" = list("*Deceased*", "*SSD*", "Active", "Physically Unfit", "Disabled"),
|
||||
"m_stat" = list("*Insane*", "*Unstable*", "*Watch*", "Stable"),
|
||||
// Medical
|
||||
"blood_type" = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"),
|
||||
)
|
||||
|
||||
/obj/machinery/computer/med_data/Destroy()
|
||||
active1 = null
|
||||
active2 = null
|
||||
@@ -33,7 +69,7 @@
|
||||
usr.drop_item()
|
||||
O.forceMove(src)
|
||||
scan = O
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -44,20 +80,25 @@
|
||||
to_chat(user, "<span class='danger'>Unable to establish a connection</span>: You're too far away from the station!")
|
||||
return
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/med_data/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/computer/med_data/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "med_data.tmpl", name, 800, 380)
|
||||
ui = new(user, src, ui_key, "MedicalRecords", "Medical Records", 800, 380, master_ui, state)
|
||||
ui.open()
|
||||
ui.set_autoupdate(FALSE)
|
||||
|
||||
/obj/machinery/computer/med_data/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/computer/med_data/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["temp"] = temp
|
||||
data["scan"] = scan ? scan.name : null
|
||||
data["authenticated"] = authenticated
|
||||
data["rank"] = rank
|
||||
data["screen"] = screen
|
||||
data["printing"] = printing
|
||||
data["isAI"] = isAI(user)
|
||||
data["isRobot"] = isrobot(user)
|
||||
if(authenticated)
|
||||
switch(screen)
|
||||
if(MED_DATA_R_LIST)
|
||||
@@ -72,17 +113,17 @@
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
var/list/fields = list()
|
||||
general["fields"] = fields
|
||||
fields[++fields.len] = list("field" = "Name:", "value" = active1.fields["name"], "edit" = null)
|
||||
fields[++fields.len] = list("field" = "ID:", "value" = active1.fields["id"], "edit" = null)
|
||||
fields[++fields.len] = list("field" = "Sex:", "value" = active1.fields["sex"], "edit" = "sex")
|
||||
fields[++fields.len] = list("field" = "Age:", "value" = active1.fields["age"], "edit" = "age")
|
||||
fields[++fields.len] = list("field" = "Fingerprint:", "value" = active1.fields["fingerprint"], "edit" = "fingerprint")
|
||||
fields[++fields.len] = list("field" = "Physical Status:", "value" = active1.fields["p_stat"], "edit" = "p_stat")
|
||||
fields[++fields.len] = list("field" = "Mental Status:", "value" = active1.fields["m_stat"], "edit" = "m_stat")
|
||||
fields[++fields.len] = FIELD("Name", active1.fields["name"], null)
|
||||
fields[++fields.len] = FIELD("ID", active1.fields["id"], null)
|
||||
fields[++fields.len] = FIELD("Sex", active1.fields["sex"], "sex")
|
||||
fields[++fields.len] = FIELD("Age", active1.fields["age"], "age")
|
||||
fields[++fields.len] = FIELD("Fingerprint", active1.fields["fingerprint"], "fingerprint")
|
||||
fields[++fields.len] = FIELD("Physical Status", active1.fields["p_stat"], "p_stat")
|
||||
fields[++fields.len] = FIELD("Mental Status", active1.fields["m_stat"], "m_stat")
|
||||
var/list/photos = list()
|
||||
general["photos"] = photos
|
||||
photos[++photos.len] = list("photo" = active1.fields["photo-south"])
|
||||
photos[++photos.len] = list("photo" = active1.fields["photo-west"])
|
||||
photos[++photos.len] = active1.fields["photo-south"]
|
||||
photos[++photos.len] = active1.fields["photo-west"]
|
||||
general["has_photos"] = (active1.fields["photo-south"] || active1.fields["photo-west"] ? 1 : 0)
|
||||
general["empty"] = 0
|
||||
else
|
||||
@@ -93,17 +134,17 @@
|
||||
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
|
||||
var/list/fields = list()
|
||||
medical["fields"] = fields
|
||||
fields[++fields.len] = list("field" = "Blood Type:", "value" = active2.fields["blood_type"], "edit" = "blood_type", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "DNA:", "value" = active2.fields["b_dna"], "edit" = "b_dna", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Minor Disabilities:", "value" = active2.fields["mi_dis"], "edit" = "mi_dis", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["mi_dis_d"], "edit" = "mi_dis_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Major Disabilities:", "value" = active2.fields["ma_dis"], "edit" = "ma_dis", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["ma_dis_d"], "edit" = "ma_dis_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Allergies:", "value" = active2.fields["alg"], "edit" = "alg", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["alg_d"], "edit" = "alg_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Current Diseases:", "value" = active2.fields["cdi"], "edit" = "cdi", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["cdi_d"], "edit" = "cdi_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Important Notes:", "value" = active2.fields["notes"], "edit" = "notes", "line_break" = 0)
|
||||
fields[++fields.len] = MED_FIELD("Blood Type", active2.fields["blood_type"], "blood_type", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("DNA", active2.fields["b_dna"], "b_dna", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Minor Disabilities", active2.fields["mi_dis"], "mi_dis", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("Details", active2.fields["mi_dis_d"], "mi_dis_d", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Major Disabilities", active2.fields["ma_dis"], "ma_dis", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("Details", active2.fields["ma_dis_d"], "ma_dis_d", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Allergies", active2.fields["alg"], "alg", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("Details", active2.fields["alg_d"], "alg_d", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Current Diseases", active2.fields["cdi"], "cdi", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("Details", active2.fields["cdi_d"], "cdi_d", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Important Notes", active2.fields["notes"], "notes", TRUE)
|
||||
if(!active2.fields["comments"] || !islist(active2.fields["comments"]))
|
||||
active2.fields["comments"] = list()
|
||||
medical["comments"] = active2.fields["comments"]
|
||||
@@ -127,7 +168,9 @@
|
||||
var/turf/T = get_turf(M)
|
||||
if(T)
|
||||
var/medbot = list()
|
||||
var/area/A = get_area(T)
|
||||
medbot["name"] = M.name
|
||||
medbot["area"] = A.name
|
||||
medbot["x"] = T.x
|
||||
medbot["y"] = T.y
|
||||
medbot["on"] = M.on
|
||||
@@ -138,395 +181,290 @@
|
||||
else
|
||||
medbot["use_beaker"] = 0
|
||||
data["medbots"] += list(medbot)
|
||||
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/med_data/Topic(href, href_list)
|
||||
/obj/machinery/computer/med_data/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(!GLOB.data_core.general.Find(active1))
|
||||
active1 = null
|
||||
if(!GLOB.data_core.medical.Find(active2))
|
||||
active2 = null
|
||||
|
||||
if(href_list["temp"])
|
||||
temp = null
|
||||
. = TRUE
|
||||
if(tgui_act_modal(action, params))
|
||||
return
|
||||
|
||||
if(href_list["temp_action"])
|
||||
if(href_list["temp_action"])
|
||||
var/temp_href = splittext(href_list["temp_action"], "=")
|
||||
switch(temp_href[1])
|
||||
if("del_all2")
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
qdel(R)
|
||||
setTemp("<h3>All records deleted.</h3>")
|
||||
if("p_stat")
|
||||
if(active1)
|
||||
switch(temp_href[2])
|
||||
if("deceased")
|
||||
active1.fields["p_stat"] = "*Deceased*"
|
||||
if("ssd")
|
||||
active1.fields["p_stat"] = "*SSD*"
|
||||
if("active")
|
||||
active1.fields["p_stat"] = "Active"
|
||||
if("unfit")
|
||||
active1.fields["p_stat"] = "Physically Unfit"
|
||||
if("disabled")
|
||||
active1.fields["p_stat"] = "Disabled"
|
||||
if("m_stat")
|
||||
if(active1)
|
||||
switch(temp_href[2])
|
||||
if("insane")
|
||||
active1.fields["m_stat"] = "*Insane*"
|
||||
if("unstable")
|
||||
active1.fields["m_stat"] = "*Unstable*"
|
||||
if("watch")
|
||||
active1.fields["m_stat"] = "*Watch*"
|
||||
if("stable")
|
||||
active1.fields["m_stat"] = "Stable"
|
||||
if("blood_type")
|
||||
if(active2)
|
||||
switch(temp_href[2])
|
||||
if("an")
|
||||
active2.fields["blood_type"] = "A-"
|
||||
if("bn")
|
||||
active2.fields["blood_type"] = "B-"
|
||||
if("abn")
|
||||
active2.fields["blood_type"] = "AB-"
|
||||
if("on")
|
||||
active2.fields["blood_type"] = "O-"
|
||||
if("ap")
|
||||
active2.fields["blood_type"] = "A+"
|
||||
if("bp")
|
||||
active2.fields["blood_type"] = "B+"
|
||||
if("abp")
|
||||
active2.fields["blood_type"] = "AB+"
|
||||
if("op")
|
||||
active2.fields["blood_type"] = "O+"
|
||||
if("del_r2")
|
||||
QDEL_NULL(active2)
|
||||
|
||||
if(href_list["scan"])
|
||||
if(scan)
|
||||
scan.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
switch(action)
|
||||
if("cleartemp")
|
||||
temp = null
|
||||
if("scan")
|
||||
if(scan)
|
||||
scan.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/card/id))
|
||||
usr.drop_item()
|
||||
I.forceMove(src)
|
||||
scan = I
|
||||
if("login")
|
||||
var/login_type = text2num(params["login_type"])
|
||||
if(login_type == LOGIN_TYPE_NORMAL && istype(scan))
|
||||
if(check_access(scan))
|
||||
authenticated = scan.registered_name
|
||||
rank = scan.assignment
|
||||
else if(login_type == LOGIN_TYPE_AI && isAI(usr))
|
||||
authenticated = usr.name
|
||||
rank = "AI"
|
||||
else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr))
|
||||
authenticated = usr.name
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
rank = "[R.modtype] [R.braintype]"
|
||||
if(authenticated)
|
||||
active1 = null
|
||||
active2 = null
|
||||
screen = MED_DATA_R_LIST
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/card/id))
|
||||
usr.drop_item()
|
||||
I.forceMove(src)
|
||||
scan = I
|
||||
. = FALSE
|
||||
|
||||
if(href_list["login"])
|
||||
if(isAI(usr))
|
||||
authenticated = usr.name
|
||||
rank = "AI"
|
||||
else if(isrobot(usr))
|
||||
authenticated = usr.name
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
rank = "[R.modtype] [R.braintype]"
|
||||
else if(istype(scan, /obj/item/card/id))
|
||||
if(check_access(scan))
|
||||
authenticated = scan.registered_name
|
||||
rank = scan.assignment
|
||||
|
||||
if(authenticated)
|
||||
active1 = null
|
||||
active2 = null
|
||||
screen = MED_DATA_MAIN
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(authenticated)
|
||||
if(href_list["logout"])
|
||||
authenticated = null
|
||||
screen = null
|
||||
active1 = null
|
||||
active2 = null
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("logout")
|
||||
if(scan)
|
||||
scan.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
authenticated = null
|
||||
screen = null
|
||||
active1 = null
|
||||
active2 = null
|
||||
if("screen")
|
||||
screen = clamp(text2num(params["screen"]) || 0, MED_DATA_R_LIST, MED_DATA_MEDBOT)
|
||||
active1 = null
|
||||
active2 = null
|
||||
if("vir")
|
||||
var/type = text2path(params["vir"] || "")
|
||||
if(!ispath(type, /datum/disease))
|
||||
return
|
||||
|
||||
if(href_list["screen"])
|
||||
screen = text2num(href_list["screen"])
|
||||
if(screen < 1)
|
||||
screen = MED_DATA_MAIN
|
||||
var/datum/disease/D = new type(0)
|
||||
var/list/payload = list(
|
||||
name = D.name,
|
||||
max_stages = D.max_stages,
|
||||
spread_text = D.spread_text,
|
||||
cure = D.cure_text || "None",
|
||||
desc = D.desc,
|
||||
severity = D.severity
|
||||
);
|
||||
tgui_modal_message(src, "virus", "", null, payload)
|
||||
qdel(D)
|
||||
if("del_all")
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
qdel(R)
|
||||
set_temp("All medical records deleted.")
|
||||
if("del_r")
|
||||
if(active2)
|
||||
set_temp("Medical record deleted.")
|
||||
qdel(active2)
|
||||
if("d_rec")
|
||||
var/datum/data/record/general_record = locate(params["d_rec"] || "")
|
||||
if(!GLOB.data_core.general.Find(general_record))
|
||||
set_temp("Record not found.", "danger")
|
||||
return
|
||||
|
||||
active1 = null
|
||||
active2 = null
|
||||
var/datum/data/record/medical_record
|
||||
for(var/datum/data/record/M in GLOB.data_core.medical)
|
||||
if(M.fields["name"] == general_record.fields["name"] && M.fields["id"] == general_record.fields["id"])
|
||||
medical_record = M
|
||||
break
|
||||
|
||||
if(href_list["vir"])
|
||||
var/type = href_list["vir"]
|
||||
var/datum/disease/D = new type(0)
|
||||
var/afs = ""
|
||||
for(var/mob/M in D.viable_mobtypes)
|
||||
afs += "[initial(M.name)];"
|
||||
var/severity = D.severity
|
||||
switch(severity)
|
||||
if("Harmful", "Minor")
|
||||
severity = "<span class='good'>[severity]</span>"
|
||||
if("Medium")
|
||||
severity = "<span class='average'>[severity]</span>"
|
||||
if("Dangerous!")
|
||||
severity = "<span class='bad'>[severity]</span>"
|
||||
if("BIOHAZARD THREAT!")
|
||||
severity = "<h4><span class='bad'>[severity]</span></h4>"
|
||||
setTemp({"<b>Name:</b> [D.name]
|
||||
<BR><b>Number of stages:</b> [D.max_stages]
|
||||
<BR><b>Spread:</b> [D.spread_text] Transmission
|
||||
<BR><b>Possible Cure:</b> [(D.cure_text||"none")]
|
||||
<BR><b>Affected Lifeforms:</b>[afs]<BR>
|
||||
<BR><b>Notes:</b> [D.desc]<BR>
|
||||
<BR><b>Severity:</b> [severity]"})
|
||||
qdel(D)
|
||||
|
||||
if(href_list["del_all"])
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_all2=1")
|
||||
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null)
|
||||
setTemp("<h3>Are you sure you wish to delete all records?</h3>", buttons)
|
||||
|
||||
if(href_list["field"])
|
||||
if(..())
|
||||
return 1
|
||||
var/a1 = active1
|
||||
var/a2 = active2
|
||||
switch(href_list["field"])
|
||||
if("fingerprint")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Med. records", active1.fields["fingerprint"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["fingerprint"] = t1
|
||||
if("sex")
|
||||
if(istype(active1, /datum/data/record))
|
||||
if(active1.fields["sex"] == "Male")
|
||||
active1.fields["sex"] = "Female"
|
||||
else
|
||||
active1.fields["sex"] = "Male"
|
||||
if("age")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = input("Please input age:", "Med. records", active1.fields["age"], null) as num
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["age"] = t1
|
||||
if("mi_dis")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input minor disabilities list:", "Med. records", active2.fields["mi_dis"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["mi_dis"] = t1
|
||||
if("mi_dis_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize minor dis.:", "Med. records", active2.fields["mi_dis_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["mi_dis_d"] = t1
|
||||
if("ma_dis")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input major diabilities list:", "Med. records", active2.fields["ma_dis"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["ma_dis"] = t1
|
||||
if("ma_dis_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize major dis.:", "Med. records", active2.fields["ma_dis_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["ma_dis_d"] = t1
|
||||
if("alg")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please state allergies:", "Med. records", active2.fields["alg"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["alg"] = t1
|
||||
if("alg_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize allergies:", "Med. records", active2.fields["alg_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["alg_d"] = t1
|
||||
if("cdi")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please state diseases:", "Med. records", active2.fields["cdi"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["cdi"] = t1
|
||||
if("cdi_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize diseases:", "Med. records", active2.fields["cdi_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["cdi_d"] = t1
|
||||
if("notes")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(html_encode(trim(input("Please summarize notes:", "Med. records", html_decode(active2.fields["notes"]), null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["notes"] = t1
|
||||
if("p_stat")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "*Deceased*", "icon" = "stethoscope", "href" = "p_stat=deceased", "status" = (active1.fields["p_stat"] == "*Deceased*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "*SSD*", "icon" = "stethoscope", "href" = "p_stat=ssd", "status" = (active1.fields["p_stat"] == "*SSD*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Active", "icon" = "stethoscope", "href" = "p_stat=active", "status" = (active1.fields["p_stat"] == "Active" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Physically Unfit", "icon" = "stethoscope", "href" = "p_stat=unfit", "status" = (active1.fields["p_stat"] == "Physically Unfit" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Disabled", "icon" = "stethoscope", "href" = "p_stat=disabled", "status" = (active1.fields["p_stat"] == "Disabled" ? "selected" : null))
|
||||
setTemp("<h3>Physical Condition</h3>", buttons)
|
||||
if("m_stat")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "*Insane*", "icon" = "stethoscope", "href" = "m_stat=insane", "status" = (active1.fields["m_stat"] == "*Insane*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "*Unstable*", "icon" = "stethoscope", "href" = "m_stat=unstable", "status" = (active1.fields["m_stat"] == "*Unstable*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "*Watch*", "icon" = "stethoscope", "href" = "m_stat=watch", "status" = (active1.fields["m_stat"] == "*Watch*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Stable", "icon" = "stethoscope", "href" = "m_stat=stable", "status" = (active1.fields["m_stat"] == "Stable" ? "selected" : null))
|
||||
setTemp("<h3>Mental Condition</h3>", buttons)
|
||||
if("blood_type")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "A-", "icon" = "tint", "href" = "blood_type=an", "status" = (active2.fields["blood_type"] == "A-" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "A+", "icon" = "tint", "href" = "blood_type=ap", "status" = (active2.fields["blood_type"] == "A+" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "B-", "icon" = "tint", "href" = "blood_type=bn", "status" = (active2.fields["blood_type"] == "B-" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "B+", "icon" = "tint", "href" = "blood_type=bp", "status" = (active2.fields["blood_type"] == "B+" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "AB-", "icon" = "tint", "href" = "blood_type=abn", "status" = (active2.fields["blood_type"] == "AB-" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "AB+", "icon" = "tint", "href" = "blood_type=abp", "status" = (active2.fields["blood_type"] == "AB+" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "O-", "icon" = "tint", "href" = "blood_type=on", "status" = (active2.fields["blood_type"] == "O-" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "O+", "icon" = "tint", "href" = "blood_type=op", "status" = (active2.fields["blood_type"] == "O+" ? "selected" : null))
|
||||
setTemp("<h3>Blood Type</h3>", buttons)
|
||||
if("b_dna")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input DNA hash:", "Med. records", active2.fields["b_dna"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["b_dna"] = t1
|
||||
if("vir_name")
|
||||
var/datum/data/record/v = locate(href_list["edit_vir"])
|
||||
if(v)
|
||||
var/t1 = copytext(trim(sanitize(input("Please input pathogen name:", "VirusDB", v.fields["name"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
v.fields["name"] = t1
|
||||
if("vir_desc")
|
||||
var/datum/data/record/v = locate(href_list["edit_vir"])
|
||||
if(v)
|
||||
var/t1 = copytext(trim(sanitize(input("Please input information about pathogen:", "VirusDB", v.fields["description"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
v.fields["description"] = t1
|
||||
|
||||
if(href_list["del_r"])
|
||||
if(active2)
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_r2=1", "status" = null)
|
||||
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null, "status" = null)
|
||||
setTemp("<h3>Are you sure you wish to delete the record (Medical Portion Only)?</h3>", buttons)
|
||||
|
||||
if(href_list["d_rec"])
|
||||
var/datum/data/record/R = locate(href_list["d_rec"])
|
||||
var/datum/data/record/M = locate(href_list["d_rec"])
|
||||
if(!GLOB.data_core.general.Find(R))
|
||||
setTemp("<h3 class='bad'>Record not found!</h3>")
|
||||
return 1
|
||||
for(var/datum/data/record/E in GLOB.data_core.medical)
|
||||
if(E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])
|
||||
M = E
|
||||
active1 = R
|
||||
active2 = M
|
||||
screen = MED_DATA_RECORD
|
||||
|
||||
if(href_list["new"])
|
||||
if(istype(active1, /datum/data/record) && !istype(active2, /datum/data/record))
|
||||
var/datum/data/record/R = new /datum/data/record()
|
||||
R.fields["name"] = active1.fields["name"]
|
||||
R.fields["id"] = active1.fields["id"]
|
||||
R.name = "Medical Record #[R.fields["id"]]"
|
||||
R.fields["blood_type"] = "Unknown"
|
||||
R.fields["b_dna"] = "Unknown"
|
||||
R.fields["mi_dis"] = "None"
|
||||
R.fields["mi_dis_d"] = "No minor disabilities have been declared."
|
||||
R.fields["ma_dis"] = "None"
|
||||
R.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
|
||||
R.fields["alg"] = "None"
|
||||
R.fields["alg_d"] = "No allergies have been detected in this patient."
|
||||
R.fields["cdi"] = "None"
|
||||
R.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
|
||||
R.fields["notes"] = "No notes."
|
||||
GLOB.data_core.medical += R
|
||||
active2 = R
|
||||
active1 = general_record
|
||||
active2 = medical_record
|
||||
screen = MED_DATA_RECORD
|
||||
|
||||
if(href_list["add_c"])
|
||||
if(!istype(active2, /datum/data/record))
|
||||
return 1
|
||||
var/a2 = active2
|
||||
var/t1 = copytext(trim(sanitize(input("Add Comment:", "Med. records", null, null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["comments"] += "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]<BR>[t1]"
|
||||
|
||||
if(href_list["del_c"])
|
||||
var/index = min(max(text2num(href_list["del_c"]) + 1, 1), length(active2.fields["comments"]))
|
||||
if(istype(active2, /datum/data/record) && active2.fields["comments"][index])
|
||||
active2.fields["comments"] -= active2.fields["comments"][index]
|
||||
|
||||
if(href_list["search"])
|
||||
var/t1 = clean_input("Search String: (Name, DNA, or ID)", "Med. records", null, null)
|
||||
if(!t1 || ..())
|
||||
return 1
|
||||
active1 = null
|
||||
active2 = null
|
||||
t1 = lowertext(t1)
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))
|
||||
if("new")
|
||||
if(istype(active1, /datum/data/record) && !istype(active2, /datum/data/record))
|
||||
var/datum/data/record/R = new /datum/data/record()
|
||||
R.fields["name"] = active1.fields["name"]
|
||||
R.fields["id"] = active1.fields["id"]
|
||||
R.name = "Medical Record #[R.fields["id"]]"
|
||||
R.fields["blood_type"] = "Unknown"
|
||||
R.fields["b_dna"] = "Unknown"
|
||||
R.fields["mi_dis"] = "None"
|
||||
R.fields["mi_dis_d"] = "No minor disabilities have been declared."
|
||||
R.fields["ma_dis"] = "None"
|
||||
R.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
|
||||
R.fields["alg"] = "None"
|
||||
R.fields["alg_d"] = "No allergies have been detected in this patient."
|
||||
R.fields["cdi"] = "None"
|
||||
R.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
|
||||
R.fields["notes"] = "No notes."
|
||||
GLOB.data_core.medical += R
|
||||
active2 = R
|
||||
if(!active2)
|
||||
setTemp("<h3 class='bad'>Could not locate record [t1].</h3>")
|
||||
else
|
||||
screen = MED_DATA_RECORD
|
||||
set_temp("Medical record created.", "success")
|
||||
if("del_c")
|
||||
var/index = text2num(params["del_c"] || "")
|
||||
if(!index || !istype(active2, /datum/data/record))
|
||||
return
|
||||
|
||||
var/list/comments = active2.fields["comments"]
|
||||
index = clamp(index, 1, length(comments))
|
||||
if(comments[index])
|
||||
comments.Cut(index, index + 1)
|
||||
if("search")
|
||||
active1 = null
|
||||
active2 = null
|
||||
var/t1 = lowertext(params["t1"] || "")
|
||||
if(!length(t1))
|
||||
return
|
||||
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))
|
||||
active2 = R
|
||||
break
|
||||
if(!active2)
|
||||
set_temp("Medical record not found. You must enter the person's exact name, ID or DNA.", "danger")
|
||||
return
|
||||
for(var/datum/data/record/E in GLOB.data_core.general)
|
||||
if(E.fields["name"] == active2.fields["name"] && E.fields["id"] == active2.fields["id"])
|
||||
active1 = E
|
||||
break
|
||||
screen = MED_DATA_RECORD
|
||||
if("print_p")
|
||||
if(!printing)
|
||||
printing = TRUE
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
|
||||
SStgui.update_uis(src)
|
||||
addtimer(CALLBACK(src, .proc/print_finish), 5 SECONDS)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(href_list["print_p"])
|
||||
if(!printing)
|
||||
printing = 1
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
|
||||
sleep(50)
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
P.info = "<CENTER><B>Medical Record</B></CENTER><BR>"
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]]
|
||||
<BR>\nSex: [active1.fields["sex"]]
|
||||
<BR>\nAge: [active1.fields["age"]]
|
||||
<BR>\nFingerprint: [active1.fields["fingerprint"]]
|
||||
<BR>\nPhysical Status: [active1.fields["p_stat"]]
|
||||
<BR>\nMental Status: [active1.fields["m_stat"]]<BR>"}
|
||||
/**
|
||||
* Called in tgui_act() to process modal actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The action passed by tgui
|
||||
* * params - The params passed by tgui
|
||||
*/
|
||||
/obj/machinery/computer/med_data/proc/tgui_act_modal(action, params)
|
||||
. = TRUE
|
||||
var/id = params["id"] // The modal's ID
|
||||
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_OPEN)
|
||||
switch(id)
|
||||
if("edit")
|
||||
var/field = arguments["field"]
|
||||
if(!length(field) || !field_edit_questions[field])
|
||||
return
|
||||
var/question = field_edit_questions[field]
|
||||
var/choices = field_edit_choices[field]
|
||||
if(length(choices))
|
||||
tgui_modal_choice(src, id, question, arguments = arguments, value = arguments["value"], choices = choices)
|
||||
else
|
||||
tgui_modal_input(src, id, question, arguments = arguments, value = arguments["value"])
|
||||
if("add_c")
|
||||
tgui_modal_input(src, id, "Please enter your message:")
|
||||
else
|
||||
P.info += "<B>General Record Lost!</B><BR>"
|
||||
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
|
||||
P.info += {"<BR>\n<CENTER><B>Medical Data</B></CENTER>
|
||||
<BR>\nBlood Type: [active2.fields["blood_type"]]
|
||||
<BR>\nDNA: [active2.fields["b_dna"]]<BR>\n
|
||||
<BR>\nMinor Disabilities: [active2.fields["mi_dis"]]
|
||||
<BR>\nDetails: [active2.fields["mi_dis_d"]]<BR>\n
|
||||
<BR>\nMajor Disabilities: [active2.fields["ma_dis"]]
|
||||
<BR>\nDetails: [active2.fields["ma_dis_d"]]<BR>\n
|
||||
<BR>\nAllergies: [active2.fields["alg"]]
|
||||
<BR>\nDetails: [active2.fields["alg_d"]]<BR>\n
|
||||
<BR>\nCurrent Diseases: [active2.fields["cdi"]] (per disease info placed in log/comment section)
|
||||
<BR>\nDetails: [active2.fields["cdi_d"]]<BR>\n
|
||||
<BR>\nImportant Notes:
|
||||
<BR>\n\t[active2.fields["notes"]]<BR>\n
|
||||
<BR>\n
|
||||
<CENTER><B>Comments/Log</B></CENTER><BR>"}
|
||||
for(var/c in active2.fields["comments"])
|
||||
P.info += "[c]<BR>"
|
||||
else
|
||||
P.info += "<B>Medical Record Lost!</B><BR>"
|
||||
P.info += "</TT>"
|
||||
P.name = "paper- 'Medical Record: [active1.fields["name"]]'"
|
||||
printing = 0
|
||||
return 1
|
||||
return FALSE
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
var/answer = params["answer"]
|
||||
switch(id)
|
||||
if("edit")
|
||||
var/field = arguments["field"]
|
||||
if(!length(field) || !field_edit_questions[field])
|
||||
return
|
||||
var/list/choices = field_edit_choices[field]
|
||||
if(length(choices) && !(answer in choices))
|
||||
return
|
||||
|
||||
/obj/machinery/computer/med_data/proc/setTemp(text, list/buttons = list())
|
||||
temp = list("text" = text, "buttons" = buttons, "has_buttons" = buttons.len > 0)
|
||||
if(field == "age")
|
||||
var/new_age = text2num(answer)
|
||||
if(new_age < AGE_MIN || new_age > AGE_MAX)
|
||||
set_temp("Invalid age. It must be between [AGE_MIN] and [AGE_MAX].", "danger")
|
||||
return
|
||||
answer = new_age
|
||||
|
||||
if(istype(active2) && (field in active2.fields))
|
||||
active2.fields[field] = answer
|
||||
else if(istype(active1) && (field in active1.fields))
|
||||
active1.fields[field] = answer
|
||||
if("add_c")
|
||||
if(!length(answer) || !istype(active2) || !length(authenticated))
|
||||
return
|
||||
active2.fields["comments"] += list(list(
|
||||
header = "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]",
|
||||
text = answer
|
||||
))
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Called when the print timer finishes
|
||||
*/
|
||||
/obj/machinery/computer/med_data/proc/print_finish()
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
P.info = "<center></b>Medical Record</b></center><br>"
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]]
|
||||
<br>\nSex: [active1.fields["sex"]]
|
||||
<br>\nAge: [active1.fields["age"]]
|
||||
<br>\nFingerprint: [active1.fields["fingerprint"]]
|
||||
<br>\nPhysical Status: [active1.fields["p_stat"]]
|
||||
<br>\nMental Status: [active1.fields["m_stat"]]<br>"}
|
||||
else
|
||||
P.info += "</b>General Record Lost!</b><br>"
|
||||
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
|
||||
P.info += {"<br>\n<center></b>Medical Data</b></center>
|
||||
<br>\nBlood Type: [active2.fields["blood_type"]]
|
||||
<br>\nDNA: [active2.fields["b_dna"]]<br>\n
|
||||
<br>\nMinor Disabilities: [active2.fields["mi_dis"]]
|
||||
<br>\nDetails: [active2.fields["mi_dis_d"]]<br>\n
|
||||
<br>\nMajor Disabilities: [active2.fields["ma_dis"]]
|
||||
<br>\nDetails: [active2.fields["ma_dis_d"]]<br>\n
|
||||
<br>\nAllergies: [active2.fields["alg"]]
|
||||
<br>\nDetails: [active2.fields["alg_d"]]<br>\n
|
||||
<br>\nCurrent Diseases: [active2.fields["cdi"]] (per disease info placed in log/comment section)
|
||||
<br>\nDetails: [active2.fields["cdi_d"]]<br>\n
|
||||
<br>\nImportant Notes:
|
||||
<br>\n\t[active2.fields["notes"]]<br>\n
|
||||
<br>\n
|
||||
<center></b>Comments/Log</b></center><br>"}
|
||||
for(var/c in active2.fields["comments"])
|
||||
P.info += "[c]<br>"
|
||||
else
|
||||
P.info += "</b>Medical Record Lost!</b><br>"
|
||||
P.info += "</tt>"
|
||||
P.name = "paper - 'Medical Record: [active1.fields["name"]]'"
|
||||
printing = FALSE
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* 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, virus
|
||||
*/
|
||||
/obj/machinery/computer/med_data/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/med_data/emp_act(severity)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
@@ -564,9 +502,10 @@
|
||||
icon_screen = "medlaptop"
|
||||
density = 0
|
||||
|
||||
#undef MED_DATA_MAIN
|
||||
#undef MED_DATA_R_LIST
|
||||
#undef MED_DATA_MAINT
|
||||
#undef MED_DATA_RECORD
|
||||
#undef MED_DATA_V_DATA
|
||||
#undef MED_DATA_MEDBOT
|
||||
#undef FIELD
|
||||
#undef MED_FIELD
|
||||
|
||||
+48
-67
@@ -103,7 +103,7 @@
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(atom/movable/O as mob|obj, mob/living/user as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(atom/movable/O, mob/living/user)
|
||||
if(O.loc == user) //no you can't pull things out of your ass
|
||||
return
|
||||
if(user.incapacitated()) //are you cuffed, dying, lying, stunned or other
|
||||
@@ -140,6 +140,7 @@
|
||||
add_attack_logs(user, L, "put into a cryo cell at [COORD(src)].", ATKLOG_ALL)
|
||||
if(user.pulling == L)
|
||||
user.stop_pulling()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/process()
|
||||
..()
|
||||
@@ -177,14 +178,14 @@
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user)
|
||||
if(user.stat)
|
||||
return
|
||||
go_out()
|
||||
return
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attack_ghost(mob/user)
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attack_hand(mob/user)
|
||||
if(user == occupant)
|
||||
@@ -194,36 +195,18 @@
|
||||
to_chat(usr, "<span class='boldnotice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
|
||||
/**
|
||||
* The ui_interact proc is used to open and update Nano UIs
|
||||
* If ui_interact is not used then the UI will not update correctly
|
||||
* ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob)
|
||||
*
|
||||
* @param user /mob The mob who is interacting with this ui
|
||||
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
|
||||
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 480)
|
||||
// open the new ui window
|
||||
ui = new(user, src, ui_key, "Cryo", "Cryo Cell", 520, 490)
|
||||
ui.open()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["isOperating"] = on
|
||||
data["hasOccupant"] = occupant ? 1 : 0
|
||||
data["hasOccupant"] = occupant ? TRUE : FALSE
|
||||
|
||||
var/occupantData[0]
|
||||
if(occupant)
|
||||
@@ -246,7 +229,7 @@
|
||||
else if(air_contents.temperature > TCRYO)
|
||||
data["cellTemperatureStatus"] = "average"
|
||||
|
||||
data["isBeakerLoaded"] = beaker ? 1 : 0
|
||||
data["isBeakerLoaded"] = beaker ? TRUE : FALSE
|
||||
data["beakerLabel"] = null
|
||||
data["beakerVolume"] = 0
|
||||
if(beaker)
|
||||
@@ -259,48 +242,44 @@
|
||||
data["auto_eject_dead"] = (auto_eject_prefs & AUTO_EJECT_DEAD) ? TRUE : FALSE
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/Topic(href, href_list)
|
||||
if(usr == occupant)
|
||||
return 0 // don't update UIs attached to this object
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_act(action, params)
|
||||
if(..() || usr == occupant)
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(..())
|
||||
return 0 // don't update UIs attached to this object
|
||||
|
||||
if(href_list["switchOn"])
|
||||
on = TRUE
|
||||
update_icon()
|
||||
|
||||
if(href_list["switchOff"])
|
||||
on = FALSE
|
||||
update_icon()
|
||||
|
||||
if(href_list["auto_eject_healthy_on"])
|
||||
auto_eject_prefs |= AUTO_EJECT_HEALTHY
|
||||
|
||||
if(href_list["auto_eject_healthy_off"])
|
||||
auto_eject_prefs &= ~AUTO_EJECT_HEALTHY
|
||||
|
||||
if(href_list["auto_eject_dead_on"])
|
||||
auto_eject_prefs |= AUTO_EJECT_DEAD
|
||||
|
||||
if(href_list["auto_eject_dead_off"])
|
||||
auto_eject_prefs &= ~AUTO_EJECT_DEAD
|
||||
|
||||
if(href_list["ejectBeaker"])
|
||||
if(beaker)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("switchOn")
|
||||
on = TRUE
|
||||
update_icon()
|
||||
if("switchOff")
|
||||
on = FALSE
|
||||
update_icon()
|
||||
if("auto_eject_healthy_on")
|
||||
auto_eject_prefs |= AUTO_EJECT_HEALTHY
|
||||
if("auto_eject_healthy_off")
|
||||
auto_eject_prefs &= ~AUTO_EJECT_HEALTHY
|
||||
if("auto_eject_dead_on")
|
||||
auto_eject_prefs |= AUTO_EJECT_DEAD
|
||||
if("auto_eject_dead_off")
|
||||
auto_eject_prefs &= ~AUTO_EJECT_DEAD
|
||||
if("ejectBeaker")
|
||||
if(!beaker)
|
||||
return
|
||||
beaker.forceMove(get_step(loc, SOUTH))
|
||||
beaker = null
|
||||
|
||||
if(href_list["ejectOccupant"])
|
||||
if(!occupant || isslime(usr) || ispAI(usr))
|
||||
return 0 // don't update UIs attached to this object
|
||||
add_attack_logs(usr, occupant, "ejected from cryo cell at [COORD(src)]", ATKLOG_ALL)
|
||||
go_out()
|
||||
if("ejectOccupant")
|
||||
if(!occupant || isslime(usr) || ispAI(usr))
|
||||
return
|
||||
add_attack_logs(usr, occupant, "ejected from cryo cell at [COORD(src)]", ATKLOG_ALL)
|
||||
go_out()
|
||||
else
|
||||
return FALSE
|
||||
|
||||
add_fingerprint(usr)
|
||||
return 1 // update UIs attached to this object
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/item/G as obj, var/mob/user as mob, params)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/item/G, var/mob/user, params)
|
||||
if(istype(G, /obj/item/reagent_containers/glass))
|
||||
var/obj/item/reagent_containers/B = G
|
||||
if(beaker)
|
||||
@@ -313,6 +292,7 @@
|
||||
beaker = B
|
||||
add_attack_logs(user, null, "Added [B] containing [B.reagents.log_list()] to a cryo cell at [COORD(src)]")
|
||||
user.visible_message("[user] adds \a [B] to [src]!", "You add \a [B] to [src]!")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
if(exchange_parts(user, G))
|
||||
@@ -357,7 +337,7 @@
|
||||
return
|
||||
|
||||
if(occupant)
|
||||
var/image/pickle = image(occupant.icon, occupant.icon_state)
|
||||
var/mutable_appearance/pickle = mutable_appearance(occupant.icon, occupant.icon_state)
|
||||
pickle.overlays = occupant.overlays
|
||||
pickle.pixel_y = 22
|
||||
|
||||
@@ -455,8 +435,9 @@
|
||||
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
if(AUTO_EJECT_DEAD)
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 40)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M)
|
||||
if(!istype(M))
|
||||
to_chat(usr, "<span class='danger'>The cryo cell cannot handle such a lifeform!</span>")
|
||||
return
|
||||
@@ -530,7 +511,7 @@
|
||||
/datum/data/function/proc/reset()
|
||||
return
|
||||
|
||||
/datum/data/function/proc/r_input(href, href_list, mob/user as mob)
|
||||
/datum/data/function/proc/r_input(href, href_list, mob/user)
|
||||
return
|
||||
|
||||
/datum/data/function/proc/display()
|
||||
|
||||
@@ -309,6 +309,20 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
/datum/asset/chem_master/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
|
||||
//Cloning pod sprites for UIs
|
||||
/datum/asset/cloning
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/cloning/register()
|
||||
assets["pod_idle.gif"] = icon('icons/obj/cloning.dmi', "pod_idle")
|
||||
assets["pod_cloning.gif"] = icon('icons/obj/cloning.dmi', "pod_cloning")
|
||||
assets["pod_mess.gif"] = icon('icons/obj/cloning.dmi', "pod_mess")
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/cloning/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
|
||||
//Pipe sprites for UIs
|
||||
/datum/asset/rpd
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
var/list/hacked_reagents = list("toxin")
|
||||
var/hack_message = "You disable the safety safeguards, enabling the \"Mad Scientist\" mode."
|
||||
var/unhack_message = "You re-enable the safety safeguards, enabling the \"NT Standard\" mode."
|
||||
var/is_drink = FALSE
|
||||
|
||||
/obj/machinery/chem_dispenser/get_cell()
|
||||
return cell
|
||||
@@ -120,7 +121,6 @@
|
||||
var/usedpower = cell.give(recharge_amount)
|
||||
if(usedpower)
|
||||
use_power(15 * recharge_amount)
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
recharge_counter = 0
|
||||
return
|
||||
recharge_counter++
|
||||
@@ -131,7 +131,6 @@
|
||||
else
|
||||
spawn(rand(0, 15))
|
||||
stat |= NOPOWER
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
/obj/machinery/chem_dispenser/ex_act(severity)
|
||||
if(severity < 3)
|
||||
@@ -145,19 +144,17 @@
|
||||
beaker = null
|
||||
overlays.Cut()
|
||||
|
||||
/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
/obj/machinery/chem_dispenser/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "chem_dispenser.tmpl", ui_title, 390, 655)
|
||||
// open the new ui window
|
||||
ui = new(user, src, ui_key, "ChemDispenser", ui_title, 390, 655)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_dispenser/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/chem_dispenser/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["glass"] = is_drink
|
||||
data["amount"] = amount
|
||||
data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI.
|
||||
data["maxEnergy"] = cell.maxcharge * powerefficiency
|
||||
@@ -187,63 +184,59 @@
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/chem_dispenser/Topic(href, href_list)
|
||||
/obj/machinery/chem_dispenser/tgui_act(actions, params)
|
||||
if(..())
|
||||
return TRUE
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(href_list["amount"])
|
||||
amount = round(text2num(href_list["amount"]), 1) // round to nearest 1
|
||||
if(amount < 0) // Since the user can actually type the commands himself, some sanity checking
|
||||
amount = 0
|
||||
if(amount > 100)
|
||||
amount = 100
|
||||
|
||||
if(href_list["dispense"])
|
||||
if(!is_operational() || QDELETED(cell))
|
||||
return
|
||||
if(beaker && dispensable_reagents.Find(href_list["dispense"]))
|
||||
. = TRUE
|
||||
switch(actions)
|
||||
if("amount")
|
||||
amount = clamp(round(text2num(params["amount"]), 1), 0, 50) // round to nearest 1 and clamp to 0 - 50
|
||||
if("dispense")
|
||||
if(!is_operational() || QDELETED(cell))
|
||||
return
|
||||
if(!beaker || !dispensable_reagents.Find(params["reagent"]))
|
||||
return
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/free = R.maximum_volume - R.total_volume
|
||||
var/actual = min(amount, (cell.charge * powerefficiency) * 10, free)
|
||||
|
||||
if(!cell.use(actual / powerefficiency))
|
||||
atom_say("Not enough energy to complete operation!")
|
||||
return
|
||||
|
||||
R.add_reagent(href_list["dispense"], actual)
|
||||
R.add_reagent(params["reagent"], actual)
|
||||
overlays.Cut()
|
||||
if(!icon_beaker)
|
||||
icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
|
||||
icon_beaker = mutable_appearance('icons/obj/chemical.dmi', "disp_beaker") //randomize beaker overlay position.
|
||||
icon_beaker.pixel_x = rand(-10, 5)
|
||||
overlays += icon_beaker
|
||||
|
||||
if(href_list["remove"])
|
||||
if(beaker)
|
||||
if(href_list["removeamount"])
|
||||
var/amount = text2num(href_list["removeamount"])
|
||||
if(isnum(amount) && (amount > 0))
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/id = href_list["remove"]
|
||||
R.remove_reagent(id, amount)
|
||||
else if(isnum(amount) && (amount == -1)) //Isolate instead
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/id = href_list["remove"]
|
||||
R.isolate_reagent(id)
|
||||
|
||||
if(href_list["ejectBeaker"])
|
||||
if(beaker)
|
||||
if("remove")
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!beaker || !amount)
|
||||
return
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/id = params["reagent"]
|
||||
if(amount > 0)
|
||||
R.remove_reagent(id, amount)
|
||||
else if(amount == -1) //Isolate instead
|
||||
R.isolate_reagent(id)
|
||||
if("ejectBeaker")
|
||||
if(!beaker)
|
||||
return
|
||||
beaker.forceMove(loc)
|
||||
if(Adjacent(usr) && !issilicon(usr))
|
||||
usr.put_in_hands(beaker)
|
||||
beaker = null
|
||||
overlays.Cut()
|
||||
else
|
||||
return FALSE
|
||||
|
||||
add_fingerprint(usr)
|
||||
return TRUE // update UIs attached to this object
|
||||
|
||||
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
|
||||
if(exchange_parts(user, I))
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
if(isrobot(user))
|
||||
@@ -263,9 +256,9 @@
|
||||
beaker = I
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You set [I] on the machine.</span>")
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
SStgui.update_uis(src) // update all UIs attached to src
|
||||
if(!icon_beaker)
|
||||
icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
|
||||
icon_beaker = mutable_appearance('icons/obj/chemical.dmi', "disp_beaker") //randomize beaker overlay position.
|
||||
icon_beaker.pixel_x = rand(-10, 5)
|
||||
overlays += icon_beaker
|
||||
return
|
||||
@@ -299,8 +292,7 @@
|
||||
to_chat(user, unhack_message)
|
||||
dispensable_reagents -= hacked_reagents
|
||||
hackedcheck = FALSE
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/chem_dispenser/screwdriver_act(mob/user, obj/item/I)
|
||||
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", "[initial(icon_state)]", I))
|
||||
@@ -321,14 +313,14 @@
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/chem_dispenser/attack_ghost(mob/user)
|
||||
if(user.can_admin_interact())
|
||||
return attack_hand(user)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_dispenser/attack_hand(mob/user)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_dispenser/soda
|
||||
icon_state = "soda_dispenser"
|
||||
@@ -342,6 +334,7 @@
|
||||
hacked_reagents = list("thirteenloko")
|
||||
hack_message = "You change the mode from 'McNano' to 'Pizza King'."
|
||||
unhack_message = "You change the mode from 'Pizza King' to 'McNano'."
|
||||
is_drink = TRUE
|
||||
|
||||
/obj/machinery/chem_dispenser/soda/New()
|
||||
..()
|
||||
@@ -377,6 +370,7 @@
|
||||
hacked_reagents = list("goldschlager", "patron", "absinthe", "ethanol", "nothing", "sake")
|
||||
hack_message = "You disable the 'nanotrasen-are-cheap-bastards' lock, enabling hidden and very expensive boozes."
|
||||
unhack_message = "You re-enable the 'nanotrasen-are-cheap-bastards' lock, disabling hidden and very expensive boozes."
|
||||
is_drink = TRUE
|
||||
|
||||
/obj/machinery/chem_dispenser/beer/New()
|
||||
..()
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
/obj/machinery/chem_heater
|
||||
name = "chemical heater"
|
||||
density = 1
|
||||
anchored = 1
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "mixer0b"
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 40
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
resistance_flags = FIRE_PROOF|ACID_PROOF
|
||||
var/obj/item/reagent_containers/beaker = null
|
||||
var/desired_temp = T0C
|
||||
var/on = FALSE
|
||||
/// Whether this should auto-eject the beaker once done heating/cooling.
|
||||
var/auto_eject = FALSE
|
||||
/// The higher this number, the faster reagents will heat/cool.
|
||||
var/speed_increase = 0
|
||||
|
||||
/obj/machinery/chem_heater/New()
|
||||
..()
|
||||
@@ -19,35 +23,36 @@
|
||||
component_parts += new /obj/item/stack/sheet/glass(null)
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/chem_heater/RefreshParts()
|
||||
speed_increase = initial(speed_increase)
|
||||
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
|
||||
speed_increase += 5 * (M.rating - 1)
|
||||
|
||||
/obj/machinery/chem_heater/process()
|
||||
..()
|
||||
if(stat & NOPOWER)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
var/state_change = FALSE
|
||||
if(on)
|
||||
if(beaker)
|
||||
if(!beaker.reagents.total_volume)
|
||||
on = FALSE
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
beaker.reagents.temperature_reagents(desired_temp)
|
||||
beaker.reagents.temperature_reagents(desired_temp)
|
||||
if(abs(beaker.reagents.chem_temp - desired_temp) <= 3)
|
||||
beaker.reagents.temperature_reagents(desired_temp, max(1, 35 - speed_increase))
|
||||
if(round(beaker.reagents.chem_temp) == round(desired_temp))
|
||||
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
on = FALSE
|
||||
state_change = TRUE
|
||||
|
||||
if(state_change)
|
||||
SSnanoui.update_uis(src)
|
||||
if(auto_eject)
|
||||
eject_beaker()
|
||||
|
||||
/obj/machinery/chem_heater/proc/eject_beaker(mob/user)
|
||||
if(beaker)
|
||||
beaker.forceMove(get_turf(src))
|
||||
if(Adjacent(user) && !issilicon(user))
|
||||
if(user && Adjacent(user) && !issilicon(user))
|
||||
user.put_in_hands(beaker)
|
||||
beaker = null
|
||||
icon_state = "mixer0b"
|
||||
on = FALSE
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/chem_heater/power_change()
|
||||
if(powered())
|
||||
@@ -55,7 +60,6 @@
|
||||
else
|
||||
spawn(rand(0, 15))
|
||||
stat |= NOPOWER
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
/obj/machinery/chem_heater/attackby(obj/item/I, mob/user)
|
||||
if(isrobot(user))
|
||||
@@ -71,7 +75,7 @@
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You add the beaker to the machine!</span>")
|
||||
icon_state = "mixer1b"
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
if(exchange_parts(user, I))
|
||||
@@ -95,62 +99,62 @@
|
||||
default_deconstruction_crowbar(user, I)
|
||||
|
||||
/obj/machinery/chem_heater/attack_hand(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_heater/attack_ghost(mob/user)
|
||||
if(user.can_admin_interact())
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_heater/attack_ai(mob/user)
|
||||
add_hiddenprint(user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/chem_heater/Topic(href, href_list)
|
||||
/obj/machinery/chem_heater/tgui_act(action, params)
|
||||
if(..())
|
||||
return FALSE
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(href_list["toggle_on"])
|
||||
if(!beaker.reagents.total_volume)
|
||||
return FALSE
|
||||
on = !on
|
||||
. = 1
|
||||
|
||||
if(href_list["adjust_temperature"])
|
||||
var/val = href_list["adjust_temperature"]
|
||||
if(isnum(val))
|
||||
desired_temp = clamp(desired_temp+val, 0, 1000)
|
||||
else if(val == "input")
|
||||
var/target = input("Please input the target temperature", name) as num
|
||||
desired_temp = clamp(target, 0, 1000)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("toggle_on")
|
||||
on = !on
|
||||
if("adjust_temperature")
|
||||
desired_temp = clamp(text2num(params["target"]), 0, 1000)
|
||||
if("eject_beaker")
|
||||
eject_beaker(usr)
|
||||
. = FALSE
|
||||
if("toggle_autoeject")
|
||||
auto_eject = !auto_eject
|
||||
else
|
||||
return FALSE
|
||||
. = 1
|
||||
add_fingerprint(usr)
|
||||
|
||||
if(href_list["eject_beaker"])
|
||||
eject_beaker(usr)
|
||||
. = 0 //updated in eject_beaker() already
|
||||
|
||||
/obj/machinery/chem_heater/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null)
|
||||
/obj/machinery/chem_heater/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
if(user.stat || user.restrained())
|
||||
return
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "chem_heater.tmpl", "ChemHeater", 350, 270)
|
||||
ui = new(user, src, ui_key, "ChemHeater", "Chemical Heater", 350, 270, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/chem_heater/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
var/cur_temp = beaker ? beaker.reagents.chem_temp : null
|
||||
|
||||
data["targetTemp"] = desired_temp
|
||||
data["targetTempReached"] = FALSE
|
||||
data["autoEject"] = auto_eject
|
||||
data["isActive"] = on
|
||||
data["isBeakerLoaded"] = beaker ? 1 : 0
|
||||
data["isBeakerLoaded"] = beaker ? TRUE : FALSE
|
||||
|
||||
data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null
|
||||
data["currentTemp"] = cur_temp
|
||||
data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null
|
||||
data["beakerMaxVolume"] = beaker ? beaker.volume : null
|
||||
|
||||
if(cur_temp)
|
||||
data["targetTempReached"] = round(cur_temp) == round(desired_temp)
|
||||
|
||||
//copy-pasted from chem dispenser
|
||||
var/beakerContents[0]
|
||||
if(beaker)
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
#define MAX_PILL_SPRITE 20 //max icon state of the pill sprites
|
||||
#define MAX_MULTI_AMOUNT 20 // Max number of pills/patches that can be made at once
|
||||
#define MAX_UNITS_PER_PILL 100 // Max amount of units in a pill
|
||||
#define MAX_UNITS_PER_PATCH 30 // Max amount of units in a patch
|
||||
#define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever
|
||||
|
||||
/obj/machinery/chem_master
|
||||
name = "\improper ChemMaster 3000"
|
||||
density = TRUE
|
||||
@@ -14,10 +20,12 @@
|
||||
var/useramount = 30 // Last used amount
|
||||
var/pillamount = 10
|
||||
var/patchamount = 10
|
||||
var/bottlesprite = "bottle"
|
||||
var/pillsprite = "1"
|
||||
var/bottlesprite = 1
|
||||
var/pillsprite = 1
|
||||
var/client/has_sprites = list()
|
||||
var/printing = FALSE
|
||||
var/static/list/pill_bottle_wrappers
|
||||
var/static/list/bottle_styles
|
||||
|
||||
/obj/machinery/chem_master/New()
|
||||
..()
|
||||
@@ -94,7 +102,7 @@
|
||||
beaker = I
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You add the beaker to the machine!</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
update_icon()
|
||||
|
||||
else if(istype(I, /obj/item/storage/pill_bottle))
|
||||
@@ -109,14 +117,10 @@
|
||||
loaded_pill_bottle = I
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You add [I] into the dispenser slot!</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/machinery/chem_master/crowbar_act(mob/user, obj/item/I)
|
||||
if(!panel_open)
|
||||
return
|
||||
@@ -142,319 +146,127 @@
|
||||
power_change()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/chem_master/Topic(href, href_list)
|
||||
/obj/machinery/chem_master/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(tgui_act_modal(action, params, ui, state))
|
||||
return TRUE
|
||||
|
||||
add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
|
||||
if(href_list["ejectp"])
|
||||
if(loaded_pill_bottle)
|
||||
loaded_pill_bottle.forceMove(loc)
|
||||
loaded_pill_bottle = null
|
||||
else if(href_list["change_pillbottle"])
|
||||
if(loaded_pill_bottle)
|
||||
var/list/wrappers = list("Default wrapper", "Red wrapper", "Green wrapper", "Pale green wrapper", "Blue wrapper", "Light blue wrapper", "Teal wrapper", "Yellow wrapper", "Orange wrapper", "Pink wrapper", "Brown wrapper")
|
||||
var/chosen = input(usr, "Select a pillbottle wrapper", "Pillbottle wrapper", wrappers[1]) as null|anything in wrappers
|
||||
if(!chosen)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("toggle")
|
||||
mode = !mode
|
||||
if("ejectp")
|
||||
if(loaded_pill_bottle)
|
||||
loaded_pill_bottle.forceMove(loc)
|
||||
loaded_pill_bottle = null
|
||||
if("print")
|
||||
if(printing || condi)
|
||||
return
|
||||
var/color
|
||||
switch(chosen)
|
||||
if("Default wrapper")
|
||||
loaded_pill_bottle.cut_overlays()
|
||||
return
|
||||
if("Red wrapper")
|
||||
color = COLOR_RED
|
||||
if("Green wrapper")
|
||||
color = COLOR_GREEN
|
||||
if("Pink wrapper")
|
||||
color = COLOR_PINK
|
||||
if("Teal wrapper")
|
||||
color = COLOR_TEAL
|
||||
if("Blue wrapper")
|
||||
color = COLOR_BLUE
|
||||
if("Brown wrapper")
|
||||
color = COLOR_MAROON
|
||||
if("Light blue wrapper")
|
||||
color = COLOR_CYAN_BLUE
|
||||
if("Yellow wrapper")
|
||||
color = COLOR_YELLOW
|
||||
if("Pale green wrapper")
|
||||
color = COLOR_PALE_BTL_GREEN
|
||||
if("Orange wrapper")
|
||||
color = COLOR_ORANGE
|
||||
loaded_pill_bottle.wrapper_color = color
|
||||
loaded_pill_bottle.apply_wrap()
|
||||
else if(href_list["close"])
|
||||
usr << browse(null, "window=chem_master")
|
||||
onclose(usr, "chem_master")
|
||||
usr.unset_machine()
|
||||
return
|
||||
|
||||
if(href_list["print_p"])
|
||||
if(!printing)
|
||||
var/idx = text2num(params["idx"]) || 0
|
||||
var/from_beaker = text2num(params["beaker"]) || FALSE
|
||||
var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
|
||||
if(idx < 1 || idx > length(reagent_list))
|
||||
return
|
||||
|
||||
var/datum/reagent/R = reagent_list[idx]
|
||||
|
||||
printing = TRUE
|
||||
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
|
||||
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
P.info = "<CENTER><B>Chemical Analysis</B></CENTER><BR>"
|
||||
P.info = "<center><b>Chemical Analysis</b></center><br>"
|
||||
P.info += "<b>Time of analysis:</b> [station_time_timestamp()]<br><br>"
|
||||
P.info += "<b>Chemical name:</b> [href_list["name"]]<br>"
|
||||
if(href_list["name"] == "Blood")
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/datum/reagent/blood/G
|
||||
for(var/datum/reagent/F in R.reagent_list)
|
||||
if(F.name == href_list["name"])
|
||||
G = F
|
||||
break
|
||||
var/B = G.data["blood_type"]
|
||||
var/C = G.data["blood_DNA"]
|
||||
P.info += "<b>Description:</b><br>Blood Type: [B]<br>DNA: [C]"
|
||||
P.info += "<b>Chemical name:</b> [R.name]<br>"
|
||||
if(istype(R, /datum/reagent/blood))
|
||||
var/datum/reagent/blood/B = R
|
||||
P.info += "<b>Description:</b> N/A<br><b>Blood Type:</b> [B.data["blood_type"]]<br><b>DNA:</b> [B.data["blood_DNA"]]"
|
||||
else
|
||||
P.info += "<b>Description:</b> [href_list["desc"]]"
|
||||
P.info += "<b>Description:</b> [R.description]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Chemical Analysis - [href_list["name"]]"
|
||||
printing = FALSE
|
||||
P.name = "Chemical Analysis - [R.name]"
|
||||
spawn(50)
|
||||
printing = FALSE
|
||||
else
|
||||
. = FALSE
|
||||
|
||||
if(beaker)
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
if(href_list["analyze"])
|
||||
var/dat = ""
|
||||
if(!condi)
|
||||
if(href_list["name"] == "Blood")
|
||||
var/datum/reagent/blood/G
|
||||
for(var/datum/reagent/F in R.reagent_list)
|
||||
if(F.name == href_list["name"])
|
||||
G = F
|
||||
break
|
||||
var/A = G.name
|
||||
var/B = G.data["blood_type"]
|
||||
var/C = G.data["blood_DNA"]
|
||||
dat += "<TITLE>Chemmaster 3000</TITLE>Chemical infos:<BR><BR>Name:<BR>[A]<BR><BR>Description:<BR>Blood Type: [B]<br>DNA: [C]"
|
||||
else
|
||||
dat += "<TITLE>Chemmaster 3000</TITLE>Chemical infos:<BR><BR>Name:<BR>[href_list["name"]]<BR><BR>Description:<BR>[href_list["desc"]]"
|
||||
dat += "<BR><BR><A href='?src=[UID()];print_p=1;desc=[href_list["desc"]];name=[href_list["name"]]'>(Print Analysis)</A><BR>"
|
||||
dat += "<A href='?src=[UID()];main=1'>(Back)</A>"
|
||||
if(. || !beaker)
|
||||
return
|
||||
|
||||
. = TRUE
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
switch(action)
|
||||
if("add")
|
||||
var/id = params["id"]
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!id || !amount)
|
||||
return
|
||||
R.trans_id_to(src, id, amount)
|
||||
if("remove")
|
||||
var/id = params["id"]
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!id || !amount)
|
||||
return
|
||||
if(mode)
|
||||
reagents.trans_id_to(beaker, id, amount)
|
||||
else
|
||||
dat += "<TITLE>Condimaster 3000</TITLE>Condiment infos:<BR><BR>Name:<BR>[href_list["name"]]<BR><BR>Description:<BR>[href_list["desc"]]<BR><BR><BR><A href='?src=[UID()];main=1'>(Back)</A>"
|
||||
usr << browse(dat, "window=chem_master;size=575x500")
|
||||
return
|
||||
|
||||
else if(href_list["add"])
|
||||
|
||||
if(href_list["amount"])
|
||||
var/id = href_list["add"]
|
||||
var/amount = text2num(href_list["amount"])
|
||||
R.trans_id_to(src, id, amount)
|
||||
|
||||
else if(href_list["addcustom"])
|
||||
|
||||
var/id = href_list["addcustom"]
|
||||
useramount = input("Select the amount to transfer.", 30, useramount) as num
|
||||
useramount = isgoodnumber(useramount)
|
||||
Topic(null, list("amount" = "[useramount]", "add" = "[id]"))
|
||||
|
||||
else if(href_list["remove"])
|
||||
|
||||
if(href_list["amount"])
|
||||
var/id = href_list["remove"]
|
||||
var/amount = text2num(href_list["amount"])
|
||||
if(mode)
|
||||
reagents.trans_id_to(beaker, id, amount)
|
||||
else
|
||||
reagents.remove_reagent(id, amount)
|
||||
|
||||
|
||||
else if(href_list["removecustom"])
|
||||
|
||||
var/id = href_list["removecustom"]
|
||||
useramount = input("Select the amount to transfer.", 30, useramount) as num
|
||||
useramount = isgoodnumber(useramount)
|
||||
Topic(null, list("amount" = "[useramount]", "remove" = "[id]"))
|
||||
|
||||
else if(href_list["toggle"])
|
||||
mode = !mode
|
||||
|
||||
else if(href_list["main"])
|
||||
attack_hand(usr)
|
||||
return
|
||||
else if(href_list["eject"])
|
||||
if(beaker)
|
||||
beaker.forceMove(get_turf(src))
|
||||
if(Adjacent(usr) && !issilicon(usr))
|
||||
usr.put_in_hands(beaker)
|
||||
beaker = null
|
||||
reagents.clear_reagents()
|
||||
update_icon()
|
||||
else if(href_list["createpill"] || href_list["createpill_multiple"])
|
||||
if(!condi)
|
||||
var/count = 1
|
||||
if(href_list["createpill_multiple"])
|
||||
count = input("Select the number of pills to make.", 10, pillamount) as num|null
|
||||
if(count == null)
|
||||
return
|
||||
count = isgoodnumber(count)
|
||||
if(count > 20)
|
||||
count = 20 //Pevent people from creating huge stacks of pills easily. Maybe move the number to defines?
|
||||
if(count <= 0)
|
||||
return
|
||||
var/amount_per_pill = reagents.total_volume / count
|
||||
if(amount_per_pill > 100)
|
||||
amount_per_pill = 100
|
||||
var/name = clean_input("Name:","Name your pill!","[reagents.get_master_reagent_name()] ([amount_per_pill]u)")
|
||||
if(!name)
|
||||
return
|
||||
name = reject_bad_text(name)
|
||||
while(count--)
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(usr, "<span class='notice'>Not enough reagents to create these pills!</span>")
|
||||
return
|
||||
var/obj/item/reagent_containers/food/pill/P = new/obj/item/reagent_containers/food/pill(loc)
|
||||
if(!name)
|
||||
name = reagents.get_master_reagent_name()
|
||||
P.name = "[name] pill"
|
||||
P.pixel_x = rand(-7, 7) //random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = "pill"+pillsprite
|
||||
reagents.trans_to(P, amount_per_pill)
|
||||
if(loaded_pill_bottle && loaded_pill_bottle.type == /obj/item/storage/pill_bottle)
|
||||
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
updateUsrDialog()
|
||||
else
|
||||
var/name = clean_input("Name:", "Name your bag!", reagents.get_master_reagent_name())
|
||||
if(!name)
|
||||
return
|
||||
name = reject_bad_text(name)
|
||||
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(loc)
|
||||
if(!name) name = reagents.get_master_reagent_name()
|
||||
P.originalname = name
|
||||
P.name = "[name] pack"
|
||||
P.desc = "A small condiment pack. The label says it contains [name]."
|
||||
reagents.trans_to(P, 10)
|
||||
else if(href_list["createpatch"] || href_list["createpatch_multiple"])
|
||||
if(!condi)
|
||||
var/count = 1
|
||||
if(href_list["createpatch_multiple"])
|
||||
count = input("Select the number of patches to make.", 10, patchamount) as num|null
|
||||
if(count == null)
|
||||
return
|
||||
count = isgoodnumber(count)
|
||||
if(!count || count <= 0)
|
||||
return
|
||||
if(count > 20)
|
||||
count = 20 //Pevent people from creating huge stacks of patches easily. Maybe move the number to defines?
|
||||
var/amount_per_patch = reagents.total_volume/count
|
||||
if(amount_per_patch > 30)
|
||||
amount_per_patch = 30
|
||||
var/name = clean_input("Name:", "Name your patch!", "[reagents.get_master_reagent_name()] ([amount_per_patch]u)")
|
||||
if(!name)
|
||||
return
|
||||
name = reject_bad_text(name)
|
||||
var/is_medical_patch = chemical_safety_check(reagents)
|
||||
while(count--)
|
||||
var/obj/item/reagent_containers/food/pill/patch/P = new/obj/item/reagent_containers/food/pill/patch(loc)
|
||||
if(!name) name = reagents.get_master_reagent_name()
|
||||
P.name = "[name] patch"
|
||||
P.pixel_x = rand(-7, 7) //random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
reagents.trans_to(P,amount_per_patch)
|
||||
if(is_medical_patch)
|
||||
P.instant_application = TRUE
|
||||
P.icon_state = "bandaid_med"
|
||||
if(loaded_pill_bottle && loaded_pill_bottle.type == /obj/item/storage/pill_bottle/patch_pack)
|
||||
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["createbottle"])
|
||||
if(!condi)
|
||||
var/name = clean_input("Name:", "Name your bottle!", reagents.get_master_reagent_name())
|
||||
if(!name)
|
||||
return
|
||||
name = reject_bad_text(name)
|
||||
var/obj/item/reagent_containers/glass/bottle/reagent/P = new/obj/item/reagent_containers/glass/bottle/reagent(loc)
|
||||
if(!name)
|
||||
name = reagents.get_master_reagent_name()
|
||||
P.name = "[name] bottle"
|
||||
P.pixel_x = rand(-7, 7) //random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = bottlesprite
|
||||
reagents.trans_to(P, 50)
|
||||
else
|
||||
var/obj/item/reagent_containers/food/condiment/P = new/obj/item/reagent_containers/food/condiment(loc)
|
||||
reagents.trans_to(P, 50)
|
||||
else if(href_list["change_pill"])
|
||||
#define MAX_PILL_SPRITE 20 //max icon state of the pill sprites
|
||||
var/dat = "<table>"
|
||||
var/j = 0
|
||||
for(var/i = 1 to MAX_PILL_SPRITE)
|
||||
j++
|
||||
if(j == 1)
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href=\"?src=[UID()]&pill_sprite=[i]\"><img src=\"pill[i].png\" /></a></td>"
|
||||
if(j == 5)
|
||||
dat += "</tr>"
|
||||
j = 0
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=chem_master_iconsel;size=225x193")
|
||||
return
|
||||
else if(href_list["change_bottle"])
|
||||
var/dat = "<table>"
|
||||
var/j = 0
|
||||
for(var/i in list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle"))
|
||||
j++
|
||||
if(j == 1)
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href=\"?src=[UID()]&bottle_sprite=[i]\"><img src=\"[i].png\" /></a></td>"
|
||||
if(j == 5)
|
||||
dat += "</tr>"
|
||||
j = 0
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=chem_master_iconsel;size=225x193")
|
||||
return
|
||||
else if(href_list["pill_sprite"])
|
||||
pillsprite = href_list["pill_sprite"]
|
||||
usr << browse(null, "window=chem_master_iconsel")
|
||||
else if(href_list["bottle_sprite"])
|
||||
bottlesprite = href_list["bottle_sprite"]
|
||||
usr << browse(null, "window=chem_master_iconsel")
|
||||
|
||||
SSnanoui.update_uis(src)
|
||||
reagents.remove_reagent(id, amount)
|
||||
if("eject")
|
||||
if(!beaker)
|
||||
return
|
||||
beaker.forceMove(get_turf(src))
|
||||
if(Adjacent(usr) && !issilicon(usr))
|
||||
usr.put_in_hands(beaker)
|
||||
beaker = null
|
||||
reagents.clear_reagents()
|
||||
update_icon()
|
||||
if("create_condi_bottle")
|
||||
if(!condi || !reagents.total_volume)
|
||||
return
|
||||
var/obj/item/reagent_containers/food/condiment/P = new(loc)
|
||||
reagents.trans_to(P, 50)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/chem_master/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/chem_master/attack_ghost(mob/user)
|
||||
if(user.can_admin_interact())
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_master/attack_hand(mob/user)
|
||||
if(..())
|
||||
return TRUE
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = TRUE)
|
||||
/obj/machinery/chem_master/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
var/datum/asset/chem_master/assets = get_asset_datum(/datum/asset/chem_master)
|
||||
assets.send(user)
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "chem_master.tmpl", name, 575, 500)
|
||||
ui = new(user, src, ui_key, "ChemMaster", name, 575, 500)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_master/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/chem_master/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["condi"] = condi
|
||||
data["loaded_pill_bottle"] = (loaded_pill_bottle ? 1 : 0)
|
||||
data["loaded_pill_bottle"] = loaded_pill_bottle ? TRUE : FALSE
|
||||
if(loaded_pill_bottle)
|
||||
data["loaded_pill_bottle_name"] = loaded_pill_bottle.name
|
||||
data["loaded_pill_bottle_contents_len"] = loaded_pill_bottle.contents.len
|
||||
data["loaded_pill_bottle_storage_slots"] = loaded_pill_bottle.storage_slots
|
||||
|
||||
data["beaker"] = (beaker ? 1 : 0)
|
||||
data["beaker"] = beaker ? TRUE : FALSE
|
||||
if(beaker)
|
||||
var/list/beaker_reagents_list = list()
|
||||
data["beaker_reagents"] = beaker_reagents_list
|
||||
@@ -464,13 +276,255 @@
|
||||
data["buffer_reagents"] = buffer_reagents_list
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
buffer_reagents_list[++buffer_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "id" = R.id, "description" = R.description)
|
||||
else
|
||||
data["beaker_reagents"] = list()
|
||||
data["buffer_reagents"] = list()
|
||||
|
||||
data["pillsprite"] = pillsprite
|
||||
data["bottlesprite"] = bottlesprite
|
||||
data["mode"] = mode
|
||||
data["printing"] = printing
|
||||
|
||||
// Transfer modal information if there is one
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
|
||||
return data
|
||||
|
||||
/**
|
||||
* Called in tgui_act() to process modal actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The action passed by tgui
|
||||
* * params - The params passed by tgui
|
||||
*/
|
||||
/obj/machinery/chem_master/proc/tgui_act_modal(action, params, datum/tgui/ui, datum/tgui_state/state)
|
||||
. = TRUE
|
||||
var/id = params["id"] // The modal's ID
|
||||
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_OPEN)
|
||||
switch(id)
|
||||
if("analyze")
|
||||
var/idx = text2num(arguments["idx"]) || 0
|
||||
var/from_beaker = text2num(arguments["beaker"]) || FALSE
|
||||
var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
|
||||
if(idx < 1 || idx > length(reagent_list))
|
||||
return
|
||||
|
||||
var/datum/reagent/R = reagent_list[idx]
|
||||
var/list/result = list("idx" = idx, "name" = R.name, "desc" = R.description)
|
||||
if(!condi && istype(R, /datum/reagent/blood))
|
||||
var/datum/reagent/blood/B = R
|
||||
result["blood_type"] = B.data["blood_type"]
|
||||
result["blood_dna"] = B.data["blood_DNA"]
|
||||
|
||||
arguments["analysis"] = result
|
||||
tgui_modal_message(src, id, "", null, arguments)
|
||||
if("change_pill_bottle_style")
|
||||
if(!loaded_pill_bottle)
|
||||
return
|
||||
if(!pill_bottle_wrappers)
|
||||
pill_bottle_wrappers = list(
|
||||
"CLEAR" = "Default",
|
||||
COLOR_RED = "Red",
|
||||
COLOR_GREEN = "Green",
|
||||
COLOR_PALE_BTL_GREEN = "Pale green",
|
||||
COLOR_BLUE = "Blue",
|
||||
COLOR_CYAN_BLUE = "Light blue",
|
||||
COLOR_TEAL = "Teal",
|
||||
COLOR_YELLOW = "Yellow",
|
||||
COLOR_ORANGE = "Orange",
|
||||
COLOR_PINK = "Pink",
|
||||
COLOR_MAROON = "Brown"
|
||||
)
|
||||
var/current = pill_bottle_wrappers[loaded_pill_bottle.wrapper_color] || "Default"
|
||||
tgui_modal_choice(src, id, "Please select a pill bottle wrapper:", null, arguments, current, pill_bottle_wrappers)
|
||||
if("addcustom")
|
||||
if(!beaker || !beaker.reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please enter the amount to transfer to buffer:", null, arguments, useramount)
|
||||
if("removecustom")
|
||||
if(!reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please enter the amount to transfer to [mode ? "beaker" : "disposal"]:", null, arguments, useramount)
|
||||
if("create_condi_pack")
|
||||
if(!condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please name your new condiment pack:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN)
|
||||
if("create_pill")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
var/num = round(text2num(arguments["num"] || 1))
|
||||
if(!num)
|
||||
return
|
||||
arguments["num"] = num
|
||||
var/amount_per_pill = clamp(reagents.total_volume / num, 0, MAX_UNITS_PER_PILL)
|
||||
var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_pill]u)"
|
||||
var/pills_text = num == 1 ? "new pill" : "[num] new pills"
|
||||
tgui_modal_input(src, id, "Please name your [pills_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
|
||||
if("create_pill_multiple")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please enter the amount of pills to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
|
||||
if("change_pill_style")
|
||||
var/list/choices = list()
|
||||
for(var/i = 1 to MAX_PILL_SPRITE)
|
||||
choices += "pill[i].png"
|
||||
tgui_modal_bento(src, id, "Please select the new style for pills:", null, arguments, pillsprite, choices)
|
||||
if("create_patch")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
var/num = round(text2num(arguments["num"] || 1))
|
||||
if(!num)
|
||||
return
|
||||
arguments["num"] = num
|
||||
var/amount_per_patch = clamp(reagents.total_volume / num, 0, MAX_UNITS_PER_PATCH)
|
||||
var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_patch]u)"
|
||||
var/patches_text = num == 1 ? "new patch" : "[num] new patches"
|
||||
tgui_modal_input(src, id, "Please name your [patches_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
|
||||
if("create_patch_multiple")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please enter the amount of patches to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
|
||||
if("create_bottle")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please name your bottle:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN)
|
||||
if("change_bottle_style")
|
||||
if(!bottle_styles)
|
||||
bottle_styles = list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle")
|
||||
var/list/bottle_styles_png = list()
|
||||
for(var/style in bottle_styles)
|
||||
bottle_styles_png += "[style].png"
|
||||
tgui_modal_bento(src, id, "Please select the new style for bottles:", null, arguments, bottlesprite, bottle_styles_png)
|
||||
else
|
||||
return FALSE
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
var/answer = params["answer"]
|
||||
switch(id)
|
||||
if("change_pill_bottle_style")
|
||||
if(!pill_bottle_wrappers || !loaded_pill_bottle) // wat?
|
||||
return
|
||||
var/color = "CLEAR"
|
||||
for(var/col in pill_bottle_wrappers)
|
||||
var/col_name = pill_bottle_wrappers[col]
|
||||
if(col_name == answer)
|
||||
color = col
|
||||
break
|
||||
if(length(color) && color != "CLEAR")
|
||||
loaded_pill_bottle.wrapper_color = color
|
||||
loaded_pill_bottle.apply_wrap()
|
||||
else
|
||||
loaded_pill_bottle.wrapper_color = null
|
||||
loaded_pill_bottle.cut_overlays()
|
||||
if("addcustom")
|
||||
var/amount = isgoodnumber(text2num(answer))
|
||||
if(!amount || !arguments["id"])
|
||||
return
|
||||
tgui_act("add", list("id" = arguments["id"], "amount" = amount), ui, state)
|
||||
if("removecustom")
|
||||
var/amount = isgoodnumber(text2num(answer))
|
||||
if(!amount || !arguments["id"])
|
||||
return
|
||||
tgui_act("remove", list("id" = arguments["id"], "amount" = amount), ui, state)
|
||||
if("create_condi_pack")
|
||||
if(!condi || !reagents.total_volume)
|
||||
return
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/obj/item/reagent_containers/food/condiment/pack/P = new(loc)
|
||||
P.originalname = answer
|
||||
P.name = "[answer] pack"
|
||||
P.desc = "A small condiment pack. The label says it contains [answer]."
|
||||
reagents.trans_to(P, 10)
|
||||
if("create_pill")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
var/count = clamp(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
|
||||
if(!count)
|
||||
return
|
||||
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/amount_per_pill = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_PILL)
|
||||
while(count--)
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(usr, "<span class='notice'>Not enough reagents to create these pills!</span>")
|
||||
return
|
||||
|
||||
var/obj/item/reagent_containers/food/pill/P = new(loc)
|
||||
P.name = "[answer] pill"
|
||||
P.pixel_x = rand(-7, 7) // Random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = "pill[pillsprite]"
|
||||
reagents.trans_to(P, amount_per_pill)
|
||||
// Load the pills in the bottle if there's one loaded
|
||||
if(istype(loaded_pill_bottle) && length(loaded_pill_bottle.contents) < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
if("create_pill_multiple")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_act("modal_open", list("id" = "create_pill", "arguments" = list("num" = answer)), ui, state)
|
||||
if("change_pill_style")
|
||||
var/new_style = clamp(text2num(answer) || 0, 0, MAX_PILL_SPRITE)
|
||||
if(!new_style)
|
||||
return
|
||||
pillsprite = new_style
|
||||
if("create_patch")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
var/count = clamp(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
|
||||
if(!count)
|
||||
return
|
||||
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/amount_per_patch = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_PATCH)
|
||||
var/is_medical_patch = chemical_safety_check(reagents)
|
||||
while(count--)
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(usr, "<span class='notice'>Not enough reagents to create these patches!</span>")
|
||||
return
|
||||
|
||||
var/obj/item/reagent_containers/food/pill/patch/P = new(loc)
|
||||
P.name = "[answer] patch"
|
||||
P.pixel_x = rand(-7, 7) // random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
reagents.trans_to(P, amount_per_patch)
|
||||
if(is_medical_patch)
|
||||
P.instant_application = TRUE
|
||||
P.icon_state = "bandaid_med"
|
||||
// Load the patches in the bottle if there's one loaded
|
||||
if(istype(loaded_pill_bottle, /obj/item/storage/pill_bottle/patch_pack) && length(loaded_pill_bottle.contents) < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
if("create_patch_multiple")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_act("modal_open", list("id" = "create_patch", "arguments" = list("num" = answer)), ui, state)
|
||||
if("create_bottle")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/obj/item/reagent_containers/glass/bottle/reagent/P = new(loc)
|
||||
P.name = "[answer] bottle"
|
||||
P.pixel_x = rand(-7, 7) // random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = length(bottle_styles) && bottle_styles[bottlesprite] || "bottle"
|
||||
reagents.trans_to(P, 50)
|
||||
if("change_bottle_style")
|
||||
if(!bottle_styles)
|
||||
return
|
||||
var/new_sprite = text2num(answer) || 1
|
||||
if(new_sprite < 1 || new_sprite > length(bottle_styles))
|
||||
return
|
||||
bottlesprite = new_sprite
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/chem_master/proc/isgoodnumber(num)
|
||||
if(isnum(num))
|
||||
if(num > 200)
|
||||
@@ -481,7 +535,7 @@
|
||||
num = round(num)
|
||||
return num
|
||||
else
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/chem_master/proc/chemical_safety_check(datum/reagents/R)
|
||||
var/all_safe = TRUE
|
||||
@@ -503,3 +557,9 @@
|
||||
component_parts += new /obj/item/reagent_containers/glass/beaker(null)
|
||||
component_parts += new /obj/item/reagent_containers/glass/beaker(null)
|
||||
RefreshParts()
|
||||
|
||||
#undef MAX_PILL_SPRITE
|
||||
#undef MAX_MULTI_AMOUNT
|
||||
#undef MAX_UNITS_PER_PILL
|
||||
#undef MAX_UNITS_PER_PATCH
|
||||
#undef MAX_CUSTOM_NAME_LEN
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* tgui modals
|
||||
*
|
||||
* Allows creation of modals within tgui.
|
||||
*/
|
||||
|
||||
GLOBAL_LIST(tgui_modals)
|
||||
|
||||
/**
|
||||
* Call this from a proc that is called in tgui_act() to process modal actions
|
||||
*
|
||||
* Example: /obj/machinery/chem_master/proc/tgui_act_modal
|
||||
* You can then switch based on the return value and show different
|
||||
* modals depending on the answer.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * action - The called action
|
||||
* * params - The params to the action
|
||||
*/
|
||||
/datum/proc/tgui_modal_act(datum/source = src, action = "", params)
|
||||
ASSERT(istype(source))
|
||||
|
||||
. = null
|
||||
switch(action)
|
||||
if("modal_open") // Params: id, arguments
|
||||
return TGUI_MODAL_OPEN
|
||||
if("modal_answer") // Params: id, answer, arguments
|
||||
params["answer"] = tgui_modal_preprocess_answer(source, params["answer"])
|
||||
if(tgui_modal_answer(source, params["id"], params["answer"])) // If there's a current modal with a delegate that returned TRUE, no need to continue
|
||||
. = TGUI_MODAL_DELEGATE
|
||||
else
|
||||
. = TGUI_MODAL_ANSWER
|
||||
tgui_modal_clear(source)
|
||||
if("modal_close") // Params: id
|
||||
tgui_modal_clear(source)
|
||||
return TGUI_MODAL_CLOSE
|
||||
|
||||
/**
|
||||
* Call this from tgui_data() to return modal information if needed
|
||||
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
*/
|
||||
/datum/proc/tgui_modal_data(datum/source = src)
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, source.UID())
|
||||
if(!current)
|
||||
return null
|
||||
|
||||
return current.to_data()
|
||||
|
||||
/**
|
||||
* Clears the current modal for a given datum
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
*/
|
||||
/datum/proc/tgui_modal_clear(datum/source = src)
|
||||
ASSERT(istype(source))
|
||||
|
||||
LAZYINITLIST(GLOB.tgui_modals)
|
||||
var/datum/tgui_modal/previous = GLOB.tgui_modals[source.UID()]
|
||||
if(!previous)
|
||||
return FALSE
|
||||
|
||||
for(var/i in 1 to length(GLOB.tgui_modals))
|
||||
var/key = GLOB.tgui_modals[i]
|
||||
if(previous == GLOB.tgui_modals[key])
|
||||
GLOB.tgui_modals.Cut(i, i + 1)
|
||||
break
|
||||
|
||||
SStgui.update_uis(source)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Opens a message TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when closed
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
*/
|
||||
/datum/proc/tgui_modal_message(datum/source = src, id, text = "Default modal message", delegate, arguments)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/modal = new(id, text, delegate, arguments)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a text input TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the input
|
||||
* * max_length - The maximum char length of the input
|
||||
*/
|
||||
/datum/proc/tgui_modal_input(datum/source = src, id, text = "Default modal message", delegate, arguments, value = "", max_length = TGUI_MODAL_INPUT_MAX_LENGTH)
|
||||
ASSERT(length(id))
|
||||
ASSERT(max_length > 0)
|
||||
|
||||
var/datum/tgui_modal/input/modal = new(id, text, delegate, arguments, value, max_length)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a dropdown input TGUI modal
|
||||
*
|
||||
* Internally checks if the answer is in the list of choices.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the dropdown
|
||||
* * choices - The list of available choices in the dropdown
|
||||
*/
|
||||
/datum/proc/tgui_modal_choice(datum/source = src, id, text = "Default modal message", delegate, arguments, value = "", choices)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/input/choice/modal = new(id, text, delegate, arguments, value, choices)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a bento input TGUI modal
|
||||
*
|
||||
* Internally checks if the answer is in the list of choices.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the bento
|
||||
* * choices - The list of available choices in the bento
|
||||
*/
|
||||
/datum/proc/tgui_modal_bento(datum/source = src, id, text = "Default modal message", delegate, arguments, value, choices)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/input/bento/modal = new(id, text, delegate, arguments, value, choices)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a yes/no TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when "Yes" is pressed
|
||||
* * delegate_no - The proc to call when "No" is pressed
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * yes_text - The text to show in the "Yes" button
|
||||
* * no_text - The text to show in the "No" button
|
||||
*/
|
||||
/datum/proc/tgui_modal_boolean(datum/source = src, id, text = "Default modal message", delegate, delegate_no, arguments, yes_text = "Yes", no_text = "No")
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/boolean/modal = new(id, text, delegate, delegate_no, arguments, yes_text, no_text)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Registers a given modal to a source. Private.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * modal - The datum/tgui_modal to register
|
||||
* * replace_previous - Whether any modal currently assigned to source should be replaced
|
||||
* * instant_update - Whether the changes should reflect immediately
|
||||
*/
|
||||
/datum/proc/tgui_modal_new(datum/source = src, datum/tgui_modal/modal = null, replace_previous = TRUE, instant_update = TRUE)
|
||||
ASSERT(istype(source))
|
||||
ASSERT(istype(modal))
|
||||
|
||||
var/datum/tgui_modal/previous = LAZYACCESS(GLOB.tgui_modals, source.UID())
|
||||
if(previous && !replace_previous)
|
||||
return FALSE
|
||||
|
||||
modal.owning_source = source
|
||||
|
||||
// Previous one should get GC'd
|
||||
LAZYSET(GLOB.tgui_modals, source.UID(), modal)
|
||||
if(instant_update)
|
||||
SStgui.update_uis(source)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Calls the source's currently assigned modal's (if there is one) on_answer() proc. Private.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * answer - The provided answer
|
||||
*/
|
||||
/datum/proc/tgui_modal_answer(datum/source = src, id, answer = "")
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, source.UID())
|
||||
if(!current)
|
||||
return FALSE
|
||||
|
||||
return current.on_answer(answer)
|
||||
|
||||
/**
|
||||
* Passes an answer from JS through the modal's proc.
|
||||
*
|
||||
* Used namely for cutting the text short if it's longer
|
||||
* than an input modal's max_length.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * answer - The provided answer
|
||||
*/
|
||||
/datum/proc/tgui_modal_preprocess_answer(datum/source = src, answer = "")
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, source.UID())
|
||||
if(!current)
|
||||
return answer
|
||||
|
||||
return current.preprocess_answer(answer)
|
||||
|
||||
/**
|
||||
* Modal datum (contains base information for a modal)
|
||||
*/
|
||||
/datum/tgui_modal
|
||||
var/datum/owning_source
|
||||
var/id
|
||||
var/text
|
||||
var/delegate
|
||||
var/list/arguments
|
||||
var/modal_type = "message"
|
||||
|
||||
/datum/tgui_modal/New(id, text, delegate, list/arguments)
|
||||
src.id = id
|
||||
src.text = text
|
||||
src.delegate = delegate
|
||||
src.arguments = arguments
|
||||
|
||||
/**
|
||||
* Called when it's time to pre-process the answer before using it
|
||||
*
|
||||
* Arguments:
|
||||
* * answer - The answer, a nullable text
|
||||
*/
|
||||
/datum/tgui_modal/proc/preprocess_answer(answer)
|
||||
return reject_bad_text(answer, TGUI_MODAL_INPUT_MAX_LENGTH) // bleh
|
||||
|
||||
/**
|
||||
* Called when a modal receives an answer
|
||||
*
|
||||
* Arguments:
|
||||
* * answer - The answer, a nullable text
|
||||
*/
|
||||
/datum/tgui_modal/proc/on_answer(answer)
|
||||
if(delegate)
|
||||
return call(owning_source, delegate)(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Creates a list that describes a modal visually to be passed to JS
|
||||
*/
|
||||
/datum/tgui_modal/proc/to_data()
|
||||
. = list()
|
||||
.["id"] = id
|
||||
.["text"] = text
|
||||
.["args"] = arguments || list()
|
||||
.["type"] = modal_type
|
||||
|
||||
/**
|
||||
* Input modal - has a text entry that can be used to enter an answer
|
||||
*/
|
||||
/datum/tgui_modal/input
|
||||
modal_type = "input"
|
||||
var/value
|
||||
var/max_length
|
||||
|
||||
/datum/tgui_modal/input/New(id, text, delegate, list/arguments, value, max_length)
|
||||
..(id, text, delegate, arguments)
|
||||
src.value = value
|
||||
src.max_length = max_length
|
||||
|
||||
/datum/tgui_modal/input/preprocess_answer(answer)
|
||||
. = ..(answer)
|
||||
if(length(answer) > max_length)
|
||||
. = copytext(., 1, max_length + 1)
|
||||
|
||||
/datum/tgui_modal/input/to_data()
|
||||
. = ..()
|
||||
.["value"] = value
|
||||
|
||||
/**
|
||||
* Choice modal - has a dropdown menu that can be used to select an answer
|
||||
*/
|
||||
/datum/tgui_modal/input/choice
|
||||
modal_type = "choice"
|
||||
var/choices
|
||||
|
||||
/datum/tgui_modal/input/choice/New(id, text, delegate, list/arguments, value, choices)
|
||||
..(id, text, delegate, arguments, value, TGUI_MODAL_INPUT_MAX_LENGTH) // Max length doesn't really matter in dropdowns, but whatever
|
||||
src.choices = choices
|
||||
|
||||
/datum/tgui_modal/input/choice/on_answer(answer)
|
||||
if(answer in choices) // Make sure the answer is actually in our choices!
|
||||
return ..(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/input/choice/to_data()
|
||||
. = ..()
|
||||
.["choices"] = choices
|
||||
|
||||
/**
|
||||
* Bento modal - Similar to choice, it displays the choices in a grid of images
|
||||
*
|
||||
* The returned answer is the index of the choice.
|
||||
*/
|
||||
/datum/tgui_modal/input/bento
|
||||
modal_type = "bento"
|
||||
var/choices
|
||||
|
||||
/datum/tgui_modal/input/bento/New(id, text, delegate, list/arguments, value, choices)
|
||||
..(id, text, delegate, arguments, text2num(value), TGUI_MODAL_INPUT_MAX_LENGTH) // Max length doesn't really matter in here, but whatever
|
||||
src.choices = choices
|
||||
|
||||
/datum/tgui_modal/input/bento/preprocess_answer(answer)
|
||||
return text2num(answer) || 0
|
||||
|
||||
/datum/tgui_modal/input/bento/on_answer(answer)
|
||||
if(answer >= 1 && answer <= length(choices)) // Make sure the answer index is actually in our indexes!
|
||||
return ..(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/input/bento/to_data()
|
||||
. = ..()
|
||||
.["choices"] = choices
|
||||
|
||||
/**
|
||||
* Boolean modal - has yes/no buttons that do different actions depending on which is pressed
|
||||
*/
|
||||
/datum/tgui_modal/boolean
|
||||
modal_type = "boolean"
|
||||
var/delegate_no
|
||||
var/yes_text
|
||||
var/no_text
|
||||
|
||||
/datum/tgui_modal/boolean/New(id, text, delegate, delegate_no, list/arguments, yes_text, no_text)
|
||||
..(id, text, delegate, arguments)
|
||||
src.delegate_no = delegate_no
|
||||
src.yes_text = yes_text
|
||||
src.no_text = no_text
|
||||
|
||||
/datum/tgui_modal/boolean/preprocess_answer(answer)
|
||||
return text2num(answer) || FALSE
|
||||
|
||||
/datum/tgui_modal/boolean/on_answer(answer)
|
||||
if(answer)
|
||||
return ..(answer, arguments)
|
||||
else if(delegate_no)
|
||||
return call(owning_source, delegate_no)(arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/boolean/to_data()
|
||||
. = ..()
|
||||
.["yes_text"] = yes_text
|
||||
.["no_text"] = no_text
|
||||
@@ -1,231 +0,0 @@
|
||||
<!--
|
||||
Title: Body Scanner UI
|
||||
Used In File(s): \code\game\machinery\adv_med.dm
|
||||
-->
|
||||
|
||||
{{if !data.occupied}}
|
||||
<h3>No occupant detected.</h3>
|
||||
{{else}}
|
||||
<h4><b>Occupant Data:</b></h4>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Name:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:data.occupant.name}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Health:
|
||||
</div>
|
||||
{{:helper.displayBar(data.occupant.health, -100, 100, (data.occupant.health >= 50) ? 'good' : (data.occupant.health >= 0) ? 'average' : 'bad')}}
|
||||
<div class="itemContent" style="width: 60px">
|
||||
{{:helper.smoothRound(data.occupant.health)}}%
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Status:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.occupant.stat==0}}
|
||||
<span class="good"> Alive </span>
|
||||
{{else data.occupant.stat==1}}
|
||||
<span class="average"> Critical </span>
|
||||
{{else}}
|
||||
<span class="bad"> Dead </span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Temperature:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.smoothRound(data.occupant.bodyTempC)}}°C, {{:helper.smoothRound(data.occupant.bodyTempF)}}°F
|
||||
</div>
|
||||
</div>
|
||||
{{if data.occupant.hasBorer}}
|
||||
<span class="bad">
|
||||
Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended. </span> <br>
|
||||
{{/if}}
|
||||
{{if data.occupant.blind}}
|
||||
<span class="average">Cataracts detected.</span><br>
|
||||
{{/if}}
|
||||
{{if data.occupant.colourblind}}
|
||||
<span class="average">Photoreceptor abnormalities detected.</span><br>
|
||||
{{/if}}
|
||||
{{if data.occupant.nearsighted}}
|
||||
<span class="average">Retinal misalignment detected.</span> <br>
|
||||
{{/if}}
|
||||
|
||||
<br>
|
||||
{{:helper.link('Print', 'print', {'print_p' : 1, 'name' : data.occupant.name})}}
|
||||
{{:helper.link('Eject Occupant', 'arrow-circle-o-down', {'ejectify' : 1}, data.occupied ? null : 'disabled')}}
|
||||
<br> <br>
|
||||
|
||||
<b>Damage: </b>
|
||||
<table> <tbody>
|
||||
<tr>
|
||||
<td> Brute Damage: </td>
|
||||
<td> Brain Damage: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth+100, (data.occupant.bruteLoss < 15) ? 'notgood' : (data.occupant.bruteLoss < 40) ? 'average' : 'bad', data.occupant.bruteLoss) }} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.brainLoss, 0, data.occupant.maxHealth+100, (data.occupant.brainLoss < 15) ? 'notgood' : (data.occupant.brainLoss < 40) ? 'average' : 'bad', data.occupant.brainLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Resp. Damage: </td>
|
||||
<td> Radiation Level: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth+100, (data.occupant.oxyLoss < 15) ? 'notgood' : (data.occupant.oxyLoss < 40) ? 'average' : 'bad', data.occupant.oxyLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.radLoss, 0, data.occupant.maxHealth+100, (data.occupant.radLoss < 15) ? 'notgood' : (data.occupant.radLoss < 40) ? 'average' : 'bad', data.occupant.radLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Toxin Damage: </td>
|
||||
<td> Genetic Damage: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth+100, (data.occupant.toxLoss < 15) ? 'notgood' : (data.occupant.toxLoss < 40) ? 'average' : 'bad', data.occupant.toxLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.cloneLoss, 0, data.occupant.maxHealth+100, (data.occupant.cloneLoss < 15) ? 'notgood' : (data.occupant.cloneLoss < 40) ? 'average' : 'bad', data.occupant.cloneLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Burn Severity: </td>
|
||||
<td> Paralysis %: ({{:helper.smoothRound(data.occupant.paralysisSeconds)}} seconds left) </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth+100, (data.occupant.fireLoss < 15) ? 'notgood' : (data.occupant.fireLoss < 40) ? 'average' : 'bad', data.occupant.fireLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.paralysis, 0, 100, (data.occupant.paralysis < 25) ? 'notgood' : (data.occupant.paralysis < 50) ? 'average' : 'bad', data.occupant.paralysis)}} </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{if data.occupant.blood.hasBlood}}
|
||||
<br>
|
||||
<b>Blood:</b>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Pulse:</div> <div class="statusValue">{{:data.occupant.blood.pulse}} bpm</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Level:</div>
|
||||
{{:helper.displayBar(data.occupant.blood.bloodLevel, 0, data.occupant.blood.bloodMax, (data.occupant.blood.percent <= 60) ? 'bad' : (data.occupant.blood.percent <= 90) ? 'average' : 'good' )}}
|
||||
<div class="statusValue"> {{:helper.smoothRound(data.occupant.blood.percent)}}%, {{:helper.smoothRound(data.occupant.blood.bloodLevel)}}cl </div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<br>
|
||||
{{if data.occupant.hasVirus}}
|
||||
<span class="bad">
|
||||
Viral pathogen detected in blood stream.
|
||||
</span> <br>
|
||||
{{/if}}
|
||||
{{if data.occupant.implant_len}}
|
||||
<br>
|
||||
<b>Implants</b>
|
||||
<table style="width: 30%">
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.implant}}
|
||||
<tr><td>{{:value.name}}</td></tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
{{/if}}
|
||||
<b>External Organs</b>
|
||||
<table> <thead>
|
||||
<tr>
|
||||
<th style="width: 25%"> Name </th>
|
||||
<th style='width: 15%'> Total damage </th>
|
||||
<th style="width: 15%"> Brute damage </th>
|
||||
<th style="width: 15%"> Burn damage </th>
|
||||
<th style="width: 30%"> Injuries </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.extOrgan}}
|
||||
<tr>
|
||||
<td> {{:value.name}} </td>
|
||||
<td> {{:helper.displayBar(value.totalLoss, 0, value.maxHealth, (value.totalLoss < value.bruised) ? 'notgood' : (value.totalLoss < value.broken) ? 'average' : 'bad', value.totalLoss) }} </td>
|
||||
<td> {{if value.bruteLoss> 0}} <span class='average'> {{else}} <span> {{/if}} {{:helper.smoothRound(value.bruteLoss)}} </span> </td>
|
||||
<td> {{if value.fireLoss> 0}} <span class='average'> {{else}} <span> {{/if}} {{:helper.smoothRound(value.fireLoss)}} </span> </td>
|
||||
<td>
|
||||
<span class='average'>
|
||||
{{if value.internalBleeding}} internal bleeding <br> {{/if}}
|
||||
{{if value.lungRuptured}} lung ruptured <br> {{/if}}
|
||||
{{if value.status.broken}} {{:value.status.broken}} <br> {{/if}}
|
||||
{{if value.germ_level > 100}}
|
||||
{{if value.germ_level < 300}}
|
||||
mild infection <br>
|
||||
{{else value.germ_level < 400}}
|
||||
mild infection+ <br>
|
||||
{{else value.germ_level < 500}}
|
||||
mild infection++ <br>
|
||||
{{else value.germ_level < 700}}
|
||||
acute infection <br>
|
||||
{{else value.germ_level < 800}}
|
||||
acute infection+ <br>
|
||||
{{else value.germ_level < 900}}
|
||||
acute infection++ <br>
|
||||
{{else value.germ_level >= 900}}
|
||||
septic <br>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if value.open}} open incision <br> {{/if}}
|
||||
</span>
|
||||
{{if value.status.splinted}} splinted <br> {{/if}}
|
||||
{{if value.status.robotic}} robotic <br> {{/if}}
|
||||
{{if value.status.dead}} <span class='bad'>DEAD</span> <br {{/if}}
|
||||
{{if value.shrapnel_len}}
|
||||
{{for value.shrapnel : shrapValue:shrapindex}}
|
||||
{{:shrapValue.known ? shrapValue.name : "unknown object"}} <br>
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<b>Internal Organs</b>
|
||||
<table> <thead>
|
||||
<tr>
|
||||
<th width=25%> Name </th>
|
||||
<th width=35%> Brute damage </th>
|
||||
<th widht=40%> Injuries </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.intOrgan}}
|
||||
<tr>
|
||||
<td> {{:value.name}} <br> </td>
|
||||
<td> {{:helper.displayBar(value.damage, 0, value.maxHealth, (value.damage < value.bruised) ? 'notgood' : (value.damage < value.broken) ? 'average' : 'bad', value.damage) }} </td>
|
||||
<td>
|
||||
<span class="average">
|
||||
{{if value.germ_level > 100}}
|
||||
{{if value.germ_level < 300}}
|
||||
mild infection <br>
|
||||
{{else value.germ_level < 400}}
|
||||
mild infection+ <br>
|
||||
{{else value.germ_level < 500}}
|
||||
mild infection++ <br>
|
||||
{{else value.germ_level < 700}}
|
||||
acute Infection <br>
|
||||
{{else value.germ_level < 800}}
|
||||
acute Infection+ <br>
|
||||
{{else value.germ_level < 900}}
|
||||
acute Infection++ <br>
|
||||
{{else value.germ_level >= 900}}
|
||||
septic <br>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{if value.robotic == 1}} robotic <br> {{/if}}
|
||||
{{if value.robotic == 2}} assisted <br> {{/if}}
|
||||
{{if value.dead}} <span class='bad'>DEAD</span> <br> {{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
@@ -1,93 +0,0 @@
|
||||
<!--
|
||||
Title: Chem Dispenser 5000 UI
|
||||
Used In File(s): \code\modules\reagents\Chemistry-Machinery.dm
|
||||
-->
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Energy:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.displayBar(data.energy, 0, data.maxEnergy, 'good', data.energy + ' Units')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Dispense:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link('1', 'gear', {'amount' : 1}, (data.amount == 1) ? 'selected' : null)}}
|
||||
{{:helper.link('5', 'gear', {'amount' : 5}, (data.amount == 5) ? 'selected' : null)}}
|
||||
{{:helper.link('10', 'gear', {'amount' : 10}, (data.amount == 10) ? 'selected' : null)}}
|
||||
{{:helper.link('20', 'gear', {'amount' : 20}, (data.amount == 20) ? 'selected' : null)}}
|
||||
{{:helper.link('30', 'gear', {'amount' : 30}, (data.amount == 30) ? 'selected' : null)}}
|
||||
{{:helper.link('50', 'gear', {'amount' : 50}, (data.amount == 50) ? 'selected' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 100%;">
|
||||
{{if data.glass}}
|
||||
Drink Dispenser
|
||||
{{else}}
|
||||
Chemical Dispenser
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemContentWide" style="width: 100%;">
|
||||
{{for data.chemicals}}
|
||||
{{:helper.link(value.title, 'arrow-circle-down', value.commands, null, data.glass ? 'fixedLeftWide' : 'fixedLeft')}}
|
||||
{{/for}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
{{if data.glass}}
|
||||
Glass
|
||||
{{else}}
|
||||
Beaker
|
||||
{{/if}} Contents
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.glass ? 'Eject Glass' : 'Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled', 'floatRight')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="statusDisplay" style="min-height: 180px;">
|
||||
<div class="item">
|
||||
<div class="itemContent" style="width: 100%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
{{if data.beakerCurrentVolume}}
|
||||
<span class="floatRight" style="width: 115px;"><b>Dispose:</b></span>
|
||||
{{/if}}
|
||||
<b>Volume: {{:data.beakerCurrentVolume}} / {{:data.beakerMaxVolume}}</b><br>
|
||||
{{for data.beakerContents}}
|
||||
<div style="min-height: 22px;">
|
||||
<div class="floatLeft">
|
||||
<span class="highlight">
|
||||
{{:value.volume}} units of {{:value.name}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="floatRight">
|
||||
{{:helper.link('Isolate', null, {'remove' : value.id, 'removeamount' : -1})}}
|
||||
{{:helper.link('1', null, {'remove' : value.id, 'removeamount' : 1})}}
|
||||
{{:helper.link('5', null, {'remove' : value.id, 'removeamount' : 5})}}
|
||||
{{:helper.link('10', null, {'remove' : value.id, 'removeamount' : 10})}}
|
||||
{{:helper.link('ALL', null, {'remove' : value.id, 'removeamount' : value.volume})}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:2px"></div> <!-- This is necessary to prevent the link margins from hitting each other and causing weird things to happen. It's essentialy a smaller <br> tag. -->
|
||||
{{empty}}
|
||||
<span class="bad">{{if data.glass}}Glass{{else}}Beaker{{/if}} is empty
|
||||
</span>
|
||||
{{/for}}
|
||||
{{else}}
|
||||
<span class="average"><i>
|
||||
No {{if data.glass}}Glass{{else}}Beaker{{/if}} loaded
|
||||
</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,47 +0,0 @@
|
||||
<!--
|
||||
Title: ChemHeater UI
|
||||
Used In File(s): \code\modules\reagents\newchem\chem_heater.dm
|
||||
-->
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Status:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.isActive ? 'On' : 'Off', 'power-off', {'toggle_on' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Target:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.targetTemp + 'K', 'gear', {'adjust_temperature' : 'input'}, null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Beaker
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link('Eject', 'eject', {'eject_beaker' : 1}, data.isBeakerLoaded ? null : 'disabled', 'floatRight')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="statusDisplay">
|
||||
<div style="height: 110px; overflow: auto;">
|
||||
<div class="item">
|
||||
<div class="itemContent">
|
||||
<div style="width: 100%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
<b>Volume: {{:helper.smoothRound(data.beakerCurrentVolume)}} / {{:data.beakerMaxVolume}}</b><br>
|
||||
<b>Temperature: {{:helper.smoothRound(data.currentTemp)}} Kelvin</b><br>
|
||||
{{for data.beakerContents}}
|
||||
<span class="highlight">{{:value.volume}} units of {{:value.name}}</span><br>
|
||||
{{/for}}
|
||||
{{else}}
|
||||
<span class="average"><i>No beaker loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,106 +0,0 @@
|
||||
{{if data.beaker}}
|
||||
<div class='item'>{{:helper.link('Eject Beaker and Clear Buffer', 'eject', {'eject': 1})}}</div>
|
||||
<div class='statusDisplay'>
|
||||
<h3>Add to buffer:</h3>
|
||||
{{for data.beaker_reagents}}
|
||||
<div class='line'>
|
||||
<div class='itemLabel'>{{:value.name}}, {{:value.volume}} units</div>
|
||||
{{:helper.link('Analyze', 'search', {'analyze': 1, 'desc': value.description, 'name': value.name})}}
|
||||
{{:helper.link('1', 'plus', {'add': value.id, 'amount': 1})}}
|
||||
{{:helper.link('5', 'plus', {'add': value.id, 'amount': 5})}}
|
||||
{{:helper.link('10', 'plus', {'add': value.id, 'amount': 10})}}
|
||||
{{:helper.link('All', 'plus', {'add': value.id, 'amount': value.volume})}}
|
||||
{{:helper.link('Custom', 'plus', {'addcustom': value.id})}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
<div class='statusDisplay'>
|
||||
<h3>
|
||||
<div class='item'>
|
||||
Transfer to {{:helper.link(data.mode ? 'beaker' : 'disposal', 'arrows-h', {'toggle': 1})}}
|
||||
</div>
|
||||
</h3>
|
||||
{{for data.buffer_reagents}}
|
||||
<div class='line'>
|
||||
<div class='itemLabel'>{{:value.name}}, {{:value.volume}} units</div>
|
||||
{{:helper.link('Analyze', 'search', {'analyze': 1, 'desc': value.description, 'name': value.name})}}
|
||||
{{:helper.link('1', 'plus', {'remove': value.id, 'amount': 1})}}
|
||||
{{:helper.link('5', 'plus', {'remove': value.id, 'amount': 5})}}
|
||||
{{:helper.link('10', 'plus', {'remove': value.id, 'amount': 10})}}
|
||||
{{:helper.link('All', 'plus', {'remove': value.id, 'amount': value.volume})}}
|
||||
{{:helper.link('Custom', 'plus', {'removecustom': value.id})}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
<div class='statusDisplay'>
|
||||
<h3>Containers:</h3>
|
||||
<div class='item'>
|
||||
{{if data.condi}}
|
||||
{{:helper.link('Create pack (10u max)', 'arrow-right', {'createpill': 1})}}
|
||||
{{:helper.link('Create bottle (50u max)', 'arrow-right', {'createbottle': 1})}}
|
||||
{{else}}
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('Create pill (100u max)', 'arrow-right', {'createpill': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Multiple', 'arrow-right', {'createpill_multiple': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Style', 'pencil', {'change_pill': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
<img src='pill{{:data.pillsprite}}.png'>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('Create patch (30u max)', 'arrow-right', {'createpatch': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Multiple', 'arrow-right', {'createpatch_multiple': 1})}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('Create bottle (50u max)', 'arrow-right', {'createbottle': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Style', 'pencil', {'change_bottle': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
<img src='{{:data.bottlesprite}}.png'>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<span class='item'>No beaker loaded</span><br>
|
||||
{{/if}}
|
||||
<div class='statusDisplay'>
|
||||
<span class='item'>
|
||||
{{if data.loaded_pill_bottle}}
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('Pill Bottle (' + data.loaded_pill_bottle_contents_len + '/' + data.loaded_pill_bottle_storage_slots + ')', 'eject', {'ejectp': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Change Wrapper', 'pencil', {'change_pillbottle': 1})}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{else}}
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('No Pill Bottle', 'eject', {}, 'disabled')}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
@@ -1,148 +0,0 @@
|
||||
<!--
|
||||
Title: Cloning Console UI
|
||||
Used In File(s): \code\game\machinery\computer\cloning.dm
|
||||
-->
|
||||
<div class="block">
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Menu</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Main', 'home', {'menu' : 1}, data.menu == 1 ? 'selected' : '')}}{{:helper.link('Records', 'folder-open', {'menu' : 2}, data.menu == 2 ? 'selected' : '')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Refresh</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Refresh', 'refresh', {'refresh' : 1})}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Autoprocessing</div>
|
||||
<div class="itemContentWide">
|
||||
{{if data.autoallowed}}
|
||||
{{:helper.link('Enabled', 'check', {'task' : 'autoprocess'}, data.autoprocess ? 'selected' : '')}}{{:helper.link('Disabled', 'close', {'task' : 'stopautoprocess'}, !data.autoprocess ? 'selected' : '')}}
|
||||
{{else}}
|
||||
{{:helper.link('Enabled', 'check', null, 'disabled')}}{{:helper.link('Disabled', 'close', null, 'selected')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{if data.disk}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Disk</div>
|
||||
<div class="itemContentWide">{{:helper.link('Eject', 'eject', {'disk' : 'eject'})}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{if data.menu == 1}}
|
||||
<h2>Modules</h2>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Scanner</div>
|
||||
<div class="itemContentWide{{if data.scanner}} good{{else}} bad{{/if}}">
|
||||
{{if data.scanner}} Found!{{else}} Error: Not detected!{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Pods</div>
|
||||
<div class="itemContentWide{{if data.numberofpods}} good{{else}} bad{{/if}}">
|
||||
{{if data.numberofpods}} Found {{:data.numberofpods}}!{{else}} Error: None detected!{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{if data.scanner}}
|
||||
<h2>Scanner Functions</h2>
|
||||
{{if data.loading}}
|
||||
<b>Scanning...</b>
|
||||
{{else}}
|
||||
<b>{{:data.scantemp}}</b>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Scan Occupant</div>
|
||||
<div class="itemContentWide">{{:helper.link('Scan', 'search', {'scan' : 1}, !data.occupant ? 'disabled' : '')}}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Scanner Lock</div>
|
||||
<div class="itemContentWide">{{if data.occupant}}{{:helper.link('Engaged', 'lock', {'lock' : 1}, data.locked ? 'selected' : '')}}{{else}} {{:helper.link('Engaged', 'lock', null, 'disabled')}}{{/if}}{{:helper.link('Disengaged', 'unlock', {'lock' : 1}, !data.locked ? 'selected' : '')}}</div>
|
||||
</div>
|
||||
{{if data.can_brainscan}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Scan Mode</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Brain', null, {'toggle_mode' : 1}, !data.scan_mode ? '' : 'selected')}}{{:helper.link('Body', null, {'toggle_mode' : 1}, data.scan_mode ? '' : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if data.numberofpods}}
|
||||
<h2>Pods</h2>
|
||||
{{for data.pods}}
|
||||
<b>{{:value.name}}</b></br>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Biomass</div>
|
||||
<div class="itemContentWide{{if value.biomass > 0}} good{{else}} bad{{/if}}">
|
||||
{{:value.biomass}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Select</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Select', 'check', {'selectpod' : value.pod}, value.pod == data.selected_pod ? 'selected' : '')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if data.menu == 2}}
|
||||
<h2>Current Records</h2>
|
||||
{{if data.temp}}
|
||||
<div class="item">
|
||||
{{:data.temp}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{for data.records}}
|
||||
<div>{{:helper.link(value.realname, 'arrow-circle-down', {'view_rec' : value.record})}}</div>
|
||||
{{empty}}
|
||||
No records found!
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
{{if data.menu == 3}}
|
||||
<h2>Selected Record</h2>
|
||||
{{if data.temp}}
|
||||
<div class="item">
|
||||
{{:data.temp}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{if !data.activerecord}}
|
||||
<div class="bad">Error: Record not found!</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<b>Real Name:</b> {{:data.realname}}<br />
|
||||
<b>Health:</b> {{:data.health}} (<span class="oxyloss_light">OXY</span> - <span class="burn">BURN</span> - <span class="toxin_light">TOX</span> - <span class="brute">BRUTE</span>)
|
||||
</div>
|
||||
<div class="item">
|
||||
<b>UI:</b> {{:data.unidentity}}<br />
|
||||
<b>SE:</b> <div style="word-wrap: break-word;">{{:data.strucenzymes}}</div>
|
||||
</div>
|
||||
{{if data.disk}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Disk</div>
|
||||
<div class="itemContentWide">{{:helper.link('Load from Disk', 'floppy-o', {'disk' : 'load'})}}{{:helper.link('Save UI + UE', 'arrow-circle-up', {'save_disk' : 'ue'})}}{{:helper.link('Save UI', 'arrow-circle-up', {'save_disk' : 'ui'})}}{{:helper.link('Save SE', 'arrow-circle-up', {'save_disk' : 'se'})}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Actions</div>
|
||||
<div class="itemContentWide">{{:helper.link('Clone', 'arrow-right', {'clone' : data.activerecord}, !data.podready ? 'disabled' : '')}}{{:helper.link('Delete', 'trash', {'del_rec' : 1})}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if data.menu == 4}}
|
||||
<h2>Confirm Record Deletion</h2>
|
||||
{{if data.temp}}
|
||||
<div class="item">
|
||||
{{:data.temp}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
{{:helper.link('Scan Card and Confirm', 'trash', {'del_rec' : 1})}}{{:helper.link('Cancel', 'close', {'menu' : 3})}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
<!--
|
||||
Title: Cryo Cell Status UI
|
||||
Used In File(s): \code\game\machinery\cryo.dm
|
||||
-->
|
||||
<h3>Cryo Cell Status</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">Cell Unoccupied</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} <i class="fa fa-arrow-right"></i>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{if data.occupant.stat < 2}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Brute Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.bruteLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Resp. Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.oxyLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Toxin Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.toxLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Burn Severity:</div>
|
||||
{{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.fireLoss)}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<br>
|
||||
<hr>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Cell Temperature:</div><div class="statusValue">
|
||||
<span class="{{:data.cellTemperatureStatus}}">{{:helper.smoothRound(data.cellTemperature)}} K</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Cryo Cell Operation</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Cryo Cell Status:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 40%;">
|
||||
{{:helper.link('On', 'power-off', {'switchOn' : 1}, data.isOperating ? 'selected' : null)}}{{:helper.link('Off', 'close', {'switchOff' : 1}, data.isOperating ? null : 'selected')}}
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Occupant', 'arrow-circle-o-down', {'ejectOccupant' : 1}, data.hasOccupant ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Beaker:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 40%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
{{:data.beakerLabel ? data.beakerLabel : '<span class="average">No label</span>'}}<br>
|
||||
{{if data.beakerVolume}}
|
||||
<span class="highlight">{{:helper.smoothRound(data.beakerVolume)}} units remaining</span><br>
|
||||
{{else}}
|
||||
<span class="bad">Beaker is empty</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="average"><i>No beaker loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 70%">
|
||||
Auto-eject healthy patients:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 30%;">
|
||||
{{:helper.link('On', 'power-off', {'auto_eject_healthy_on' : 1}, data.auto_eject_healthy ? 'selected' : null)}}{{:helper.link('Off', 'close', {'auto_eject_healthy_off' : 0}, data.auto_eject_healthy ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 70%">
|
||||
Auto-eject dead patients:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 30%;">
|
||||
{{:helper.link('On', 'power-off', {'auto_eject_dead_on' : 1}, data.auto_eject_dead ? 'selected' : null)}}{{:helper.link('Off', 'close', {'auto_eject_dead_off' : 0}, data.auto_eject_dead ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,313 +0,0 @@
|
||||
<!--
|
||||
Title: DNA Modifier UI
|
||||
Used In File(s): D:\Development\SS13-BS12\code\game\dna\dna_modifier.dm
|
||||
-->
|
||||
<h3>Status</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">Cell Unoccupied</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} =>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{if !data.occupant.isViableSubject || !data.occupant.uniqueIdentity || !data.occupant.structuralEnzymes}}
|
||||
<div class="notice">
|
||||
The occupant's DNA structure is ruined beyond recognition, please insert a subject with an intact DNA structure.
|
||||
</div>
|
||||
{{else data.occupant.stat < 2}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Radiation:</div>
|
||||
{{:helper.displayBar(data.occupant.radiationLevel, 0, 100, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.radiationLevel)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Unique Enzymes:</div>
|
||||
<div class="statusValue">{{:data.occupant.uniqueEnzymes ? data.occupant.uniqueEnzymes : '<span class="bad">Unknown</span>'}}</div>
|
||||
</div>
|
||||
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<div class="clearBoth"></div>
|
||||
</div>
|
||||
|
||||
<h3>Operations</h3>
|
||||
{{if !data.occupant.isViableSubject || !data.occupant.uniqueIdentity || !data.occupant.structuralEnzymes}}
|
||||
<div class="notice">
|
||||
No operation possible on this subject
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
{{:helper.link('Modify U.I.', 'link', {'selectMenuKey' : 'ui'}, data.selectedMenuKey == 'ui' ? 'selected' : null)}}
|
||||
{{:helper.link('Modify S.E.', 'link', {'selectMenuKey' : 'se'}, data.selectedMenuKey == 'se' ? 'selected' : null)}}
|
||||
{{:helper.link('Transfer Buffers', 'floppy-o', {'selectMenuKey' : 'buffer'}, data.selectedMenuKey == 'buffer' ? 'selected' : null)}}
|
||||
{{:helper.link('Rejuvenators', 'plus', {'selectMenuKey' : 'rejuvenators'}, data.selectedMenuKey == 'rejuvenators' ? 'selected' : null)}}
|
||||
</div>
|
||||
|
||||
<div class="item"> </div>
|
||||
|
||||
{{if !data.selectedMenuKey || data.selectedMenuKey == 'ui'}}
|
||||
<h3>Modify Unique Identifier</h3>
|
||||
{{:helper.displayDNABlocks(data.occupant.uniqueIdentity, data.selectedUIBlock, data.selectedUISubBlock, data.dnaBlockSize, 'UI')}}
|
||||
<div class="clearBoth"></div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Target:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('-', null, {'changeUITarget' : 0}, (data.selectedUITarget > 0) ? null : 'disabled')}}
|
||||
<div class="statusValue"> {{:data.selectedUITargetHex}} </div>
|
||||
{{:helper.link('+', null, {'changeUITarget' : 1}, (data.selectedUITarget < 15) ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Irradiate Block', 'exclamation-circle', {'pulseUIRadiation' : 1}, !data.occupant.isViableSubject ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{else data.selectedMenuKey == 'se'}}
|
||||
<h3>Modify Structural Enzymes</h3>
|
||||
{{:helper.displayDNABlocks(data.occupant.structuralEnzymes, data.selectedSEBlock, data.selectedSESubBlock, data.dnaBlockSize, 'SE')}}
|
||||
<div class="clearBoth"></div>
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Irradiate Block', 'exclamation-circle', {'pulseSERadiation' : 1}, !data.occupant.isViableSubject ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{else data.selectedMenuKey == 'buffer'}}
|
||||
<h3>Transfer Buffers</h3>
|
||||
{{for data.buffers}}
|
||||
<h4>Buffer {{:(index + 1)}}</h4>
|
||||
<div class="itemGroup">
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Load Data:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Subject U.I.', 'link', {'bufferOption' : 'saveUI', 'bufferId' : (index + 1)}, !data.hasOccupant ? 'disabled' : null)}}
|
||||
{{:helper.link('Subject U.I. + U.E.', 'link', {'bufferOption' : 'saveUIAndUE', 'bufferId' : (index + 1)}, !data.hasOccupant ? 'disabled' : null)}}
|
||||
{{:helper.link('Subject S.E.', 'link', {'bufferOption' : 'saveSE', 'bufferId' : (index + 1)}, !data.hasOccupant ? 'disabled' : null)}}
|
||||
{{:helper.link('From Disk', 'floppy-o', {'bufferOption' : 'loadDisk', 'bufferId' : (index + 1)}, (!data.hasDisk || !data.disk.data) ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{if value.data}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Label:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link(value.label, 'file', {'bufferOption' : 'changeLabel', 'bufferId' : (index + 1)})}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Subject:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:value.owner ? value.owner : '<span class="average">Unknown</span>'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Stored Data:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:value.data == 'ui' ? 'Unique Identifiers' : 'Structural Enzymes'}}
|
||||
{{:value.ue ? ' + Unique Enzymes' : ''}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
<span class="highlight">This buffer is empty.</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Options:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Clear', 'trash', {'bufferOption' : 'clear', 'bufferId' : (index + 1)}, !value.data ? 'disabled' : null)}}
|
||||
{{:helper.link('Injector', data.isInjectorReady ? 'pencil' : 'clock-o', {'bufferOption' : 'createInjector', 'bufferId' : (index + 1)}, (!data.isInjectorReady || !value.data) ? 'disabled' : null)}}
|
||||
{{:helper.link('Block Injector', data.isInjectorReady ? 'pencil' : 'clock-o', {'bufferOption' : 'createInjector', 'bufferId' : (index + 1), 'createBlockInjector' : 1}, (!data.isInjectorReady || !value.data) ? 'disabled' : null)}}
|
||||
{{:helper.link('Transfer', 'exclamation-circle', {'bufferOption' : 'transfer', 'bufferId' : (index + 1)}, (!data.hasOccupant || !value.data) ? 'disabled' : null)}}
|
||||
{{:helper.link('Save To Disk', 'floppy-o', {'bufferOption' : 'saveDisk', 'bufferId' : (index + 1)}, (!value.data || !data.hasDisk) ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
|
||||
<h4>Data Disk</h4>
|
||||
<div class="itemGroup">
|
||||
{{if data.hasDisk}}
|
||||
{{if data.disk.data}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Label:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:data.disk.label ? data.disk.label : 'No Label'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Subject:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:data.disk.owner ? data.disk.owner : '<span class="average">Unknown</span>'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Stored Data:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:data.disk.data == 'ui' ? 'Unique Identifiers' : 'Structural Enzymes'}}
|
||||
{{:data.disk.ue ? ' + Unique Enzymes' : ''}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
<span class="average">Disk is blank.</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
<span class="highlight">No disk inserted.</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Options:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Wipe Disk', 'trash', {'bufferOption' : 'wipeDisk'}, (!data.hasDisk || !data.disk.data) ? 'disabled' : null)}}
|
||||
{{:helper.link('Eject Disk', 'eject', {'bufferOption' : 'ejectDisk'}, !data.hasDisk ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else data.selectedMenuKey == 'rejuvenators'}}
|
||||
<h3>Rejuvenators</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Inject:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('5', 'pencil', {'injectRejuvenators' : 5}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
{{:helper.link('10', 'pencil', {'injectRejuvenators' : 10}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
{{:helper.link('20', 'pencil', {'injectRejuvenators' : 20}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
{{:helper.link('30', 'pencil', {'injectRejuvenators' : 30}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
{{:helper.link('50', 'pencil', {'injectRejuvenators' : 50}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Beaker:
|
||||
</div>
|
||||
<div class="itemContentWide" style="width: 40%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
{{:data.beakerLabel ? data.beakerLabel : '<span class="average">No label</span>'}}<br>
|
||||
{{if data.beakerVolume}}
|
||||
<span class="highlight">{{:data.beakerVolume}} units remaining</span><br>
|
||||
{{else}}
|
||||
<span class="bad">Beaker is empty</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="average"><i>No beaker loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemContentWide" style="width: 26%;">
|
||||
{{:helper.link('Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="item"> </div>
|
||||
|
||||
{{if !data.selectedMenuKey || data.selectedMenuKey == 'ui' || data.selectedMenuKey == 'se'}}
|
||||
<h3>Radiation Emitter Settings</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Intensity:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('-', null, {'radiationIntensity' : 0}, (data.radiationIntensity > 1) ? null : 'disabled')}}
|
||||
<div class="statusValue"> {{:data.radiationIntensity}} </div>
|
||||
{{:helper.link('+', null, {'radiationIntensity' : 1}, (data.radiationIntensity < 10) ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Duration:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('-', null, {'radiationDuration' : 0}, (data.radiationDuration > 2) ? null : 'disabled')}}
|
||||
<div class="statusValue"> {{:data.radiationDuration}} </div>
|
||||
{{:helper.link('+', null, {'radiationDuration' : 1}, (data.radiationDuration < 20) ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Pulse Radiation', 'exclamation-circle', {'pulseRadiation' : 1}, !data.hasOccupant ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<div class="item"> </div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Occupant:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Eject Occupant', 'eject', {'ejectOccupant' : 1}, data.locked || !data.hasOccupant || data.irradiating ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Door Lock:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Engaged', 'lock', {'toggleLock' : 1}, data.locked ? 'selected' : !data.hasOccupant ? 'disabled' : null)}}
|
||||
{{:helper.link('Disengaged', 'unlock', {'toggleLock' : 1}, !data.locked ? 'selected' : data.irradiating ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if data.irradiating}}
|
||||
<div class="mask">
|
||||
<div class="maskContent">
|
||||
<h1>Irradiating Subject</h1>
|
||||
<h3>For {{:data.irradiating}} seconds.</h3>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,171 +0,0 @@
|
||||
<!--
|
||||
Title: Medical Records UI
|
||||
Used In File(s): \code\game\machinery\computer\medical.dm
|
||||
-->
|
||||
|
||||
<!--
|
||||
#define MED_DATA_MAIN 1 // Main menu
|
||||
#define MED_DATA_R_LIST 2 // Record list
|
||||
#define MED_DATA_MAINT 3 // Records maintenance
|
||||
#define MED_DATA_RECORD 4 // Record
|
||||
#define MED_DATA_V_DATA 5 // Virus database
|
||||
#define MED_DATA_MEDBOT 6 // Medbot monitor
|
||||
-->
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
<b>Confirm Identity:</b>
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.scan ? data.scan : "----------", 'eject', {'scan' : 1}, null, data.scan ? 'itemContentWide' : 'fixedLeft')}}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{{if data.authenticated}}
|
||||
{{if data.screen == 1}} <!-- MED_DATA_MAIN -->
|
||||
<h3>Menu</h3>
|
||||
<div class="item">
|
||||
<div class="line">{{:helper.link('Search Records', 'search', {'search' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('List Records', 'list', {'screen' : 2})}}</div>
|
||||
<div class="line">{{:helper.link('Virus Database', 'database', {'screen' : 5})}}</div>
|
||||
<div class="line">{{:helper.link('Medbot Tracking', 'plus-square', {'screen' : 6})}}</div>
|
||||
<div class="line">{{:helper.link('Record Maintenance', 'wrench', {'screen' : 3})}}</div>
|
||||
<div class="line">{{:helper.link('Logout', 'lock', {'logout' : 1})}}</div>
|
||||
</div>
|
||||
{{else data.screen == 2}} <!-- MED_DATA_R_LIST -->
|
||||
<h3><center>Record List</center></h3>
|
||||
{{for data.records}}
|
||||
<div class="line">{{:helper.link(value.id + ': ' + value.name, 'user', {'d_rec' : value.ref})}}</div>
|
||||
{{/for}}
|
||||
<br><hr>
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}</div>
|
||||
{{else data.screen == 3}} <!-- MED_DATA_MAINT -->
|
||||
<h3>Records Maintenance</h3>
|
||||
<div class="line">{{:helper.link('Backup To Disk', 'download', {'back' : 1}, 'disabled')}}</div>
|
||||
<div class="line">{{:helper.link('Upload From disk', 'upload', {'u_load' : 1}, 'disabled')}}</div>
|
||||
<div class="line">{{:helper.link('Delete All Records', 'trash', {'del_all' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}</div>
|
||||
{{else data.screen == 4}} <!-- MED_DATA_RECORD -->
|
||||
<h3><center>Medical Record</center></h3>
|
||||
<h4><center>General Data</center></h4>
|
||||
{{if data.general.empty}}
|
||||
<span class="bad"><center>General Record Lost!</center></span>
|
||||
{{else}}
|
||||
<div class="statusDisplayRecords">
|
||||
<table style='width:100%'><tr>
|
||||
<td valign='top' style='margin-right: 300px;'>
|
||||
{{for data.general.fields}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">{{:value.field}}</div>
|
||||
<div class="itemContent">{{:helper.link(value.value, value.edit ? 'pencil' : 'user-times', {'field' : value.edit}, value.edit ? null : 'disabled')}}</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
</td>
|
||||
<td valign='middle' align='center' style='width: 300px;'>
|
||||
{{if data.general.has_photos}}
|
||||
{{for data.general.photos}}
|
||||
{{if value.photo}}
|
||||
<img src={{:value.photo}} height=96 width=96 border=5>
|
||||
{{/if}}
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<h4><center>Medical Data</center></h4>
|
||||
{{if data.medical.empty}}
|
||||
<span class="bad"><center>Medical Record Lost!</center></span>
|
||||
<div style="text-align: center;">
|
||||
<div style="display: inline-block;">{{:helper.link('New Record', 'plus', {'new' : 1})}}</div>
|
||||
</div>
|
||||
<h3><center>Menu</center></h3>
|
||||
{{else}}
|
||||
{{for data.medical.fields}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">{{:value.field}}</div>
|
||||
<div class="itemContent">{{:helper.link(value.value, 'pencil', {'field' : value.edit})}}</div>
|
||||
</div>
|
||||
{{if value.line_break}}
|
||||
<br>
|
||||
{{/if}}
|
||||
{{/for}}
|
||||
|
||||
<h4><center>Comments/Log</center></h4>
|
||||
{{for data.medical.comments}}
|
||||
<div class="line">{{:value}}</div>
|
||||
<div class="line">{{:helper.link('Remove entry', 'trash', {'del_c' : index})}}</div>
|
||||
<br><hr>
|
||||
{{/for}}
|
||||
|
||||
<div style="text-align: center;">
|
||||
<div style="display: inline-block;">{{:helper.link('Add Entry', 'plus', {'add_c' : 1})}}</div>
|
||||
</div>
|
||||
|
||||
<h3><center>Menu</center></h3>
|
||||
<div class="line">{{:helper.link('Delete Record (Medical Only)', 'trash', {'del_r' : 1})}}</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="line">{{:helper.link('Print Record', 'print', {'print_p' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 2})}}</div>
|
||||
{{else data.screen == 5}} <!-- MED_DATA_V_DATA -->
|
||||
<h3><center>Virus Database</center></h3>
|
||||
{{for data.virus}}
|
||||
<div class="line">{{:helper.link(value.name, 'arrow-right', {'vir' : value.D})}}</div>
|
||||
{{/for}}
|
||||
<br><hr>
|
||||
{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}
|
||||
{{else data.screen == 6}} <!-- MED_DATA_MEDBOT -->
|
||||
<h3><center>Medical Robot Monitor</center></h3>
|
||||
{{for data.medbots}}
|
||||
<h4>{{:value.name}}</h4>
|
||||
<div class="item">
|
||||
<div class="itemLabel">Location:</div>
|
||||
<div class="itemContent">{{:value.x}}, {{:value.y}}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">Status:</div>
|
||||
<div class="itemContent">
|
||||
{{:value.on ? "<span class='good'>Online</span>" : "<span class='average'>Offline</span>"}}. {{if value.use_beaker}}Reservoir: [{{:value.total_volume}}/{{:value.maximum_volume}}]{{else}}Using internal synthesizer.{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{{empty}}
|
||||
<h4 class="bad"><center>None detected!</center></h4>
|
||||
{{/for}}
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<h3>Menu</h3>
|
||||
{{:helper.link('Login', 'unlock', {'login' : 1})}}
|
||||
{{/if}}
|
||||
|
||||
{{if data.temp}}
|
||||
<div class="mask" style="display: table;">
|
||||
<div class="maskContent" style="margin: 0px; vertical-align: middle; align:center; display: table-cell;">
|
||||
{{if data.temp.notice}}
|
||||
<div class="notice"><center>{{:data.temp.text}}</center></div>
|
||||
{{else}}
|
||||
<center>{{:data.temp.text}}</center>
|
||||
{{/if}}
|
||||
|
||||
|
||||
{{if data.temp.has_buttons}}
|
||||
<div class="line">
|
||||
<div style="display: inline-block;">
|
||||
<div style="width: 500px; display: flex; display: -webkit-flex; flex-wrap: wrap; -webkit-flex-wrap: wrap; justify-content: center; -webkit-justify-content: center;">
|
||||
{{for data.temp.buttons}}
|
||||
{{:helper.link(value.name, value.icon, {'temp' : 1, 'temp_action' : value.href}, value.status)}}
|
||||
{{/for}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div style="display: inline-block;">
|
||||
<div class="item">{{:helper.link('Clear screen', 'home', {'temp' : 1})}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,215 +0,0 @@
|
||||
<!--
|
||||
Title: Operating Computer UI
|
||||
Used In File(s): \code\game\machinery\computer\Operating.dm
|
||||
-->
|
||||
<h3>Patient Monitor</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if data.choice==0}}
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">No Patient Detected</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} =>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= data.occupant.maxHealth}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else data.occupant.health > 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'average')}}
|
||||
{{else data.occupant.health >= data.minhealth}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'bad alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Brute Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.bruteLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Resp. Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.oxyLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Toxin Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.toxLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Burn Severity:</div>
|
||||
{{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.fireLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Patient Temperature:</div>
|
||||
{{if data.occupant.temperatureSuitability == -3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'bad')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 0}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'good')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'bad')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{if data.occupant.hasBlood}}
|
||||
<br>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Level:</div>
|
||||
{{if data.occupant.bloodPercent <= 60}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'bad')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{else data.occupant.bloodPercent <= 90}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'average')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'good')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Type:</div> <div class="statusValue">{{:data.occupant.bloodType}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Pulse:</div> <div class="statusValue">{{:data.occupant.pulse}} bpm</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{if data.occupant.inSurgery}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Initiated Surgery Procedure:</div> <div class="statusValue">{{:data.occupant.surgeryName}}</div>
|
||||
<br>
|
||||
<div class="statusLabel">Next Step:</div> <div class="statusValue">{{:data.occupant.stepName}}</div>
|
||||
|
||||
</div>
|
||||
{{/if}}
|
||||
<br>
|
||||
<br>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
{{:helper.link('Options', 'gear', {'choiceOn' : 1})}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Loudspeaker:
|
||||
</div>
|
||||
<div class="itemContentNarrow" style="float: left">
|
||||
{{:helper.link('On', 'power-off', {'verboseOn' : 1}, data.verbose ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', {'verboseOff' : 1}, data.verbose ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Health Announcer:
|
||||
</div>
|
||||
<div class="itemContentNarrow" style="float: left">
|
||||
{{:helper.link('On', 'power-off', {'healthOn' : 1}, data.health ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', {'healthOff' : 1}, data.health ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health Announcer Threshold:</div>
|
||||
{{:helper.link('-', null, {'health_adj' : -100}, (data.healthAlarm >= 0) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'health_adj' : -10}, (data.healthAlarm >= -90) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'health_adj' : -1}, (data.healthAlarm > -100) ? null : 'disabled')}}
|
||||
|
||||
{{if data.healthAlarm >= 100}}
|
||||
{{:helper.displayBar(data.healthAlarm, 0, 100, 'good')}}
|
||||
{{else data.healthAlarm > 0}}
|
||||
{{:helper.displayBar(data.healthAlarm, 0, 100, 'average')}}
|
||||
{{else data.healthAlarm >= -100}}
|
||||
{{:helper.displayBar(data.healthAlarm, 0, -100, 'average alignRight')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.healthAlarm, 0, -100, 'bad alignRight')}}
|
||||
{{/if}}
|
||||
|
||||
{{:helper.link('+', null, {'health_adj' : 1}, (data.healthAlarm < 100) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'health_adj' : 10}, (data.healthAlarm <= 90) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'health_adj' : 100}, (data.healthAlarm <= 0) ? null : 'disabled')}}
|
||||
<div style="float: left; width: 80px; text-align: center;"> {{: data.healthAlarm }} </div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Oxygen Alarm:
|
||||
</div>
|
||||
<div class="itemContentNarrow" style="float: left">
|
||||
{{:helper.link('On', 'power-off', {'oxyOn' : 1}, data.oxy ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', {'oxyOff' : 1}, data.oxy ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="line">
|
||||
<div class="statusLabel">Oxygen Alert Threshold:</div>
|
||||
{{:helper.link('-', null, {'oxy_adj' : -100}, (data.oxyAlarm >= 100) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'oxy_adj' : -10}, (data.oxyAlarm >= 10) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'oxy_adj' : -1}, (data.oxyAlarm >= 0) ? null : 'disabled')}}
|
||||
{{:helper.displayBar( data.oxyAlarm, 0, 200, 'good')}}
|
||||
{{:helper.link('+', null, {'oxy_adj' : 1}, (data.oxyAlarm < 200) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'oxy_adj' : 10}, (data.oxyAlarm <= 190) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'oxy_adj' : 100}, (data.oxyAlarm <= 100) ? null : 'disabled')}}
|
||||
<div style="float: left; width: 80px; text-align: center;"> {{: data.oxyAlarm }} </div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Critical Alert:
|
||||
</div>
|
||||
<div class="itemContentNarrow" style="float: left">
|
||||
{{:helper.link('On', 'power-off', {'critOn' : 1}, data.crit ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', {'critOff' : 1}, data.crit ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
{{:helper.link('Return', 'arrow-left', {'choiceOff' : 1})}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
@@ -1,211 +0,0 @@
|
||||
<!--
|
||||
Title: Sleeper Status UI
|
||||
Used In File(s): \code\game\machinery\Sleeper.dm
|
||||
-->
|
||||
<h3>Sleeper Status</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">Sleeper Unoccupied</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} =>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= data.occupant.maxHealth}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else data.occupant.health > 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'average')}}
|
||||
{{else data.occupant.health >= data.minhealth}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'bad alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">=> Brute Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.bruteLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">=> Resp. Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.oxyLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">=> Toxin Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.toxLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">=> Burn Severity:</div>
|
||||
{{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.fireLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="line">
|
||||
<!--
|
||||
<div class="statusLabel">Patient Temperature:</div>
|
||||
{{if data.occupant.temperatureSuitability == -3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'cold3')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'cold2')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'cold1')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 0}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'good')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'hot1')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'hot2')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'hot3')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{/if}}
|
||||
If you can get the changing temperature bars to work right, congratulations
|
||||
-->
|
||||
<div class="statusLabel">Patient Temperature:</div>
|
||||
{{if data.occupant.temperatureSuitability == -3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'bad')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 0}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'good')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'bad')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
||||
{{if data.occupant.hasBlood}}
|
||||
|
||||
<br>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Pulse:</div> <div class="statusValue">{{:data.occupant.pulse}} bpm</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Level:</div>
|
||||
{{if data.occupant.bloodPercent <= 60}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'bad')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{else data.occupant.bloodPercent <= 90}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'average')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'good')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<h3>Sleeper Operation</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Sleeper Status:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Occupant', 'arrow-circle-o-down', {'ejectify' : 1}, data.hasOccupant ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Dialysis Beaker:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 40%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
<span class="highlight">{{:helper.smoothRound(data.beakerFreeSpace)}} units of space remaining</span><br>
|
||||
{{else}}
|
||||
<span class="average"><i>No Dialysis Output Beaker Loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Beaker', 'eject', {'removebeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
{{if data.isBeakerLoaded}}
|
||||
<div class="line">
|
||||
<div class="itemContent">
|
||||
{{:helper.link('On', 'power-off', {'togglefilter' : 1}, data.occupant.hasBlood ? (data.dialysis ? 'selected' : null) : 'disabled')}}{{:helper.link('Off', 'close', {'togglefilter' : 1}, data.dialysis ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Chemicals:
|
||||
</div>
|
||||
|
||||
{{for data.chemicals}}
|
||||
<div class="line"><b>{{:value.title}}</b></div>
|
||||
<div class="line">
|
||||
{{if value.overdosing}}
|
||||
{{:helper.displayBar(value.occ_amount, 0, data.maxchem, 'bad')}}
|
||||
{{else value.od_warning}}
|
||||
{{:helper.displayBar(value.occ_amount, 0, data.maxchem, 'average')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(value.occ_amount, 0, data.maxchem, 'good')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(value.pretty_amount)}}/{{:data.maxchem}}</div>
|
||||
<br>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="itemContent">
|
||||
{{:helper.link('5', 'gear', {'chemical' : value.id, 'amount' : 5}, (!value.injectable || ((value.occ_amount + 5) > data.maxchem)) ? 'disabled' : null)}}
|
||||
{{:helper.link('10', 'gear', {'chemical' : value.id, 'amount' : 10}, (!value.injectable || ((value.occ_amount + 10) > data.maxchem)) ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 35%">
|
||||
Auto-eject dead patients:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 30%">
|
||||
{{:helper.link('On', 'power-off', {'auto_eject_dead_on' : 1}, data.auto_eject_dead ? 'selected' : null)}}{{:helper.link('Off', 'close', {'auto_eject_dead_off' : 0}, data.auto_eject_dead ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#include "code\__DEFINES\station_goals.dm"
|
||||
#include "code\__DEFINES\status_effects.dm"
|
||||
#include "code\__DEFINES\subsystems.dm"
|
||||
#include "code\__DEFINES\tgui.dm"
|
||||
#include "code\__DEFINES\tools.dm"
|
||||
#include "code\__DEFINES\typeids.dm"
|
||||
#include "code\__DEFINES\vv.dm"
|
||||
@@ -2455,6 +2456,7 @@
|
||||
#include "code\modules\telesci\telepad.dm"
|
||||
#include "code\modules\telesci\telesci_computer.dm"
|
||||
#include "code\modules\tgui\external.dm"
|
||||
#include "code\modules\tgui\modal.dm"
|
||||
#include "code\modules\tgui\states.dm"
|
||||
#include "code\modules\tgui\tgui.dm"
|
||||
#include "code\modules\tgui\modules\_base.dm"
|
||||
|
||||
@@ -68,7 +68,10 @@ const mapColorPropTo = attrName => (style, value) => {
|
||||
|
||||
const styleMapperByPropName = {
|
||||
// Direct mapping
|
||||
display: mapRawPropTo('display'),
|
||||
position: mapRawPropTo('position'),
|
||||
float: mapRawPropTo('float'),
|
||||
clear: mapRawPropTo('clear'),
|
||||
overflow: mapRawPropTo('overflow'),
|
||||
overflowX: mapRawPropTo('overflow-x'),
|
||||
overflowY: mapRawPropTo('overflow-y'),
|
||||
@@ -88,6 +91,9 @@ const styleMapperByPropName = {
|
||||
opacity: mapRawPropTo('opacity'),
|
||||
textAlign: mapRawPropTo('text-align'),
|
||||
verticalAlign: mapRawPropTo('vertical-align'),
|
||||
textTransform: mapRawPropTo('text-transform'),
|
||||
wordWrap: mapRawPropTo('word-wrap'),
|
||||
textOverflow: mapRawPropTo('text-overflow'),
|
||||
// Boolean props
|
||||
inline: mapBooleanPropTo('display', 'inline-block'),
|
||||
bold: mapBooleanPropTo('font-weight', 'bold'),
|
||||
@@ -125,6 +131,18 @@ const styleMapperByPropName = {
|
||||
color: mapColorPropTo('color'),
|
||||
textColor: mapColorPropTo('color'),
|
||||
backgroundColor: mapColorPropTo('background-color'),
|
||||
// Flex props
|
||||
order: mapRawPropTo('order'),
|
||||
flexDirection: mapRawPropTo('flex-direction'),
|
||||
flexGrow: mapRawPropTo('flex-grow'),
|
||||
flexShrink: mapRawPropTo('flex-shrink'),
|
||||
flexWrap: mapRawPropTo('flex-wrap'),
|
||||
flexFlow: mapRawPropTo('flex-flow'),
|
||||
flexBasis: mapRawPropTo('flex-basis'),
|
||||
flex: mapRawPropTo('flex'),
|
||||
alignItems: mapRawPropTo('align-items'),
|
||||
justifyContent: mapRawPropTo('justify-content'),
|
||||
alignSelf: mapRawPropTo('align-self'),
|
||||
// Utility props
|
||||
fillPositionedParent: (style, value) => {
|
||||
if (value) {
|
||||
@@ -140,6 +158,9 @@ const styleMapperByPropName = {
|
||||
export const computeBoxProps = props => {
|
||||
const computedProps = {};
|
||||
const computedStyles = {};
|
||||
if (props.double) {
|
||||
computedStyles["transform"] = "scale(2);";
|
||||
}
|
||||
// Compute props
|
||||
for (let propName of Object.keys(props)) {
|
||||
if (propName === 'style') {
|
||||
|
||||
@@ -8,9 +8,11 @@ export const computeFlexProps = props => {
|
||||
direction,
|
||||
wrap,
|
||||
align,
|
||||
alignContent,
|
||||
justify,
|
||||
inline,
|
||||
spacing = 0,
|
||||
spacingPrecise = 0,
|
||||
...rest
|
||||
} = props;
|
||||
return {
|
||||
@@ -23,6 +25,7 @@ export const computeFlexProps = props => {
|
||||
),
|
||||
inline && 'Flex--inline',
|
||||
spacing > 0 && 'Flex--spacing--' + spacing,
|
||||
spacingPrecise > 0 && 'Flex--spacingPrecise--' + spacingPrecise,
|
||||
className,
|
||||
]),
|
||||
style: {
|
||||
@@ -30,6 +33,7 @@ export const computeFlexProps = props => {
|
||||
'flex-direction': direction,
|
||||
'flex-wrap': wrap,
|
||||
'align-items': align,
|
||||
'align-content': alignContent,
|
||||
'justify-content': justify,
|
||||
},
|
||||
...rest,
|
||||
|
||||
@@ -76,6 +76,11 @@ export class Input extends Component {
|
||||
const input = this.inputRef.current;
|
||||
if (input) {
|
||||
input.value = toInputValue(nextValue);
|
||||
if (this.props.autofocus) {
|
||||
input.focus();
|
||||
input.selectionStart = 0;
|
||||
input.selectionEnd = input.value.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +109,7 @@ export class Input extends Component {
|
||||
value,
|
||||
maxLength,
|
||||
placeholder,
|
||||
autofocus,
|
||||
...boxProps
|
||||
} = props;
|
||||
// Box props
|
||||
|
||||
@@ -35,6 +35,7 @@ export const Knob = props => {
|
||||
size,
|
||||
bipolar,
|
||||
children,
|
||||
popUpPosition,
|
||||
...rest
|
||||
} = props;
|
||||
return (
|
||||
@@ -102,7 +103,10 @@ export const Knob = props => {
|
||||
</div>
|
||||
</div>
|
||||
{dragging && (
|
||||
<div className="Knob__popupValue">
|
||||
<div className={classes([
|
||||
'Knob__popupValue',
|
||||
popUpPosition && 'Knob__popupValue--' + popUpPosition,
|
||||
])}>
|
||||
{displayElement}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -20,6 +20,7 @@ export const LabeledListItem = props => {
|
||||
labelColor = 'label',
|
||||
color,
|
||||
textAlign,
|
||||
verticalAlign,
|
||||
buttons,
|
||||
content,
|
||||
children,
|
||||
@@ -33,6 +34,7 @@ export const LabeledListItem = props => {
|
||||
<Box
|
||||
as="td"
|
||||
color={labelColor}
|
||||
verticalAlign={verticalAlign}
|
||||
className={classes([
|
||||
'LabeledList__cell',
|
||||
'LabeledList__label',
|
||||
@@ -43,6 +45,7 @@ export const LabeledListItem = props => {
|
||||
as="td"
|
||||
color={color}
|
||||
textAlign={textAlign}
|
||||
verticalAlign={verticalAlign}
|
||||
className={classes([
|
||||
'LabeledList__cell',
|
||||
'LabeledList__content',
|
||||
|
||||
@@ -6,10 +6,20 @@ export const Modal = props => {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
onEnter,
|
||||
...rest
|
||||
} = props;
|
||||
let handleKeyDown;
|
||||
if (onEnter) {
|
||||
handleKeyDown = e => {
|
||||
if (e.keyCode === 13) {
|
||||
onEnter(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
return (
|
||||
<Dimmer>
|
||||
<Dimmer
|
||||
onKeyDown={handleKeyDown}>
|
||||
<div
|
||||
className={classes([
|
||||
'Modal',
|
||||
|
||||
@@ -8,7 +8,10 @@ export const Section = props => {
|
||||
level = 1,
|
||||
buttons,
|
||||
content,
|
||||
stretchContents,
|
||||
noTopPadding,
|
||||
children,
|
||||
scrollable,
|
||||
...rest
|
||||
} = props;
|
||||
const hasTitle = !isFalsy(title) || !isFalsy(buttons);
|
||||
@@ -18,6 +21,7 @@ export const Section = props => {
|
||||
className={classes([
|
||||
'Section',
|
||||
'Section--level--' + level,
|
||||
props.flexGrow && 'Section--flex',
|
||||
className,
|
||||
])}
|
||||
{...rest}>
|
||||
@@ -32,10 +36,14 @@ export const Section = props => {
|
||||
</div>
|
||||
)}
|
||||
{hasContent && (
|
||||
<div className="Section__content">
|
||||
<Box className={classes([
|
||||
"Section__content",
|
||||
!!stretchContents && "Section__content--stretchContents",
|
||||
!!noTopPadding && "Section__content--noTopPadding",
|
||||
])}>
|
||||
{content}
|
||||
{children}
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
|
||||
+16
-16
@@ -3,30 +3,30 @@ import 'core-js/es';
|
||||
import 'core-js/web/immediate';
|
||||
import 'core-js/web/queue-microtask';
|
||||
import 'core-js/web/timers';
|
||||
import 'regenerator-runtime/runtime';
|
||||
import './polyfills/html5shiv';
|
||||
import './polyfills/ie8';
|
||||
import './polyfills/dom4';
|
||||
import './polyfills/css-om';
|
||||
import './polyfills/inferno';
|
||||
|
||||
// Themes
|
||||
import './styles/main.scss';
|
||||
import './styles/themes/cardtable.scss';
|
||||
import './styles/themes/malfunction.scss';
|
||||
import './styles/themes/ntos.scss';
|
||||
import './styles/themes/hackerman.scss';
|
||||
import './styles/themes/retro.scss';
|
||||
import './styles/themes/syndicate.scss';
|
||||
|
||||
import { loadCSS } from 'fg-loadcss';
|
||||
import { render } from 'inferno';
|
||||
import 'regenerator-runtime/runtime';
|
||||
import { setupHotReloading } from 'tgui-dev-server/link/client';
|
||||
import { backendUpdate } from './backend';
|
||||
import { IS_IE8 } from './byond';
|
||||
import { setupDrag } from './drag';
|
||||
import { logger } from './logging';
|
||||
import './polyfills/css-om';
|
||||
import './polyfills/dom4';
|
||||
import './polyfills/html5shiv';
|
||||
import './polyfills/ie8';
|
||||
import './polyfills/inferno';
|
||||
import { createStore, StoreProvider } from './store';
|
||||
// Themes
|
||||
import './styles/main.scss';
|
||||
import './styles/themes/cardtable.scss';
|
||||
import './styles/themes/hackerman.scss';
|
||||
import './styles/themes/malfunction.scss';
|
||||
import './styles/themes/ntos.scss';
|
||||
import './styles/themes/retro.scss';
|
||||
import './styles/themes/syndicate.scss';
|
||||
|
||||
|
||||
|
||||
const enteredBundleAt = Date.now();
|
||||
const store = createStore();
|
||||
|
||||
@@ -0,0 +1,433 @@
|
||||
import { round } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { AnimatedNumber, Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Table, Tooltip } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
const stats = [
|
||||
['good', 'Alive'],
|
||||
['average', 'Critical'],
|
||||
['bad', 'DEAD'],
|
||||
];
|
||||
|
||||
const abnormalities = [
|
||||
['hasBorer', 'bad', 'Large growth detected in frontal lobe,'
|
||||
+ ' possibly cancerous. Surgical removal is recommended.'],
|
||||
['hasVirus', 'bad', 'Viral pathogen detected in blood stream.'],
|
||||
['blind', 'average', 'Cataracts detected.'],
|
||||
['colourblind', 'average', 'Photoreceptor abnormalities detected.'],
|
||||
['nearsighted', 'average', 'Retinal misalignment detected.'],
|
||||
];
|
||||
|
||||
const damages = [
|
||||
['Respiratory', 'oxyLoss'],
|
||||
['Brain', 'brainLoss'],
|
||||
['Toxin', 'toxLoss'],
|
||||
['Radioactive', 'radLoss'],
|
||||
['Brute', 'bruteLoss'],
|
||||
['Genetic', 'cloneLoss'],
|
||||
['Burn', 'fireLoss'],
|
||||
['Paralysis', 'paralysis'],
|
||||
];
|
||||
|
||||
const damageRange = {
|
||||
average: [0.25, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
};
|
||||
|
||||
const mapTwoByTwo = (a, c) => {
|
||||
let result = [];
|
||||
for (let i = 0; i < a.length; i += 2) {
|
||||
result.push(c(a[i], a[i + 1], i));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const reduceOrganStatus = A => {
|
||||
return A.length > 0
|
||||
? A
|
||||
.filter(s => !!s && s.length > 0)
|
||||
.reduce((a, s) => a === null
|
||||
? [s]
|
||||
: <Fragment key={s}>{a}<br />{s}</Fragment>, null
|
||||
)
|
||||
: null;
|
||||
};
|
||||
|
||||
const germStatus = i => {
|
||||
if (i > 100) {
|
||||
if (i < 300) { return "mild infection"; }
|
||||
if (i < 400) { return "mild infection+"; }
|
||||
if (i < 500) { return "mild infection++"; }
|
||||
if (i < 700) { return "acute infection"; }
|
||||
if (i < 800) { return "acute infection+"; }
|
||||
if (i < 900) { return "acute infection++"; }
|
||||
if (i >= 900) { return "septic"; }
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
export const BodyScanner = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
occupied,
|
||||
occupant = {},
|
||||
} = data;
|
||||
const body = occupied ? (
|
||||
<BodyScannerMain occupant={occupant} />
|
||||
) : (
|
||||
<BodyScannerEmpty />
|
||||
);
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content scrollable className="Layout__content--flexColumn">
|
||||
{body}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMain = props => {
|
||||
const {
|
||||
occupant,
|
||||
} = props;
|
||||
return (
|
||||
<Box>
|
||||
<BodyScannerMainOccupant occupant={occupant} />
|
||||
<BodyScannerMainAbnormalities occupant={occupant} />
|
||||
<BodyScannerMainDamage occupant={occupant} />
|
||||
<BodyScannerMainOrgansExternal organs={occupant.extOrgan} />
|
||||
<BodyScannerMainOrgansInternal organs={occupant.intOrgan} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainOccupant = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
occupant,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Occupant"
|
||||
buttons={(
|
||||
<Fragment>
|
||||
<Button
|
||||
icon="user-slash"
|
||||
onClick={() => act('ejectify')}>
|
||||
Eject
|
||||
</Button>
|
||||
<Button
|
||||
icon="print"
|
||||
onClick={() => act('print_p')}>
|
||||
Print Report
|
||||
</Button>
|
||||
</Fragment>
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{occupant.name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={occupant.maxHealth}
|
||||
value={occupant.health / occupant.maxHealth}
|
||||
ranges={{
|
||||
good: [0.5, Infinity],
|
||||
average: [0, 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Status" color={stats[occupant.stat][0]}>
|
||||
{stats[occupant.stat][1]}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Temperature">
|
||||
<AnimatedNumber
|
||||
value={round(occupant.bodyTempC, 0)}
|
||||
/>°C,
|
||||
<AnimatedNumber
|
||||
value={round(occupant.bodyTempF, 0)}
|
||||
/>°F
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Implants">
|
||||
{occupant.implant_len ? (
|
||||
<Box>
|
||||
{occupant.implant.map(im => im.name).join(', ')}
|
||||
</Box>
|
||||
) : (
|
||||
<Box color="label">
|
||||
None
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainAbnormalities = props => {
|
||||
const {
|
||||
occupant,
|
||||
} = props;
|
||||
if (!(occupant.hasBorer || occupant.blind
|
||||
|| occupant.colourblind || occupant.nearsighted
|
||||
|| occupant.hasVirus)) {
|
||||
return (
|
||||
<Section title="Abnormalities">
|
||||
<Box color="label">
|
||||
No abnormalities found.
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="Abnormalities">
|
||||
{abnormalities.map((a, i) => {
|
||||
if (occupant[a[0]]) {
|
||||
return (
|
||||
<Box color={a[1]} bold={a[1] === "bad"}>
|
||||
{a[2]}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainDamage = props => {
|
||||
const {
|
||||
occupant,
|
||||
} = props;
|
||||
return (
|
||||
<Section title="Damage">
|
||||
<Table>
|
||||
{mapTwoByTwo(damages, (d1, d2, i) => (
|
||||
<Fragment>
|
||||
<Table.Row color="label">
|
||||
<Table.Cell>
|
||||
{d1[0]}:
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{!!d2 && d2[0] + ":"}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<BodyScannerMainDamageBar
|
||||
value={occupant[d1[1]]}
|
||||
marginBottom={i < (damages.length - 2)}
|
||||
/>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{!!d2 && (
|
||||
<BodyScannerMainDamageBar value={occupant[d2[1]]} />
|
||||
)}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Fragment>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainDamageBar = props => {
|
||||
return (
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max="100"
|
||||
value={props.value / 100}
|
||||
mt="0.5rem"
|
||||
mb={!!props.marginBottom && "0.5rem"}
|
||||
ranges={damageRange}>
|
||||
{round(props.value, 0)}
|
||||
</ProgressBar>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainOrgansExternal = props => {
|
||||
if (props.organs.length === 0) {
|
||||
return (
|
||||
<Section title="External Organs">
|
||||
<Box color="label">
|
||||
N/A
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="External Organs">
|
||||
<Table>
|
||||
<Table.Row header>
|
||||
<Table.Cell>
|
||||
Name
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
Damage
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="right">
|
||||
Injuries
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{props.organs.map((o, i) => (
|
||||
<Table.Row key={i} textTransform="capitalize">
|
||||
<Table.Cell width="33%">
|
||||
{o.name}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center" q>
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={o.maxHealth}
|
||||
mt={i > 0 && "0.5rem"}
|
||||
value={o.totalLoss / 100}
|
||||
ranges={damageRange}>
|
||||
<Box float="left" display="inline">
|
||||
{!!o.bruteLoss && (
|
||||
<Box display="inline" position="relative">
|
||||
<Icon name="bone" />
|
||||
{round(o.bruteLoss, 0)}
|
||||
<Tooltip
|
||||
position="top"
|
||||
content="Brute damage"
|
||||
/>
|
||||
</Box>)}
|
||||
{!!o.fireLoss && (
|
||||
<Box display="inline" position="relative">
|
||||
<Icon name="fire" />
|
||||
{round(o.fireLoss, 0)}
|
||||
<Tooltip
|
||||
position="top"
|
||||
content="Burn damage"
|
||||
/>
|
||||
</Box>)}
|
||||
</Box>
|
||||
<Box display="inline">
|
||||
{round(o.totalLoss, 0)}
|
||||
</Box>
|
||||
</ProgressBar>
|
||||
</Table.Cell>
|
||||
<Table.Cell
|
||||
textAlign="right"
|
||||
width="33%">
|
||||
<Box color="average" display="inline">
|
||||
{reduceOrganStatus([
|
||||
o.internalBleeding && "Internal bleeding",
|
||||
o.lungRuptured && "Ruptured lung",
|
||||
!!o.status.broken && o.status.broken,
|
||||
germStatus(o.germ_level),
|
||||
!!o.open && "Open incision",
|
||||
])}
|
||||
</Box>
|
||||
<Box display="inline">
|
||||
{reduceOrganStatus([
|
||||
!!o.status.splinted && "Splinted",
|
||||
!!o.status.robotic && "Robotic",
|
||||
!!o.status.dead && (
|
||||
<Box color="bad">
|
||||
DEAD
|
||||
</Box>
|
||||
),
|
||||
])}
|
||||
{reduceOrganStatus(o.shrapnel.map(
|
||||
s => s.known
|
||||
? s.name
|
||||
: "Unknown object"
|
||||
))}
|
||||
</Box>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainOrgansInternal = props => {
|
||||
if (props.organs.length === 0) {
|
||||
return (
|
||||
<Section title="Internal Organs">
|
||||
<Box color="label">
|
||||
N/A
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="Internal Organs">
|
||||
<Table>
|
||||
<Table.Row header>
|
||||
<Table.Cell>
|
||||
Name
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
Damage
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="right">
|
||||
Injuries
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{props.organs.map((o, i) => (
|
||||
<Table.Row key={i} textTransform="capitalize">
|
||||
<Table.Cell width="33%">
|
||||
{o.name}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={o.maxHealth}
|
||||
value={o.damage / 100}
|
||||
mt={i > 0 && "0.5rem"}
|
||||
ranges={damageRange}>
|
||||
{round(o.damage, 0)}
|
||||
</ProgressBar>
|
||||
</Table.Cell>
|
||||
<Table.Cell
|
||||
textAlign="right"
|
||||
width="33%">
|
||||
<Box color="average" display="inline">
|
||||
{reduceOrganStatus([
|
||||
germStatus(o.germ_level),
|
||||
])}
|
||||
</Box>
|
||||
<Box display="inline">
|
||||
{reduceOrganStatus([
|
||||
(o.robotic === 1) && "Robotic",
|
||||
(o.robotic === 2) && "Assisted",
|
||||
!!o.dead && (
|
||||
<Box color="bad">
|
||||
DEAD
|
||||
</Box>
|
||||
),
|
||||
])}
|
||||
</Box>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerEmpty = () => {
|
||||
return (
|
||||
<Section textAlign="center" flexGrow="1">
|
||||
<Flex height="100%">
|
||||
<Flex.Item grow="1" align="center" color="label">
|
||||
<Icon
|
||||
name="user-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
No occupant detected.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,181 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, LabeledList, ProgressBar, Section } from "../components";
|
||||
import { BeakerContents } from "../interfaces/common/BeakerContents";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
const dispenseAmounts = [1, 5, 10, 20, 30, 50];
|
||||
const removeAmounts = [1, 5, 10];
|
||||
|
||||
export const ChemDispenser = (props, context) => {
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
<ChemDispenserSettings />
|
||||
<ChemDispenserChemicals />
|
||||
<ChemDispenserBeaker />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemDispenserSettings = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
amount,
|
||||
energy,
|
||||
maxEnergy,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Settings" flex="content">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Energy">
|
||||
<ProgressBar
|
||||
value={energy}
|
||||
minValue={0}
|
||||
maxValue={maxEnergy}
|
||||
ranges={{
|
||||
good: [maxEnergy * 0.5, Infinity],
|
||||
average: [maxEnergy * 0.25, maxEnergy * 0.5],
|
||||
bad: [-Infinity, maxEnergy * 0.25],
|
||||
}}>
|
||||
{energy} / {maxEnergy} Units
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Dispense" verticalAlign="middle">
|
||||
<Flex direction="row" spacing="1">
|
||||
{dispenseAmounts.map((a, i) => (
|
||||
<Flex.Item key={i} grow="1" width="14%" display="inline-block">
|
||||
<Button
|
||||
icon="cog"
|
||||
selected={amount === a}
|
||||
content={a}
|
||||
m="0"
|
||||
width="100%"
|
||||
onClick={() => act('amount', {
|
||||
amount: a,
|
||||
})}
|
||||
/>
|
||||
</Flex.Item>
|
||||
))}
|
||||
</Flex>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemDispenserChemicals = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
chemicals = [],
|
||||
} = data;
|
||||
const flexFillers = [];
|
||||
for (let i = 0; i < (chemicals.length + 1) % 3; i++) {
|
||||
flexFillers.push(true);
|
||||
}
|
||||
return (
|
||||
<Section
|
||||
title={data.glass ? 'Drink Dispenser' : 'Chemical Dispenser'}
|
||||
flexGrow="1">
|
||||
<Flex
|
||||
direction="row"
|
||||
wrap="wrap"
|
||||
height="100%"
|
||||
spacingPrecise="2"
|
||||
align="flex-start"
|
||||
alignContent="flex-start">
|
||||
{chemicals.map((c, i) => (
|
||||
<Flex.Item
|
||||
key={i}
|
||||
grow="1"
|
||||
basis="25%"
|
||||
height="20px"
|
||||
width="30%"
|
||||
display="inline-block">
|
||||
<Button
|
||||
icon="arrow-circle-down"
|
||||
overflow="hidden"
|
||||
textOverflow="ellipsis"
|
||||
width="100%"
|
||||
height="100%"
|
||||
align="flex-start"
|
||||
content={c.title}
|
||||
onClick={() => act('dispense', {
|
||||
reagent: c.id,
|
||||
})}
|
||||
/>
|
||||
</Flex.Item>
|
||||
))}
|
||||
{flexFillers.map((_, i) => (
|
||||
<Flex.Item key={i} grow="1" basis="25%" height="20px" />
|
||||
))}
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemDispenserBeaker = (properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isBeakerLoaded,
|
||||
beakerCurrentVolume,
|
||||
beakerMaxVolume,
|
||||
beakerContents = [],
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title={data.glass ? 'Glass' : 'Beaker'}
|
||||
flex="content"
|
||||
minHeight="25%"
|
||||
buttons={(
|
||||
<Box>
|
||||
{!!isBeakerLoaded && (
|
||||
<Box inline color="label" mr={2}>
|
||||
{beakerCurrentVolume} / {beakerMaxVolume} units
|
||||
</Box>
|
||||
)}
|
||||
<Button
|
||||
icon="eject"
|
||||
content="Eject"
|
||||
disabled={!isBeakerLoaded}
|
||||
onClick={() => act('ejectBeaker')}
|
||||
/>
|
||||
</Box>
|
||||
)}>
|
||||
<BeakerContents
|
||||
beakerLoaded={isBeakerLoaded}
|
||||
beakerContents={beakerContents}
|
||||
buttons={chemical => (
|
||||
<Fragment>
|
||||
<Button
|
||||
content="Isolate"
|
||||
icon="compress-arrows-alt"
|
||||
onClick={() => act('remove', {
|
||||
reagent: chemical.id,
|
||||
amount: -1,
|
||||
})}
|
||||
/>
|
||||
{removeAmounts.map((a, i) => (
|
||||
<Button
|
||||
key={i}
|
||||
content={a}
|
||||
onClick={() => act('remove', {
|
||||
reagent: chemical.id,
|
||||
amount: a,
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
content="ALL"
|
||||
onClick={() => act('remove', {
|
||||
reagent: chemical.id,
|
||||
amount: chemical.volume,
|
||||
})}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
import { round, toFixed } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { AnimatedNumber, Box, Button, LabeledList, NumberInput, Section } from "../components";
|
||||
import { BeakerContents } from '../interfaces/common/BeakerContents';
|
||||
import { Window } from "../layouts";
|
||||
|
||||
export const ChemHeater = (_props, _context) => {
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
<ChemHeaterSettings />
|
||||
<ChemHeaterBeaker />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemHeaterSettings = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
targetTemp,
|
||||
targetTempReached,
|
||||
autoEject,
|
||||
isActive,
|
||||
currentTemp,
|
||||
isBeakerLoaded,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Settings"
|
||||
flexBasis="content"
|
||||
buttons={(
|
||||
<Fragment>
|
||||
<Button
|
||||
content="Auto-eject"
|
||||
icon={autoEject ? "toggle-on" : "toggle-off"}
|
||||
selected={autoEject}
|
||||
onClick={() => act("toggle_autoeject")} />
|
||||
<Button
|
||||
content={isActive ? "On" : "Off"}
|
||||
icon="power-off"
|
||||
selected={isActive}
|
||||
disabled={!isBeakerLoaded}
|
||||
onClick={() => act("toggle_on")} />
|
||||
</Fragment>
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Target">
|
||||
<NumberInput
|
||||
width="65px"
|
||||
unit="K"
|
||||
step={10}
|
||||
stepPixelSize={3}
|
||||
value={round(targetTemp, 0)}
|
||||
minValue={0}
|
||||
maxValue={1000}
|
||||
onDrag={(e, value) => act('adjust_temperature', {
|
||||
target: value,
|
||||
})}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item
|
||||
label="Reading"
|
||||
color={targetTempReached ? "good" : "average"}>
|
||||
{isBeakerLoaded && (
|
||||
<AnimatedNumber
|
||||
value={currentTemp}
|
||||
format={value => toFixed(value) + " K"} />
|
||||
) || '—'}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemHeaterBeaker = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isBeakerLoaded,
|
||||
beakerCurrentVolume,
|
||||
beakerMaxVolume,
|
||||
beakerContents,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Beaker"
|
||||
flexGrow="1"
|
||||
buttons={!!isBeakerLoaded && (
|
||||
<Box>
|
||||
<Box inline color="label" mr={2}>
|
||||
{beakerCurrentVolume} / {beakerMaxVolume} units
|
||||
</Box>
|
||||
<Button
|
||||
icon="eject"
|
||||
content="Eject"
|
||||
onClick={() => act('eject_beaker')} />
|
||||
</Box>
|
||||
)}>
|
||||
<BeakerContents
|
||||
beakerLoaded={isBeakerLoaded}
|
||||
beakerContents={beakerContents}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,408 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, Section } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
import { BeakerContents } from './common/BeakerContents';
|
||||
import { ComplexModal, modalOpen, modalRegisterBodyOverride } from './common/ComplexModal';
|
||||
|
||||
const transferAmounts = [1, 5, 10];
|
||||
const bottleStyles = [
|
||||
"bottle.png",
|
||||
"small_bottle.png",
|
||||
"wide_bottle.png",
|
||||
"round_bottle.png",
|
||||
"reagent_bottle.png",
|
||||
];
|
||||
|
||||
const analyzeModalBodyOverride = (modal, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const result = modal.args.analysis;
|
||||
return (
|
||||
<Section
|
||||
level={2}
|
||||
m="-1rem"
|
||||
pb="1rem"
|
||||
title={data.condi ? "Condiment Analysis" : "Reagent Analysis"}>
|
||||
<Box mx="0.5rem">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{result.name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Description">
|
||||
{(result.desc || "").length > 0 ? result.desc : "N/A"}
|
||||
</LabeledList.Item>
|
||||
{result.blood_type && (
|
||||
<Fragment>
|
||||
<LabeledList.Item label="Blood type">
|
||||
{result.blood_type}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item
|
||||
label="Blood DNA"
|
||||
className="LabeledList__breakContents">
|
||||
{result.blood_dna}
|
||||
</LabeledList.Item>
|
||||
</Fragment>
|
||||
)}
|
||||
{!data.condi && (
|
||||
<Button
|
||||
icon={data.printing ? 'spinner' : 'print'}
|
||||
disabled={data.printing}
|
||||
iconSpin={!!data.printing}
|
||||
ml="0.5rem"
|
||||
content="Print"
|
||||
onClick={() => act('print', {
|
||||
idx: result.idx,
|
||||
beaker: modal.args.beaker,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</LabeledList>
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export const ChemMaster = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
condi,
|
||||
beaker,
|
||||
beaker_reagents = [],
|
||||
buffer_reagents = [],
|
||||
mode,
|
||||
} = data;
|
||||
return (
|
||||
<Window resizable>
|
||||
<ComplexModal />
|
||||
<Window.Content scrollable className="Layout__content--flexColumn">
|
||||
<ChemMasterBeaker
|
||||
beaker={beaker}
|
||||
beakerReagents={beaker_reagents}
|
||||
bufferNonEmpty={buffer_reagents.length > 0}
|
||||
/>
|
||||
<ChemMasterBuffer
|
||||
mode={mode}
|
||||
bufferReagents={buffer_reagents}
|
||||
/>
|
||||
<ChemMasterProduction
|
||||
isCondiment={condi}
|
||||
bufferNonEmpty={buffer_reagents.length > 0}
|
||||
/>
|
||||
<ChemMasterCustomization />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemMasterBeaker = (props, context) => {
|
||||
const { act } = useBackend(context);
|
||||
const {
|
||||
beaker,
|
||||
beakerReagents,
|
||||
bufferNonEmpty,
|
||||
} = props;
|
||||
return (
|
||||
<Section
|
||||
title="Beaker"
|
||||
flexGrow="0"
|
||||
flexBasis="300px"
|
||||
buttons={bufferNonEmpty
|
||||
? <Button.Confirm
|
||||
icon="eject"
|
||||
disabled={!beaker}
|
||||
content="Eject and Clear Buffer"
|
||||
onClick={() => act('eject')}
|
||||
/>
|
||||
: <Button
|
||||
icon="eject"
|
||||
disabled={!beaker}
|
||||
content="Eject and Clear Buffer"
|
||||
onClick={() => act('eject')}
|
||||
/>}>
|
||||
{beaker
|
||||
? <BeakerContents
|
||||
beakerLoaded
|
||||
beakerContents={beakerReagents}
|
||||
buttons={(chemical, i) => (
|
||||
<Box mb={(i < beakerReagents.length - 1) && "2px"}>
|
||||
<Button
|
||||
content="Analyze"
|
||||
mb="0"
|
||||
onClick={() => modalOpen(context, 'analyze', {
|
||||
idx: i + 1,
|
||||
beaker: 1,
|
||||
})}
|
||||
/>
|
||||
{transferAmounts.map((am, j) =>
|
||||
(<Button
|
||||
key={j}
|
||||
content={am}
|
||||
mb="0"
|
||||
onClick={() => act('add', {
|
||||
id: chemical.id,
|
||||
amount: am,
|
||||
})}
|
||||
/>)
|
||||
)}
|
||||
<Button
|
||||
content="All"
|
||||
mb="0"
|
||||
onClick={() => act('add', {
|
||||
id: chemical.id,
|
||||
amount: chemical.volume,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
content="Custom.."
|
||||
mb="0"
|
||||
onClick={() => modalOpen(context, 'addcustom', {
|
||||
id: chemical.id,
|
||||
})}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
/>
|
||||
: (
|
||||
<Box color="label">
|
||||
No beaker loaded.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemMasterBuffer = (props, context) => {
|
||||
const { act } = useBackend(context);
|
||||
const {
|
||||
mode,
|
||||
bufferReagents = [],
|
||||
} = props;
|
||||
return (
|
||||
<Section
|
||||
title="Buffer"
|
||||
flexGrow="0"
|
||||
flexBasis="300px"
|
||||
buttons={
|
||||
<Box color="label">
|
||||
Transferring to
|
||||
<Button
|
||||
icon={mode ? "flask" : "trash"}
|
||||
color={!mode && "bad"}
|
||||
content={mode ? "Beaker" : "Disposal"}
|
||||
onClick={() => act('toggle')}
|
||||
/>
|
||||
</Box>
|
||||
}>
|
||||
{(bufferReagents.length > 0)
|
||||
? <BeakerContents
|
||||
beakerLoaded
|
||||
beakerContents={bufferReagents}
|
||||
buttons={(chemical, i) => (
|
||||
<Box mb={(i < bufferReagents.length - 1) && "2px"}>
|
||||
<Button
|
||||
content="Analyze"
|
||||
mb="0"
|
||||
onClick={() => modalOpen(context, 'analyze', {
|
||||
idx: i + 1,
|
||||
beaker: 0,
|
||||
})}
|
||||
/>
|
||||
{transferAmounts.map((am, i) =>
|
||||
(<Button
|
||||
key={i}
|
||||
content={am}
|
||||
mb="0"
|
||||
onClick={() => act('remove', {
|
||||
id: chemical.id,
|
||||
amount: am,
|
||||
})}
|
||||
/>)
|
||||
)}
|
||||
<Button
|
||||
content="All"
|
||||
mb="0"
|
||||
onClick={() => act('remove', {
|
||||
id: chemical.id,
|
||||
amount: chemical.volume,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
content="Custom.."
|
||||
mb="0"
|
||||
onClick={() => modalOpen(context, 'removecustom', {
|
||||
id: chemical.id,
|
||||
})}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
/>
|
||||
: (
|
||||
<Box color="label">
|
||||
Buffer is empty.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemMasterProduction = (props, context) => {
|
||||
const { act } = useBackend(context);
|
||||
if (!props.bufferNonEmpty) {
|
||||
return (
|
||||
<Section
|
||||
title="Production"
|
||||
height="100%"
|
||||
flexGrow="1">
|
||||
<Flex height="100%">
|
||||
<Flex.Item
|
||||
grow="1"
|
||||
align="center"
|
||||
textAlign="center"
|
||||
color="label">
|
||||
<Icon
|
||||
name="tint-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
Buffer is empty.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="Production" height="100%" flexGrow="1">
|
||||
{!props.isCondiment ? (
|
||||
<ChemMasterProductionChemical />
|
||||
) : (
|
||||
<ChemMasterProductionCondiment />
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemMasterProductionChemical = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
return (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Pills">
|
||||
<Button
|
||||
icon="circle"
|
||||
content="One (100u max)"
|
||||
onClick={() => modalOpen(context, 'create_pill')}
|
||||
/>
|
||||
<Button
|
||||
icon="plus-circle"
|
||||
content="Multiple"
|
||||
mx="0.5rem"
|
||||
onClick={() => modalOpen(context, 'create_pill_multiple')}
|
||||
/>
|
||||
<Button
|
||||
onClick={() => modalOpen(context, 'change_pill_style')}>
|
||||
<div style={
|
||||
"display: inline-block;"
|
||||
+ "width: 16px;"
|
||||
+ "height: 16px;"
|
||||
+ "vertical-align: middle;"
|
||||
+ "background: url(pill" + data.pillsprite + ".png);"
|
||||
+ "background-size: 200%;"
|
||||
+ "background-position: left -10px bottom -6px;"
|
||||
} />
|
||||
Style
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Patches">
|
||||
<Button
|
||||
icon="square"
|
||||
content="One (30u max)"
|
||||
mr="0.5rem"
|
||||
onClick={() => modalOpen(context, 'create_patch')}
|
||||
/>
|
||||
<Button
|
||||
icon="plus-square"
|
||||
content="Multiple"
|
||||
onClick={() => modalOpen(context, 'create_patch_multiple')}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Bottle">
|
||||
<Button
|
||||
icon="wine-bottle"
|
||||
content="Create bottle (50u max)"
|
||||
mr="0.5rem"
|
||||
mb="0.5rem"
|
||||
onClick={() => modalOpen(context, 'create_bottle')}
|
||||
/>
|
||||
<Button
|
||||
mb="0.5rem"
|
||||
onClick={() => modalOpen(context, 'change_bottle_style')}>
|
||||
<div style={
|
||||
"display: inline-block;"
|
||||
+ "width: 16px;"
|
||||
+ "height: 16px;"
|
||||
+ "vertical-align: middle;"
|
||||
+ "background: url(" + bottleStyles[data.bottlesprite - 1] + ");"
|
||||
+ "background-size: 200%;"
|
||||
+ "background-position: left -10px bottom -6px;"
|
||||
} />
|
||||
Style
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemMasterProductionCondiment = (props, context) => {
|
||||
const { act } = useBackend(context);
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
icon="box"
|
||||
content="Create condiment pack (10u max)"
|
||||
mb="0.5rem"
|
||||
onClick={() => modalOpen(context, 'create_condi_pack')}
|
||||
/><br />
|
||||
<Button
|
||||
icon="wine-bottle"
|
||||
content="Create bottle (50u max)"
|
||||
mb="0"
|
||||
onClick={() => act('create_condi_bottle')}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemMasterCustomization = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
if (!data.loaded_pill_bottle) {
|
||||
return (
|
||||
<Section title="Pill Bottle Customization">
|
||||
<Box color="label">
|
||||
None loaded.
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="Pill Bottle Customization">
|
||||
<Button
|
||||
disabled={!data.loaded_pill_bottle}
|
||||
icon="eject"
|
||||
content={data.loaded_pill_bottle
|
||||
? data.loaded_pill_bottle_name
|
||||
: "None loaded"}
|
||||
onClick={() => act('ejectp')}
|
||||
/>
|
||||
<Button
|
||||
disabled={!data.loaded_pill_bottle}
|
||||
icon="palette"
|
||||
content="Change wrapper"
|
||||
mb="0"
|
||||
onClick={() => modalOpen(context, 'change_pill_bottle_style')}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
modalRegisterBodyOverride('analyze', analyzeModalBodyOverride);
|
||||
@@ -0,0 +1,461 @@
|
||||
import { round } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, NoticeBox, ProgressBar, Section, Tabs } from "../components";
|
||||
import { COLORS } from '../constants';
|
||||
import { ComplexModal, modalRegisterBodyOverride } from '../interfaces/common/ComplexModal';
|
||||
import { Window } from "../layouts";
|
||||
|
||||
const viewRecordModalBodyOverride = (modal, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
activerecord,
|
||||
realname,
|
||||
health,
|
||||
unidentity,
|
||||
strucenzymes,
|
||||
} = modal.args;
|
||||
const damages = health.split(' - ');
|
||||
return (
|
||||
<Section
|
||||
level={2}
|
||||
m="-1rem"
|
||||
pb="1rem"
|
||||
title={"Records of " + realname}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{realname}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Damage">
|
||||
{damages.length > 1 ? (
|
||||
<Fragment>
|
||||
<Box color={COLORS.damageType.oxy} display="inline">
|
||||
{damages[0]}
|
||||
</Box>
|
||||
|
|
||||
<Box color={COLORS.damageType.toxin} display="inline">
|
||||
{damages[2]}
|
||||
</Box>
|
||||
|
|
||||
<Box color={COLORS.damageType.brute} display="inline">
|
||||
{damages[3]}
|
||||
</Box>
|
||||
|
|
||||
<Box color={COLORS.damageType.burn} display="inline">
|
||||
{damages[1]}
|
||||
</Box>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Box color="bad">
|
||||
Unknown
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="UI" className="LabeledList__breakContents">
|
||||
{unidentity}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="SE" className="LabeledList__breakContents">
|
||||
{strucenzymes}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Disk">
|
||||
<Button.Confirm
|
||||
disabled={!data.disk}
|
||||
icon="arrow-circle-down"
|
||||
content="Import"
|
||||
onClick={() => act('disk', {
|
||||
option: 'load',
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
disabled={!data.disk}
|
||||
icon="arrow-circle-up"
|
||||
content="Export UI"
|
||||
onClick={() => act('disk', {
|
||||
option: 'save',
|
||||
savetype: 'ui',
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
disabled={!data.disk}
|
||||
icon="arrow-circle-up"
|
||||
content="Export UI and UE"
|
||||
onClick={() => act('disk', {
|
||||
option: 'save',
|
||||
savetype: 'ue',
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
disabled={!data.disk}
|
||||
icon="arrow-circle-up"
|
||||
content="Export SE"
|
||||
onClick={() => act('disk', {
|
||||
option: 'save',
|
||||
savetype: 'se',
|
||||
})}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Actions">
|
||||
<Button
|
||||
disabled={!data.podready}
|
||||
icon="user-plus"
|
||||
content="Clone"
|
||||
onClick={() => act('clone', {
|
||||
ref: activerecord,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
icon="trash"
|
||||
content="Delete"
|
||||
onClick={() => act('del_rec')}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export const CloningConsole = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
menu,
|
||||
} = data;
|
||||
modalRegisterBodyOverride('view_rec', viewRecordModalBodyOverride);
|
||||
return (
|
||||
<Window resizable>
|
||||
<ComplexModal maxWidth="75%" maxHeight="75%" />
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
<CloningConsoleTemp />
|
||||
<CloningConsoleStatus />
|
||||
<CloningConsoleNavigation />
|
||||
<Section noTopPadding flexGrow="1">
|
||||
<CloningConsoleBody />
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const CloningConsoleNavigation = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
menu,
|
||||
} = data;
|
||||
return (
|
||||
<Tabs>
|
||||
<Tabs.Tab
|
||||
selected={menu === 1}
|
||||
icon="home"
|
||||
onClick={() => act('menu', {
|
||||
num: 1,
|
||||
})}>
|
||||
Main
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
selected={menu === 2}
|
||||
icon="folder"
|
||||
onClick={() => act('menu', {
|
||||
num: 2,
|
||||
})}>
|
||||
Records
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
const CloningConsoleBody = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
menu,
|
||||
} = data;
|
||||
let body;
|
||||
if (menu === 1) {
|
||||
body = <CloningConsoleMain />;
|
||||
} else if (menu === 2) {
|
||||
body = <CloningConsoleRecords />;
|
||||
}
|
||||
return body;
|
||||
};
|
||||
|
||||
const CloningConsoleMain = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
loading,
|
||||
scantemp,
|
||||
occupant,
|
||||
locked,
|
||||
can_brainscan,
|
||||
scan_mode,
|
||||
numberofpods,
|
||||
pods,
|
||||
selected_pod,
|
||||
} = data;
|
||||
const isLocked = locked && !!occupant;
|
||||
return (
|
||||
<Fragment>
|
||||
<Section
|
||||
title="Scanner"
|
||||
level="2"
|
||||
buttons={
|
||||
<Fragment>
|
||||
<Box display="inline" color="label">
|
||||
Scanner Lock:
|
||||
</Box>
|
||||
<Button
|
||||
disabled={!occupant}
|
||||
selected={isLocked}
|
||||
icon={isLocked ? "toggle-on" : "toggle-off"}
|
||||
content={isLocked ? "Engaged" : "Disengaged"}
|
||||
onClick={() => act('lock')}
|
||||
/>
|
||||
<Button
|
||||
disabled={isLocked || !occupant}
|
||||
icon="user-slash"
|
||||
content="Eject Occupant"
|
||||
onClick={() => act('eject')}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Status">
|
||||
{loading ? (
|
||||
<Box color="average">
|
||||
<Icon name="spinner" spin />
|
||||
Scanning...
|
||||
</Box>
|
||||
) : (
|
||||
<Box color={scantemp.color}>
|
||||
{scantemp.text}
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
{!!can_brainscan && (
|
||||
<LabeledList.Item label="Scan Mode">
|
||||
<Button
|
||||
icon={scan_mode ? "brain" : "male"}
|
||||
content={scan_mode ? "Brain" : "Body"}
|
||||
onClick={() => act('toggle_mode')}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
)}
|
||||
</LabeledList>
|
||||
<Button
|
||||
disabled={!occupant || loading}
|
||||
icon="user"
|
||||
content="Scan Occupant"
|
||||
mt="0.5rem"
|
||||
mb="0"
|
||||
onClick={() => act('scan')}
|
||||
/>
|
||||
</Section>
|
||||
<Section title="Pods" level="2">
|
||||
{numberofpods
|
||||
? pods.map((pod, i) => {
|
||||
let podAction;
|
||||
if (pod.status === "cloning") {
|
||||
podAction = (
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max="100"
|
||||
value={pod.progress / 100}
|
||||
ranges={{
|
||||
good: [0.75, Infinity],
|
||||
average: [0.25, 0.75],
|
||||
bad: [-Infinity, 0.25],
|
||||
}}
|
||||
mt="0.5rem">
|
||||
<Box textAlign="center">
|
||||
{round(pod.progress, 0) + "%"}
|
||||
</Box>
|
||||
</ProgressBar>
|
||||
);
|
||||
} else if (pod.status === "mess") {
|
||||
podAction = (
|
||||
<Box bold color="bad" mt="0.5rem">
|
||||
ERROR
|
||||
</Box>
|
||||
);
|
||||
} else {
|
||||
podAction = (
|
||||
<Button
|
||||
selected={selected_pod === pod.pod}
|
||||
icon={selected_pod === pod.pod && "check"}
|
||||
content="Select"
|
||||
mt="0.5rem"
|
||||
onClick={() => act('selectpod', {
|
||||
ref: pod.pod,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={i}
|
||||
width="64px"
|
||||
textAlign="center"
|
||||
display="inline-block"
|
||||
mr="0.5rem">
|
||||
<img
|
||||
src={"pod_" + pod.status + ".gif"}
|
||||
style={{
|
||||
width: "100%",
|
||||
"-ms-interpolation-mode": "nearest-neighbor",
|
||||
}}
|
||||
/>
|
||||
<Box color="label">
|
||||
Pod #{i + 1}
|
||||
</Box>
|
||||
<Box
|
||||
bold
|
||||
color={pod.biomass >= 150 ? "good" : "bad"}
|
||||
display="inline">
|
||||
<Icon
|
||||
name={pod.biomass >= 150 ? "circle" : "circle-o"}
|
||||
/>
|
||||
{pod.biomass}
|
||||
</Box>
|
||||
{podAction}
|
||||
</Box>
|
||||
);
|
||||
})
|
||||
: (
|
||||
<Box color="bad">
|
||||
No pods detected. Unable to clone.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const CloningConsoleRecords = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
records,
|
||||
} = data;
|
||||
if (!records.length) {
|
||||
return (
|
||||
<Flex height="100%">
|
||||
<Flex.Item
|
||||
grow="1"
|
||||
align="center"
|
||||
textAlign="center"
|
||||
color="label">
|
||||
<Icon
|
||||
name="user-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
No records found.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Box mt="0.5rem">
|
||||
{records.map((record, i) => (
|
||||
<Button
|
||||
key={i}
|
||||
icon="user"
|
||||
mb="0.5rem"
|
||||
content={record.realname}
|
||||
onClick={() => act('view_rec', {
|
||||
ref: record.record,
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const CloningConsoleTemp = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
temp,
|
||||
} = data;
|
||||
if (!temp || !temp.text || temp.text.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tempProp = { [temp.style]: true };
|
||||
return (
|
||||
<NoticeBox {...tempProp}>
|
||||
<Box display="inline-block" verticalAlign="middle">
|
||||
{temp.text}
|
||||
</Box>
|
||||
<Button
|
||||
icon="times-circle"
|
||||
float="right"
|
||||
onClick={() => act('cleartemp')}
|
||||
/>
|
||||
<Box clear="both" />
|
||||
</NoticeBox>
|
||||
);
|
||||
};
|
||||
|
||||
const CloningConsoleStatus = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
scanner,
|
||||
numberofpods,
|
||||
autoallowed,
|
||||
autoprocess,
|
||||
disk,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Status"
|
||||
buttons={
|
||||
<Fragment>
|
||||
{!!autoallowed && (
|
||||
<Fragment>
|
||||
<Box display="inline" color="label">
|
||||
Auto-processing:
|
||||
</Box>
|
||||
<Button
|
||||
selected={autoprocess}
|
||||
icon={autoprocess ? "toggle-on" : "toggle-off"}
|
||||
content={autoprocess ? "Enabled" : "Disabled"}
|
||||
onClick={() => act('autoprocess', {
|
||||
on: autoprocess ? 0 : 1,
|
||||
})}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
<Button
|
||||
disabled={!disk}
|
||||
icon="eject"
|
||||
content="Eject Disk"
|
||||
onClick={() => act('disk', {
|
||||
option: 'eject',
|
||||
})}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Scanner">
|
||||
{scanner ? (
|
||||
<Box color="good">
|
||||
Connected
|
||||
</Box>
|
||||
) : (
|
||||
<Box color="bad">
|
||||
Not connected!
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Pods">
|
||||
{numberofpods ? (
|
||||
<Box color="good">
|
||||
{numberofpods} connected
|
||||
</Box>
|
||||
) : (
|
||||
<Box color="bad">
|
||||
None connected!
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,206 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { AnimatedNumber, Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
const damageTypes = [
|
||||
{
|
||||
label: "Resp.",
|
||||
type: "oxyLoss",
|
||||
},
|
||||
{
|
||||
label: "Toxin",
|
||||
type: "toxLoss",
|
||||
},
|
||||
{
|
||||
label: "Brute",
|
||||
type: "bruteLoss",
|
||||
},
|
||||
{
|
||||
label: "Burn",
|
||||
type: "fireLoss",
|
||||
},
|
||||
];
|
||||
|
||||
const statNames = [
|
||||
["good", "Conscious"],
|
||||
["average", "Unconscious"],
|
||||
["bad", "DEAD"],
|
||||
];
|
||||
|
||||
export const Cryo = (props, context) => {
|
||||
return (
|
||||
<Window>
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
<CryoContent />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const CryoContent = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isOperating,
|
||||
hasOccupant,
|
||||
occupant = [],
|
||||
cellTemperature,
|
||||
cellTemperatureStatus,
|
||||
isBeakerLoaded,
|
||||
auto_eject_healthy,
|
||||
auto_eject_dead,
|
||||
} = data;
|
||||
return (
|
||||
<Fragment>
|
||||
<Section
|
||||
title="Occupant"
|
||||
flexGrow="1"
|
||||
buttons={(
|
||||
<Button
|
||||
icon="user-slash"
|
||||
onClick={() => act('ejectOccupant')}
|
||||
disabled={!hasOccupant}>
|
||||
Eject
|
||||
</Button>
|
||||
)}>
|
||||
{hasOccupant ? (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Occupant">
|
||||
{occupant.name || "Unknown"}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health">
|
||||
<ProgressBar
|
||||
min={occupant.health}
|
||||
max={occupant.maxHealth}
|
||||
value={occupant.health / occupant.maxHealth}
|
||||
color={occupant.health > 0 ? 'good' : 'average'}>
|
||||
<AnimatedNumber
|
||||
value={Math.round(occupant.health)} />
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item
|
||||
label="Status"
|
||||
color={statNames[occupant.stat][0]}>
|
||||
{statNames[occupant.stat][1]}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Temperature">
|
||||
<AnimatedNumber
|
||||
value={Math.round(occupant.bodyTemperature)} />
|
||||
{' K'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Divider />
|
||||
{(damageTypes.map(damageType => (
|
||||
<LabeledList.Item
|
||||
key={damageType.id}
|
||||
label={damageType.label}>
|
||||
<ProgressBar
|
||||
value={occupant[damageType.type]/100}
|
||||
ranges={{ bad: [0.01, Infinity] }}>
|
||||
<AnimatedNumber
|
||||
value={Math.round(occupant[damageType.type])} />
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
)))}
|
||||
</LabeledList>
|
||||
) : (
|
||||
<Flex height="100%" textAlign="center">
|
||||
<Flex.Item grow="1" align="center" color="label">
|
||||
<Icon
|
||||
name="user-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
No occupant detected.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
)}
|
||||
</Section>
|
||||
<Section
|
||||
title="Cell"
|
||||
buttons={(
|
||||
<Button
|
||||
icon="eject"
|
||||
onClick={() => act('ejectBeaker')}
|
||||
disabled={!isBeakerLoaded}>
|
||||
Eject Beaker
|
||||
</Button>
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Power">
|
||||
<Button
|
||||
icon="power-off"
|
||||
onClick={() => act(isOperating ? 'switchOff' : 'switchOn')}
|
||||
selected={isOperating}>
|
||||
{isOperating ? "On" : "Off"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Temperature" color={cellTemperatureStatus}>
|
||||
<AnimatedNumber value={cellTemperature} /> K
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Beaker">
|
||||
<CryoBeaker />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Divider />
|
||||
<LabeledList.Item label="Auto-eject healthy occupants">
|
||||
<Button
|
||||
icon={auto_eject_healthy ? "toggle-on" : "toggle-off"}
|
||||
selected={auto_eject_healthy}
|
||||
onClick={() => act(auto_eject_healthy
|
||||
? 'auto_eject_healthy_off'
|
||||
: 'auto_eject_healthy_on'
|
||||
)}>
|
||||
{auto_eject_healthy ? "On" : "Off"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Auto-eject dead occupants">
|
||||
<Button
|
||||
icon={auto_eject_dead ? "toggle-on" : "toggle-off"}
|
||||
selected={auto_eject_dead}
|
||||
onClick={() => act(auto_eject_dead
|
||||
? 'auto_eject_dead_off'
|
||||
: 'auto_eject_dead_on'
|
||||
)}>
|
||||
{auto_eject_dead ? "On" : "Off"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const CryoBeaker = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isBeakerLoaded,
|
||||
beakerLabel,
|
||||
beakerVolume,
|
||||
} = data;
|
||||
if (isBeakerLoaded) {
|
||||
return (
|
||||
<Fragment>
|
||||
{beakerLabel
|
||||
? beakerLabel
|
||||
: (
|
||||
<Box color="average">
|
||||
No label
|
||||
</Box>
|
||||
)}
|
||||
<Box color={!beakerVolume && "bad"}>
|
||||
{beakerVolume ? (
|
||||
<AnimatedNumber
|
||||
value={beakerVolume}
|
||||
format={v => Math.round(v) + " units remaining"}
|
||||
/>
|
||||
) : "Beaker is empty"}
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Box color="average">
|
||||
No beaker loaded
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,711 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Dimmer, Flex, Icon, Knob, LabeledList, ProgressBar, Section, Tabs } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
import { ComplexModal } from './common/ComplexModal';
|
||||
|
||||
const stats = [
|
||||
['good', 'Alive'],
|
||||
['average', 'Critical'],
|
||||
['bad', 'DEAD'],
|
||||
];
|
||||
|
||||
const operations = [
|
||||
['ui', 'Modify U.I.', 'dna'],
|
||||
['se', 'Modify S.E.', 'dna'],
|
||||
['buffer', 'Transfer Buffers', 'syringe'],
|
||||
['rejuvenators', 'Rejuvenators', 'flask'],
|
||||
];
|
||||
|
||||
const rejuvenatorsDoses = [5, 10, 20, 30, 50];
|
||||
|
||||
export const DNAModifier = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
irradiating,
|
||||
dnaBlockSize,
|
||||
occupant,
|
||||
} = data;
|
||||
context.dnaBlockSize = dnaBlockSize;
|
||||
context.isDNAInvalid = !occupant.isViableSubject
|
||||
|| !occupant.uniqueIdentity
|
||||
|| !occupant.structuralEnzymes;
|
||||
let radiatingModal;
|
||||
if (irradiating) {
|
||||
radiatingModal = <DNAModifierIrradiating duration={irradiating} />;
|
||||
}
|
||||
return (
|
||||
<Window resizable>
|
||||
<ComplexModal />
|
||||
{radiatingModal}
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
<DNAModifierOccupant />
|
||||
<DNAModifierMain />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierOccupant = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
locked,
|
||||
hasOccupant,
|
||||
occupant,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Occupant"
|
||||
buttons={
|
||||
<Fragment>
|
||||
<Box color="label" display="inline" mr="0.5rem">
|
||||
Door Lock:
|
||||
</Box>
|
||||
<Button
|
||||
disabled={!hasOccupant}
|
||||
selected={locked}
|
||||
icon={locked ? "toggle-on" : "toggle-off"}
|
||||
content={locked ? "Engaged" : "Disengaged"}
|
||||
onClick={() => act('toggleLock')}
|
||||
/>
|
||||
<Button
|
||||
disabled={!hasOccupant || locked}
|
||||
icon="user-slash"
|
||||
content="Eject"
|
||||
onClick={() => act('ejectOccupant')}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
{hasOccupant ? (
|
||||
<Fragment>
|
||||
<Box>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{occupant.name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health">
|
||||
<ProgressBar
|
||||
min={occupant.minHealth}
|
||||
max={occupant.maxHealth}
|
||||
value={occupant.health / occupant.maxHealth}
|
||||
ranges={{
|
||||
good: [0.5, Infinity],
|
||||
average: [0, 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Status" color={stats[occupant.stat][0]}>
|
||||
{stats[occupant.stat][1]}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Divider />
|
||||
</LabeledList>
|
||||
</Box>
|
||||
{context.isDNAInvalid ? (
|
||||
<Box color="bad">
|
||||
<Icon name="exclamation-circle" />
|
||||
The occupant's DNA structure is ruined beyond recognition,
|
||||
please insert a subject with an intact DNA structure.
|
||||
</Box>
|
||||
) : (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Radiation">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max="100"
|
||||
value={occupant.radiationLevel / 100}
|
||||
color="average"
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Unique Enzymes">
|
||||
{data.occupant.uniqueEnzymes
|
||||
? data.occupant.uniqueEnzymes : (
|
||||
<Box color="bad">
|
||||
<Icon name="exclamation-circle" />
|
||||
Unknown
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
)}
|
||||
</Fragment>
|
||||
) : (
|
||||
<Box color="label">
|
||||
Cell unoccupied.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierMain = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
selectedMenuKey,
|
||||
hasOccupant,
|
||||
occupant,
|
||||
} = data;
|
||||
if (!hasOccupant) {
|
||||
return (
|
||||
<Section flexGrow="1">
|
||||
<Flex height="100%">
|
||||
<Flex.Item
|
||||
grow="1"
|
||||
align="center"
|
||||
textAlign="center"
|
||||
color="label">
|
||||
<Icon
|
||||
name="user-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
No occupant in DNA modifier.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
} else if (context.isDNAInvalid) {
|
||||
return (
|
||||
<Section flexGrow="1">
|
||||
<Flex height="100%">
|
||||
<Flex.Item
|
||||
grow="1"
|
||||
align="center"
|
||||
textAlign="center"
|
||||
color="label">
|
||||
<Icon
|
||||
name="user-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
No operation possible on this subject.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
let body;
|
||||
if (selectedMenuKey === "ui") {
|
||||
body = (
|
||||
<Fragment>
|
||||
<DNAModifierMainUI />
|
||||
<DNAModifierMainRadiationEmitter />
|
||||
</Fragment>
|
||||
);
|
||||
} else if (selectedMenuKey === "se") {
|
||||
body = (
|
||||
<Fragment>
|
||||
<DNAModifierMainSE />
|
||||
<DNAModifierMainRadiationEmitter />
|
||||
</Fragment>
|
||||
);
|
||||
} else if (selectedMenuKey === "buffer") {
|
||||
body = <DNAModifierMainBuffers />;
|
||||
} else if (selectedMenuKey === "rejuvenators") {
|
||||
body = <DNAModifierMainRejuvenators />;
|
||||
}
|
||||
return (
|
||||
<Section flexGrow="1">
|
||||
<Tabs>
|
||||
{operations.map((op, i) => (
|
||||
<Tabs.Tab
|
||||
key={i}
|
||||
selected={selectedMenuKey === op[0]}
|
||||
onClick={() => act('selectMenuKey', { key: op[0] })}>
|
||||
<Icon name={op[2]} />
|
||||
{op[1]}
|
||||
</Tabs.Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
{body}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierMainUI = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
selectedUIBlock,
|
||||
selectedUISubBlock,
|
||||
selectedUITarget,
|
||||
occupant,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Modify Unique Identifier" level="2">
|
||||
<DNAModifierBlocks
|
||||
dnaString={occupant.uniqueIdentity}
|
||||
selectedBlock={selectedUIBlock}
|
||||
selectedSubblock={selectedUISubBlock}
|
||||
blockSize={context.dnaBlockSize}
|
||||
action="selectUIBlock"
|
||||
/>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Target">
|
||||
<Knob
|
||||
minValue="1"
|
||||
maxValue="15"
|
||||
stepPixelSize="20"
|
||||
value={selectedUITarget}
|
||||
format={value => value.toString(16).toUpperCase()}
|
||||
ml="0"
|
||||
onChange={(e, val) => act('changeUITarget', { value: val })}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Button
|
||||
icon="radiation"
|
||||
content="Irradiate Block"
|
||||
mt="0.5rem"
|
||||
onClick={() => act('pulseUIRadiation')}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierMainSE = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
selectedSEBlock,
|
||||
selectedSESubBlock,
|
||||
occupant,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Modify Structural Enzymes" level="2">
|
||||
<DNAModifierBlocks
|
||||
dnaString={occupant.structuralEnzymes}
|
||||
selectedBlock={selectedSEBlock}
|
||||
selectedSubblock={selectedSESubBlock}
|
||||
blockSize={context.dnaBlockSize}
|
||||
action="selectSEBlock"
|
||||
/>
|
||||
<Button
|
||||
icon="radiation"
|
||||
content="Irradiate Block"
|
||||
onClick={() => act('pulseSERadiation')}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierMainRadiationEmitter = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
radiationIntensity,
|
||||
radiationDuration,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Radiation Emitter" level="2">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Intensity">
|
||||
<Knob
|
||||
minValue="1"
|
||||
maxValue="10"
|
||||
stepPixelSize="20"
|
||||
value={radiationIntensity}
|
||||
popUpPosition="right"
|
||||
ml="0"
|
||||
onChange={(e, val) => act('radiationIntensity', { value: val })}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Duration">
|
||||
<Knob
|
||||
minValue="1"
|
||||
maxValue="20"
|
||||
stepPixelSize="10"
|
||||
unit="s"
|
||||
value={radiationDuration}
|
||||
popUpPosition="right"
|
||||
ml="0"
|
||||
onChange={(e, val) => act('radiationDuration', { value: val })}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Button
|
||||
icon="radiation"
|
||||
content="Pulse Radiation"
|
||||
tooltip="Mutates a random block of either the occupant's UI or SE."
|
||||
tooltipPosition="top-right"
|
||||
mt="0.5rem"
|
||||
onClick={() => act('pulseRadiation')}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierMainBuffers = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
buffers,
|
||||
} = data;
|
||||
let bufferElements = buffers.map((buffer, i) => (
|
||||
<DNAModifierMainBuffersElement
|
||||
key={i}
|
||||
id={i + 1}
|
||||
name={"Buffer " + (i + 1)}
|
||||
buffer={buffer}
|
||||
/>
|
||||
));
|
||||
return (
|
||||
<Fragment>
|
||||
<Section title="Buffers" level="2">
|
||||
{bufferElements}
|
||||
</Section>
|
||||
<DNAModifierMainBuffersDisk />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierMainBuffersElement = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
buffer,
|
||||
} = props;
|
||||
const isInjectorReady = data.isInjectorReady;
|
||||
const realName = name + (buffer.data ? ' - ' + buffer.label : '');
|
||||
return (
|
||||
<Box backgroundColor="rgba(0, 0, 0, 0.33)" mb="0.5rem">
|
||||
<Section
|
||||
title={realName}
|
||||
level="3"
|
||||
mx="0"
|
||||
lineHeight="18px"
|
||||
buttons={
|
||||
<Fragment>
|
||||
<Button.Confirm
|
||||
disabled={!buffer.data}
|
||||
icon="trash"
|
||||
content="Clear"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'clear',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
disabled={!buffer.data}
|
||||
icon="pen"
|
||||
content="Rename"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'changeLabel',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
disabled={!buffer.data || !data.hasDisk}
|
||||
icon="save"
|
||||
content="Export"
|
||||
tooltip="Exports this buffer to the currently loaded data disk."
|
||||
tooltipPosition="bottom-left"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'saveDisk',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Write">
|
||||
<Button
|
||||
icon="arrow-circle-down"
|
||||
content="Subject U.I"
|
||||
mb="0"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'saveUI',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
icon="arrow-circle-down"
|
||||
content="Subject U.I and U.E."
|
||||
mb="0"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'saveUIAndUE',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
icon="arrow-circle-down"
|
||||
content="Subject S.E."
|
||||
mb="0"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'saveSE',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
disabled={!data.hasDisk || !data.disk.data}
|
||||
icon="arrow-circle-down"
|
||||
content="From Disk"
|
||||
mb="0"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'loadDisk',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
{!!buffer.data && (
|
||||
<Fragment>
|
||||
<LabeledList.Item label="Subject">
|
||||
{buffer.owner || (
|
||||
<Box color="average">
|
||||
Unknown
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Data Type">
|
||||
{buffer.type === "ui"
|
||||
? "Unique Identifiers"
|
||||
: "Structural Enzymes"}
|
||||
{!!buffer.ue && " and Unique Enzymes"}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Transfer to">
|
||||
<Button
|
||||
disabled={!isInjectorReady}
|
||||
icon={isInjectorReady ? "syringe" : "spinner"}
|
||||
iconSpin={!isInjectorReady}
|
||||
content="Injector"
|
||||
mb="0"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'createInjector',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
disabled={!isInjectorReady}
|
||||
icon={isInjectorReady ? "syringe" : "spinner"}
|
||||
iconSpin={!isInjectorReady}
|
||||
content="Block Injector"
|
||||
mb="0"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'createInjector',
|
||||
id: id,
|
||||
block: 1,
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
icon="user"
|
||||
content="Subject"
|
||||
mb="0"
|
||||
onClick={() => act('bufferOption', {
|
||||
option: 'transfer',
|
||||
id: id,
|
||||
})}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</Fragment>
|
||||
)}
|
||||
</LabeledList>
|
||||
{!buffer.data && (
|
||||
<Box color="label" mt="0.5rem">
|
||||
This buffer is empty.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierMainBuffersDisk = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
hasDisk,
|
||||
disk,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Data Disk"
|
||||
level="2"
|
||||
buttons={
|
||||
<Fragment>
|
||||
<Button.Confirm
|
||||
disabled={!hasDisk || !disk.data}
|
||||
icon="trash"
|
||||
content="Wipe"
|
||||
onClick={() => act('wipeDisk')}
|
||||
/>
|
||||
<Button
|
||||
disabled={!hasDisk}
|
||||
icon="eject"
|
||||
content="Eject"
|
||||
onClick={() => act('ejectDisk')}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
{hasDisk ? (
|
||||
disk.data ? (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Label">
|
||||
{disk.label ? disk.label : "No label"}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Subject">
|
||||
{disk.owner
|
||||
? disk.owner : (
|
||||
<Box color="average">
|
||||
Unknown
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Data Type">
|
||||
{disk.type === "ui"
|
||||
? "Unique Identifiers"
|
||||
: "Structural Enzymes"}
|
||||
{!!disk.ue && " and Unique Enzymes"}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
) : (
|
||||
<Box color="label">
|
||||
Disk is blank.
|
||||
</Box>
|
||||
)
|
||||
) : (
|
||||
<Box color="label" textAlign="center" my="1rem">
|
||||
<Icon name="save-o" size="4" /><br />
|
||||
No disk inserted.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierMainRejuvenators = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isBeakerLoaded,
|
||||
beakerVolume,
|
||||
beakerLabel,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Rejuvenators and Beaker"
|
||||
level="2"
|
||||
buttons={
|
||||
<Button
|
||||
disabled={!isBeakerLoaded}
|
||||
icon="eject"
|
||||
content="Eject"
|
||||
onClick={() => act('ejectBeaker')}
|
||||
/>
|
||||
}>
|
||||
{isBeakerLoaded ? (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Inject">
|
||||
{rejuvenatorsDoses.map((a, i) => (
|
||||
<Button
|
||||
key={i}
|
||||
disabled={a > beakerVolume}
|
||||
icon="syringe"
|
||||
content={a}
|
||||
onClick={() => act('injectRejuvenators', {
|
||||
amount: a,
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
disabled={beakerVolume <= 0}
|
||||
icon="syringe"
|
||||
content="All"
|
||||
onClick={() => act('injectRejuvenators', {
|
||||
amount: beakerVolume,
|
||||
})}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Beaker">
|
||||
<Box mb="0.5rem">
|
||||
{beakerLabel ? beakerLabel : "No label"}
|
||||
</Box>
|
||||
{beakerVolume ? (
|
||||
<Box color="good">
|
||||
{beakerVolume} unit{beakerVolume === 1 ? "" : "s"} remaining
|
||||
</Box>
|
||||
) : (
|
||||
<Box color="bad">
|
||||
Empty
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
) : (
|
||||
<Box color="label" textAlign="center" my="25%">
|
||||
<Icon name="exclamation-triangle" size="4" /><br />
|
||||
No beaker loaded.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierIrradiating = (props, context) => {
|
||||
return (
|
||||
<Dimmer textAlign="center">
|
||||
<Icon name="spinner" size="5" spin /><br />
|
||||
<Box color="average">
|
||||
<h1>
|
||||
<Icon name="radiation" />
|
||||
Irradiating occupant
|
||||
<Icon name="radiation" />
|
||||
</h1>
|
||||
</Box>
|
||||
<Box color="label">
|
||||
<h3>
|
||||
For {props.duration} second{props.duration === 1 ? "" : "s"}
|
||||
</h3>
|
||||
</Box>
|
||||
</Dimmer>
|
||||
);
|
||||
};
|
||||
|
||||
const DNAModifierBlocks = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
dnaString,
|
||||
selectedBlock,
|
||||
selectedSubblock,
|
||||
blockSize,
|
||||
action,
|
||||
} = props;
|
||||
|
||||
const characters = dnaString.split('');
|
||||
let curBlock = 0;
|
||||
let dnaBlocks = [];
|
||||
for (let block = 0; block < characters.length; block += blockSize) {
|
||||
const realBlock = block / blockSize + 1;
|
||||
let subBlocks = [];
|
||||
for (let subblock = 0; subblock < blockSize; subblock++) {
|
||||
const realSubblock = subblock + 1;
|
||||
subBlocks.push(
|
||||
<Button
|
||||
selected={selectedBlock === realBlock
|
||||
&& selectedSubblock === realSubblock}
|
||||
content={characters[block + subblock]}
|
||||
mb="0"
|
||||
onClick={() => act(action, {
|
||||
block: realBlock,
|
||||
subblock: realSubblock,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
dnaBlocks.push(
|
||||
<Flex.Item flex="0 0 16%" mb="1rem">
|
||||
<Box
|
||||
display="inline-block"
|
||||
width="20px"
|
||||
height="20px"
|
||||
mr="0.5rem"
|
||||
lineHeight="20px"
|
||||
backgroundColor="rgba(0, 0, 0, 0.33)"
|
||||
fontFamily="monospace"
|
||||
textAlign="center">
|
||||
{realBlock}
|
||||
</Box>
|
||||
{subBlocks}
|
||||
</Flex.Item>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Flex wrap="wrap">
|
||||
{dnaBlocks}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,422 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Collapsible, Icon, Input, LabeledList, Section, Tabs } from "../components";
|
||||
import { ComplexModal, modalOpen, modalRegisterBodyOverride } from "../interfaces/common/ComplexModal";
|
||||
import { Window } from "../layouts";
|
||||
import { LoginInfo } from './common/LoginInfo';
|
||||
import { LoginScreen } from './common/LoginScreen';
|
||||
import { TemporaryNotice } from './common/TemporaryNotice';
|
||||
|
||||
const severities = {
|
||||
"Minor": "good",
|
||||
"Medium": "average",
|
||||
"Dangerous!": "bad",
|
||||
"Harmful": "bad",
|
||||
"BIOHAZARD THREAT!": "bad",
|
||||
};
|
||||
|
||||
const doEdit = (context, field) => {
|
||||
modalOpen(context, 'edit', {
|
||||
field: field.edit,
|
||||
value: field.value,
|
||||
});
|
||||
};
|
||||
|
||||
const virusModalBodyOverride = (modal, context) => {
|
||||
const virus = modal.args;
|
||||
return (
|
||||
<Section
|
||||
level={2}
|
||||
m="-1rem"
|
||||
pb="1rem"
|
||||
title={virus.name || "Virus"}>
|
||||
<Box mx="0.5rem">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Number of stages">
|
||||
{virus.max_stages}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Spread">
|
||||
{virus.spread_text} Transmission
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Possible cure">
|
||||
{virus.cure}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Notes">
|
||||
{virus.desc}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Severity"
|
||||
color={severities[virus.severity]}>
|
||||
{virus.severity}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export const MedicalRecords = (_properties, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
authenticated,
|
||||
screen,
|
||||
} = data;
|
||||
if (!authenticated) {
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content>
|
||||
<LoginScreen />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
|
||||
let body;
|
||||
if (screen === 2) { // List Records
|
||||
body = <MedicalRecordsList />;
|
||||
} else if (screen === 3) { // Record Maintenance
|
||||
body = <MedicalRecordsMaintenance />;
|
||||
} else if (screen === 4) { // View Records
|
||||
body = <MedicalRecordsView />;
|
||||
} else if (screen === 5) { // Virus Database
|
||||
body = <MedicalRecordsViruses />;
|
||||
} else if (screen === 6) { // Medbot Tracking
|
||||
body = <MedicalRecordsMedbots />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Window resizable>
|
||||
<ComplexModal />
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
<LoginInfo />
|
||||
<TemporaryNotice />
|
||||
<MedicalRecordsNavigation />
|
||||
<Section height="100%" flexGrow="1">
|
||||
{body}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const MedicalRecordsList = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
records,
|
||||
} = data;
|
||||
return (
|
||||
<Fragment>
|
||||
<Input
|
||||
fluid
|
||||
placeholder="Search by Name, DNA, or ID"
|
||||
onChange={(_event, value) => act('search', { t1: value })}
|
||||
/>
|
||||
<Box mt="0.5rem">
|
||||
{records.map((record, i) => (
|
||||
<Fragment key={i}>
|
||||
<Button
|
||||
icon="user"
|
||||
mb="0.5rem"
|
||||
content={record.id + ": " + record.name}
|
||||
onClick={() => act('d_rec', { d_rec: record.ref })}
|
||||
/>
|
||||
<br />
|
||||
</Fragment>
|
||||
))}
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const MedicalRecordsMaintenance = (_properties, context) => {
|
||||
const { act } = useBackend(context);
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
icon="download"
|
||||
content="Backup to Disk"
|
||||
disabled
|
||||
/><br />
|
||||
<Button
|
||||
icon="upload"
|
||||
content="Upload from Disk"
|
||||
my="0.5rem"
|
||||
disabled
|
||||
/> <br />
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
content="Delete All Medical Records"
|
||||
onClick={() => act('del_all')}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const MedicalRecordsView = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
medical,
|
||||
printing,
|
||||
} = data;
|
||||
return (
|
||||
<Fragment>
|
||||
<Section title="General Data" level={2} mt="-6px">
|
||||
<MedicalRecordsViewGeneral />
|
||||
</Section>
|
||||
<Section title="Medical Data" level={2}>
|
||||
<MedicalRecordsViewMedical />
|
||||
</Section>
|
||||
<Section title="Actions" level={2}>
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
disabled={!!medical.empty}
|
||||
content="Delete Medical Record"
|
||||
color="bad"
|
||||
onClick={() => act('del_r')}
|
||||
/>
|
||||
<Button
|
||||
icon={printing ? 'spinner' : 'print'}
|
||||
disabled={printing}
|
||||
iconSpin={!!printing}
|
||||
content="Print Entry"
|
||||
ml="0.5rem"
|
||||
onClick={() => act('print_p')}
|
||||
/><br />
|
||||
<Button
|
||||
icon="arrow-left"
|
||||
content="Back"
|
||||
mt="0.5rem"
|
||||
onClick={() => act('screen', { screen: 2 })}
|
||||
/>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const MedicalRecordsViewGeneral = (_properties, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
general,
|
||||
} = data;
|
||||
if (!general || !general.fields) {
|
||||
return (
|
||||
<Box color="bad">
|
||||
General records lost!
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<Box width="50%" float="left">
|
||||
<LabeledList>
|
||||
{general.fields.map((field, i) => (
|
||||
<LabeledList.Item key={i} label={field.field}>
|
||||
<Box height="20px" display="inline-block">
|
||||
{field.value}
|
||||
</Box>
|
||||
{!!field.edit && (
|
||||
<Button
|
||||
icon="pen"
|
||||
ml="0.5rem"
|
||||
onClick={() => doEdit(context, field)}
|
||||
/>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Box>
|
||||
<Box width="50%" float="right" textAlign="right">
|
||||
{!!general.has_photos && (
|
||||
general.photos.map((p, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
display="inline-block"
|
||||
textAlign="center"
|
||||
color="label">
|
||||
<img
|
||||
src={p.substr(1, p.length - 1)}
|
||||
style={{
|
||||
width: '96px',
|
||||
'margin-bottom': '0.5rem',
|
||||
'-ms-interpolation-mode': 'nearest-neighbor',
|
||||
}}
|
||||
/><br />
|
||||
Photo #{i + 1}
|
||||
</Box>
|
||||
))
|
||||
)}
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const MedicalRecordsViewMedical = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
medical,
|
||||
} = data;
|
||||
if (!medical || !medical.fields) {
|
||||
return (
|
||||
<Box color="bad">
|
||||
Medical records lost!
|
||||
<Button
|
||||
icon="pen"
|
||||
content="New Record"
|
||||
ml="0.5rem"
|
||||
onClick={() => act('new')}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<LabeledList>
|
||||
{medical.fields.map((field, i) => (
|
||||
<LabeledList.Item
|
||||
key={i}
|
||||
label={field.field}>
|
||||
{field.value}
|
||||
<Button
|
||||
icon="pen"
|
||||
ml="0.5rem"
|
||||
mb={field.line_break ? '1rem' : 'initial'}
|
||||
onClick={() => doEdit(context, field)}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
<Section title="Comments/Log" level={2}>
|
||||
{medical.comments.length === 0 ? (
|
||||
<Box color="label">
|
||||
No comments found.
|
||||
</Box>
|
||||
)
|
||||
: medical.comments.map((comment, i) => (
|
||||
<Box key={i}>
|
||||
<Box color="label" display="inline">
|
||||
{comment.header}
|
||||
</Box><br />
|
||||
{comment.text}
|
||||
<Button
|
||||
icon="comment-slash"
|
||||
color="bad"
|
||||
ml="0.5rem"
|
||||
onClick={() => act('del_c', { del_c: i + 1 })}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
|
||||
<Button
|
||||
icon="comment-medical"
|
||||
content="Add Entry"
|
||||
color="good"
|
||||
mt="0.5rem"
|
||||
mb="0"
|
||||
onClick={() => modalOpen(context, 'add_c')}
|
||||
/>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const MedicalRecordsViruses = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
virus,
|
||||
} = data;
|
||||
virus.sort((a, b) => a.name > b.name ? 1 : -1);
|
||||
return virus.map((vir, i) => (
|
||||
<Fragment key={i}>
|
||||
<Button
|
||||
icon="flask"
|
||||
content={vir.name}
|
||||
mb="0.5rem"
|
||||
onClick={() => act('vir', { vir: vir.D })}
|
||||
/>
|
||||
<br />
|
||||
</Fragment>
|
||||
));
|
||||
};
|
||||
|
||||
const MedicalRecordsMedbots = (_properties, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
medbots,
|
||||
} = data;
|
||||
if (medbots.length === 0) {
|
||||
return (
|
||||
<Box color="label">
|
||||
There are no Medbots.
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return medbots.map((medbot, i) => (
|
||||
<Collapsible
|
||||
key={i}
|
||||
open
|
||||
title={medbot.name}>
|
||||
<Box px="0.5rem">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Location">
|
||||
{medbot.area || 'Unknown'} ({medbot.x}, {medbot.y})
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Status">
|
||||
{medbot.on ? (
|
||||
<Fragment>
|
||||
<Box color="good">
|
||||
Online
|
||||
</Box>
|
||||
<Box mt="0.5rem">
|
||||
{medbot.use_beaker
|
||||
? ("Reservoir: "
|
||||
+ medbot.total_volume + "/" + medbot.maximum_volume)
|
||||
: "Using internal synthesizer."}
|
||||
</Box>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Box color="average">
|
||||
Offline
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Box>
|
||||
</Collapsible>
|
||||
));
|
||||
};
|
||||
|
||||
const MedicalRecordsNavigation = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
screen,
|
||||
} = data;
|
||||
return (
|
||||
<Tabs>
|
||||
<Tabs.Tab
|
||||
selected={screen === 2}
|
||||
onClick={() => act('screen', { screen: 2 })}>
|
||||
<Icon name="list" />
|
||||
List Records
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
selected={screen === 5}
|
||||
onClick={() => act('screen', { screen: 5 })}>
|
||||
<Icon name="database" />
|
||||
Virus Database
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
selected={screen === 6}
|
||||
onClick={() => act('screen', { screen: 6 })}>
|
||||
<Icon name="plus-square" />
|
||||
Medbot Tracking
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
selected={screen === 3}
|
||||
onClick={() => act('screen', { screen: 3 })}>
|
||||
<Icon name="wrench" />
|
||||
Record Maintenance
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
modalRegisterBodyOverride('virus', virusModalBodyOverride);
|
||||
@@ -0,0 +1,251 @@
|
||||
import { round } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Window } from "../layouts";
|
||||
import { Box, Button, Flex, Icon, Knob, LabeledList, Section, Tabs, ProgressBar } from "../components";
|
||||
|
||||
const stats = [
|
||||
['good', 'Conscious'],
|
||||
['average', 'Unconscious'],
|
||||
['bad', 'DEAD'],
|
||||
];
|
||||
|
||||
const damages = [
|
||||
['Resp.', 'oxyLoss'],
|
||||
['Toxin', 'toxLoss'],
|
||||
['Brute', 'bruteLoss'],
|
||||
['Burn', 'fireLoss'],
|
||||
];
|
||||
|
||||
const damageRange = {
|
||||
average: [0.25, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
};
|
||||
|
||||
const tempColors = [
|
||||
'bad',
|
||||
'average',
|
||||
'average',
|
||||
'good',
|
||||
'average',
|
||||
'average',
|
||||
'bad',
|
||||
];
|
||||
|
||||
export const OperatingComputer = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
hasOccupant,
|
||||
choice,
|
||||
} = data;
|
||||
let body;
|
||||
if (!choice) {
|
||||
body = hasOccupant
|
||||
? <OperatingComputerPatient />
|
||||
: <OperatingComputerUnoccupied />;
|
||||
} else {
|
||||
body = <OperatingComputerOptions />;
|
||||
}
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
<Tabs>
|
||||
<Tabs.Tab
|
||||
selected={!choice}
|
||||
icon="user"
|
||||
onClick={() => act('choiceOff')}>
|
||||
Patient
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
selected={!!choice}
|
||||
icon="cog"
|
||||
onClick={() => act('choiceOn')}>
|
||||
Options
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
<Section flexGrow="1">
|
||||
{body}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const OperatingComputerPatient = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
occupant,
|
||||
} = data;
|
||||
return (
|
||||
<Fragment>
|
||||
<Section title="Patient" level="2">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{occupant.name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Status" color={stats[occupant.stat][0]}>
|
||||
{stats[occupant.stat][1]}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={occupant.maxHealth}
|
||||
value={occupant.health / occupant.maxHealth}
|
||||
ranges={{
|
||||
good: [0.5, Infinity],
|
||||
average: [0, 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
{damages.map((d, i) => (
|
||||
<LabeledList.Item key={i} label={d[0] + " Damage"}>
|
||||
<ProgressBar
|
||||
key={i}
|
||||
min="0"
|
||||
max="100"
|
||||
value={occupant[d[1]] / 100}
|
||||
ranges={damageRange}>
|
||||
{round(occupant[d[1]])}
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
<LabeledList.Item label="Temperature">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={occupant.maxTemp}
|
||||
value={occupant.bodyTemperature / occupant.maxTemp}
|
||||
color={tempColors[occupant.temperatureSuitability + 3]}>
|
||||
{round(occupant.btCelsius)}°C, {round(occupant.btFaren)}°F
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
{!!occupant.hasBlood && (
|
||||
<Fragment>
|
||||
<LabeledList.Item label="Blood Level">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={occupant.bloodMax}
|
||||
value={occupant.bloodLevel / occupant.bloodMax}
|
||||
ranges={{
|
||||
bad: [-Infinity, 0.6],
|
||||
average: [0.6, 0.9],
|
||||
good: [0.6, Infinity],
|
||||
}}>
|
||||
{occupant.bloodPercent}%, {occupant.bloodLevel}cl
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Pulse">
|
||||
{occupant.pulse} BPM
|
||||
</LabeledList.Item>
|
||||
</Fragment>
|
||||
)}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section title="Current Procedure" level="2">
|
||||
{occupant.inSurgery ? (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Procedure">
|
||||
{occupant.surgeryName}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Next Step">
|
||||
{occupant.stepName}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
) : (
|
||||
<Box color="label">
|
||||
No procedure ongoing.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const OperatingComputerUnoccupied = () => {
|
||||
return (
|
||||
<Flex textAlign="center" height="100%">
|
||||
<Flex.Item grow="1" align="center" color="label">
|
||||
<Icon
|
||||
name="user-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
No patient detected.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
const OperatingComputerOptions = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
verbose,
|
||||
health,
|
||||
healthAlarm,
|
||||
oxy,
|
||||
oxyAlarm,
|
||||
crit,
|
||||
} = data;
|
||||
return (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Loudspeaker">
|
||||
<Button
|
||||
selected={verbose}
|
||||
icon={verbose ? "toggle-on" : "toggle-off"}
|
||||
content={verbose ? "On" : "Off"}
|
||||
onClick={() => act(verbose ? 'verboseOff' : 'verboseOn')}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health Announcer">
|
||||
<Button
|
||||
selected={health}
|
||||
icon={health ? "toggle-on" : "toggle-off"}
|
||||
content={health ? "On" : "Off"}
|
||||
onClick={() => act(health ? 'healthOff' : 'healthOn')}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health Announcer Threshold">
|
||||
<Knob
|
||||
bipolar
|
||||
minValue="-100"
|
||||
maxValue="100"
|
||||
value={healthAlarm}
|
||||
stepPixelSize="5"
|
||||
ml="0"
|
||||
onChange={(e, val) => act('health_adj', {
|
||||
new: val,
|
||||
})}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Oxygen Alarm">
|
||||
<Button
|
||||
selected={oxy}
|
||||
icon={oxy ? "toggle-on" : "toggle-off"}
|
||||
content={oxy ? "On" : "Off"}
|
||||
onClick={() => act(oxy ? 'oxyOff' : 'oxyOn')}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Oxygen Alarm Threshold">
|
||||
<Knob
|
||||
bipolar
|
||||
minValue="-100"
|
||||
maxValue="100"
|
||||
value={oxyAlarm}
|
||||
stepPixelSize="5"
|
||||
ml="0"
|
||||
onChange={(e, val) => act('oxy_adj', {
|
||||
new: val,
|
||||
})}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Critical Alert">
|
||||
<Button
|
||||
selected={crit}
|
||||
icon={crit ? "toggle-on" : "toggle-off"}
|
||||
content={crit ? "On" : "Off"}
|
||||
onClick={() => act(crit ? 'critOff' : 'critOn')}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,315 @@
|
||||
import { round } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
const stats = [
|
||||
['good', 'Alive'],
|
||||
['average', 'Critical'],
|
||||
['bad', 'DEAD'],
|
||||
];
|
||||
|
||||
const damages = [
|
||||
['Resp.', 'oxyLoss'],
|
||||
['Toxin', 'toxLoss'],
|
||||
['Brute', 'bruteLoss'],
|
||||
['Burn', 'fireLoss'],
|
||||
];
|
||||
|
||||
const damageRange = {
|
||||
average: [0.25, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
};
|
||||
|
||||
const tempColors = [
|
||||
'bad',
|
||||
'average',
|
||||
'average',
|
||||
'good',
|
||||
'average',
|
||||
'average',
|
||||
'bad',
|
||||
];
|
||||
|
||||
export const Sleeper = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
hasOccupant,
|
||||
} = data;
|
||||
const body = hasOccupant ? <SleeperMain /> : <SleeperEmpty />;
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
{body}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const SleeperMain = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
occupant,
|
||||
} = data;
|
||||
return (
|
||||
<Fragment>
|
||||
<SleeperOccupant />
|
||||
<SleeperDamage />
|
||||
<SleeperChemicals />
|
||||
<SleeperDialysis />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const SleeperOccupant = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
occupant,
|
||||
auto_eject_dead,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Occupant"
|
||||
buttons={(
|
||||
<Fragment>
|
||||
<Box color="label" display="inline">
|
||||
Auto-eject if dead:
|
||||
</Box>
|
||||
<Button
|
||||
icon={auto_eject_dead ? "toggle-on" : "toggle-off"}
|
||||
selected={auto_eject_dead}
|
||||
content={auto_eject_dead ? 'On' : 'Off'}
|
||||
onClick={() =>
|
||||
act('auto_eject_dead_' + (auto_eject_dead ? 'off' : 'on'))}
|
||||
/>
|
||||
<Button
|
||||
icon="user-slash"
|
||||
content="Eject"
|
||||
onClick={() => act('ejectify')}
|
||||
/>
|
||||
</Fragment>
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{occupant.name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={occupant.maxHealth}
|
||||
value={occupant.health / occupant.maxHealth}
|
||||
ranges={{
|
||||
good: [0.5, Infinity],
|
||||
average: [0, 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}>
|
||||
{round(occupant.health, 0)}
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Status" color={stats[occupant.stat][0]}>
|
||||
{stats[occupant.stat][1]}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Temperature">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={occupant.maxTemp}
|
||||
value={occupant.bodyTemperature / occupant.maxTemp}
|
||||
color={tempColors[occupant.temperatureSuitability + 3]}>
|
||||
{round(occupant.btCelsius, 0)}°C,
|
||||
{round(occupant.btFaren, 0)}°F
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
{!!occupant.hasBlood && (
|
||||
<Fragment>
|
||||
<LabeledList.Item label="Blood Level">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={occupant.bloodMax}
|
||||
value={occupant.bloodLevel / occupant.bloodMax}
|
||||
ranges={{
|
||||
bad: [-Infinity, 0.6],
|
||||
average: [0.6, 0.9],
|
||||
good: [0.6, Infinity],
|
||||
}}>
|
||||
{occupant.bloodPercent}%, {occupant.bloodLevel}cl
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Pulse" verticalAlign="middle">
|
||||
{occupant.pulse} BPM
|
||||
</LabeledList.Item>
|
||||
</Fragment>
|
||||
)}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const SleeperDamage = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
occupant,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Damage">
|
||||
<LabeledList>
|
||||
{damages.map((d, i) => (
|
||||
<LabeledList.Item key={i} label={d[0]}>
|
||||
<ProgressBar
|
||||
key={i}
|
||||
min="0"
|
||||
max="100"
|
||||
value={occupant[d[1]] / 100}
|
||||
ranges={damageRange}>
|
||||
{round(occupant[d[1]], 0)}
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const SleeperDialysis = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isBeakerLoaded,
|
||||
beakerMaxSpace,
|
||||
beakerFreeSpace,
|
||||
dialysis,
|
||||
} = data;
|
||||
const canDialysis = dialysis && beakerFreeSpace > 0;
|
||||
return (
|
||||
<Section
|
||||
title="Dialysis"
|
||||
buttons={
|
||||
<Fragment>
|
||||
<Button
|
||||
disabled={!isBeakerLoaded || beakerFreeSpace <= 0}
|
||||
selected={canDialysis}
|
||||
icon={canDialysis ? "toggle-on" : "toggle-off"}
|
||||
content={canDialysis ? "Active" : "Inactive"}
|
||||
onClick={() => act('togglefilter')}
|
||||
/>
|
||||
<Button
|
||||
disabled={!isBeakerLoaded}
|
||||
icon="eject"
|
||||
content="Eject"
|
||||
onClick={() => act('removebeaker')}
|
||||
/>
|
||||
</Fragment>
|
||||
}>
|
||||
{isBeakerLoaded ? (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Remaining Space">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={beakerMaxSpace}
|
||||
value={beakerFreeSpace / beakerMaxSpace}
|
||||
ranges={{
|
||||
good: [0.5, Infinity],
|
||||
average: [0.25, 0.5],
|
||||
bad: [-Infinity, 0.25],
|
||||
}}>
|
||||
{beakerFreeSpace}u
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
) : (
|
||||
<Box color="label">
|
||||
No beaker loaded.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const SleeperChemicals = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
occupant,
|
||||
chemicals,
|
||||
maxchem,
|
||||
amounts,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Chemicals" flexGrow="1">
|
||||
{chemicals.map((chem, i) => {
|
||||
let barColor = '';
|
||||
let odWarning;
|
||||
if (chem.overdosing) {
|
||||
barColor = 'bad';
|
||||
odWarning = (
|
||||
<Box color="bad">
|
||||
<Icon name="exclamation-circle" />
|
||||
Overdosing!
|
||||
</Box>
|
||||
);
|
||||
} else if (chem.od_warning) {
|
||||
barColor = 'average';
|
||||
odWarning = (
|
||||
<Box color="average">
|
||||
<Icon name="exclamation-triangle" />
|
||||
Close to overdosing
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Box key={i} backgroundColor="rgba(0, 0, 0, 0.33)" mb="0.5rem">
|
||||
<Section
|
||||
title={chem.title}
|
||||
level="3"
|
||||
mx="0"
|
||||
lineHeight="18px"
|
||||
buttons={odWarning}>
|
||||
<Flex align="flex-start">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={maxchem}
|
||||
value={chem.occ_amount / maxchem}
|
||||
color={barColor}
|
||||
mr="0.5rem">
|
||||
{chem.pretty_amount}/{maxchem}u
|
||||
</ProgressBar>
|
||||
{amounts.map((a, i) => (
|
||||
<Button
|
||||
key={i}
|
||||
disabled={!chem.injectable
|
||||
|| ((chem.occ_amount + a) > maxchem)
|
||||
|| occupant.stat === 2}
|
||||
icon="syringe"
|
||||
content={a}
|
||||
mb="0"
|
||||
height="19px"
|
||||
onClick={() => act('chemical', {
|
||||
chemid: chem.id,
|
||||
amount: a,
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</Section>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const SleeperEmpty = (props, context) => {
|
||||
return (
|
||||
<Section textAlign="center" flexGrow="1">
|
||||
<Flex height="100%">
|
||||
<Flex.Item grow="1" align="center" color="label">
|
||||
<Icon
|
||||
name="user-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
No occupant detected.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Box } from '../../components';
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
const formatUnits = a => a + ' unit' + (a === 1 ? '' : 's');
|
||||
|
||||
/**
|
||||
* Displays a beaker's contents
|
||||
* @property {object} props
|
||||
*/
|
||||
export const BeakerContents = props => {
|
||||
const { beakerLoaded, beakerContents = [], buttons } = props;
|
||||
return (
|
||||
<Box>
|
||||
{!beakerLoaded && (
|
||||
<Box color="label">
|
||||
No beaker loaded.
|
||||
</Box>
|
||||
) || beakerContents.length === 0 && (
|
||||
<Box color="label">
|
||||
Beaker is empty.
|
||||
</Box>
|
||||
)}
|
||||
{beakerContents.map((chemical, i) => (
|
||||
<Box key={chemical.name} width="100%">
|
||||
<Box color="label" display="inline" verticalAlign="middle">
|
||||
{formatUnits(chemical.volume)} of {chemical.name}
|
||||
</Box>
|
||||
{!!buttons && (
|
||||
<Box float="right" display="inline">
|
||||
{buttons(chemical, i)}
|
||||
</Box>
|
||||
)}
|
||||
<Box clear="both" />
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
BeakerContents.propTypes = {
|
||||
/**
|
||||
* Whether there is a loaded beaker or not
|
||||
*/
|
||||
beakerLoaded: PropTypes.bool,
|
||||
/**
|
||||
* The reagents in the beaker
|
||||
*/
|
||||
beakerContents: PropTypes.array,
|
||||
/**
|
||||
* The buttons to display next to each reagent line
|
||||
*/
|
||||
buttons: PropTypes.arrayOf(PropTypes.element),
|
||||
};
|
||||
@@ -0,0 +1,198 @@
|
||||
import { useBackend } from "../../backend";
|
||||
import { Box, Button, Dropdown, Flex, Input, Modal } from '../../components';
|
||||
|
||||
let bodyOverrides = {};
|
||||
|
||||
/**
|
||||
* Sends a call to BYOND to open a modal
|
||||
* @param {any} context The React context
|
||||
* @param {string} id The identifier of the modal
|
||||
* @param {object=} args The arguments to pass to the modal
|
||||
*/
|
||||
export const modalOpen = (context, id, args) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const newArgs = Object.assign(data.modal ? data.modal.args : {}, args || {});
|
||||
|
||||
act('modal_open', {
|
||||
id: id,
|
||||
arguments: JSON.stringify(newArgs),
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers an override for any modal with the given id
|
||||
* @param {string} id The identifier of the modal
|
||||
* @param {function} bodyOverride The override function that returns the
|
||||
* modal contents
|
||||
*/
|
||||
export const modalRegisterBodyOverride = (id, bodyOverride) => {
|
||||
bodyOverrides[id] = bodyOverride;
|
||||
};
|
||||
|
||||
const modalAnswer = (context, id, answer, args) => {
|
||||
const { act, data } = useBackend(context);
|
||||
if (!data.modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newArgs = Object.assign(data.modal.args || {}, args || {});
|
||||
act('modal_answer', {
|
||||
id: id,
|
||||
answer: answer,
|
||||
arguments: JSON.stringify(newArgs),
|
||||
});
|
||||
};
|
||||
|
||||
const modalClose = (context, id) => {
|
||||
const { act } = useBackend(context);
|
||||
act('modal_close', {
|
||||
id: id,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays a modal and its actions. Passed data must have a valid modal field
|
||||
*
|
||||
* **A valid modal field contains:**
|
||||
*
|
||||
* `id` — The identifier of the modal.
|
||||
* Used for server-client communication and overriding
|
||||
*
|
||||
* `text` — The text of the modal
|
||||
*
|
||||
* `type` — The type of the modal:
|
||||
* `message`, `input`, `choice`, `bento` and `boolean`.
|
||||
* Overriden by a body override registered to the identifier if applicable.
|
||||
* Defaults to `message` if not found
|
||||
* @param {object} props
|
||||
* @param {object} context
|
||||
*/
|
||||
export const ComplexModal = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
if (!data.modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
id,
|
||||
text,
|
||||
type,
|
||||
} = data.modal;
|
||||
|
||||
let modalOnEnter;
|
||||
let modalBody;
|
||||
let modalFooter = (
|
||||
<Button
|
||||
icon="arrow-left"
|
||||
content="Cancel"
|
||||
color="grey"
|
||||
onClick={() => modalClose(context)}
|
||||
/>
|
||||
);
|
||||
|
||||
// Different contents depending on the type
|
||||
if (bodyOverrides[id]) {
|
||||
modalBody = bodyOverrides[id](data.modal, context);
|
||||
} else if (type === "input") {
|
||||
let curValue = data.modal.value;
|
||||
modalOnEnter = e => modalAnswer(context, id, curValue);
|
||||
modalBody = (
|
||||
<Input
|
||||
value={data.modal.value}
|
||||
placeholder="ENTER to submit"
|
||||
width="100%"
|
||||
my="0.5rem"
|
||||
autofocus
|
||||
onChange={(_e, val) => {
|
||||
curValue = val;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
modalFooter = (
|
||||
<Box mt="0.5rem">
|
||||
<Button
|
||||
icon="arrow-left"
|
||||
content="Cancel"
|
||||
color="grey"
|
||||
onClick={() => modalClose(context)}
|
||||
/>
|
||||
<Button
|
||||
icon="check"
|
||||
content={"Confirm"}
|
||||
color="good"
|
||||
float="right"
|
||||
m="0"
|
||||
onClick={() => modalAnswer(context, id, curValue)}
|
||||
/>
|
||||
<Box clear="both" />
|
||||
</Box>
|
||||
);
|
||||
} else if (type === "choice") {
|
||||
const realChoices = (typeof data.modal.choices === "object")
|
||||
? Object.values(data.modal.choices)
|
||||
: data.modal.choices;
|
||||
modalBody = (
|
||||
<Dropdown
|
||||
options={realChoices}
|
||||
selected={data.modal.value}
|
||||
width="100%"
|
||||
my="0.5rem"
|
||||
onSelected={val => modalAnswer(context, id, val)}
|
||||
/>
|
||||
);
|
||||
} else if (type === "bento") {
|
||||
modalBody = (
|
||||
<Flex
|
||||
spacingPrecise="1"
|
||||
wrap="wrap"
|
||||
my="0.5rem"
|
||||
maxHeight="1%">
|
||||
{data.modal.choices.map((c, i) => (
|
||||
<Flex.Item key={i} flex="1 1 auto">
|
||||
<Button
|
||||
selected={(i + 1) === parseInt(data.modal.value, 10)}
|
||||
onClick={() => modalAnswer(context, id, i + 1)}>
|
||||
<img src={c} />
|
||||
</Button>
|
||||
</Flex.Item>
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
} else if (type === "boolean") {
|
||||
modalFooter = (
|
||||
<Box mt="0.5rem">
|
||||
<Button
|
||||
icon="times"
|
||||
content={data.modal.no_text}
|
||||
color="bad"
|
||||
float="left"
|
||||
mb="0"
|
||||
onClick={() => modalAnswer(context, id, 0)}
|
||||
/>
|
||||
<Button
|
||||
icon="check"
|
||||
content={data.modal.yes_text}
|
||||
color="good"
|
||||
float="right"
|
||||
m="0"
|
||||
onClick={() => modalAnswer(context, id, 1)}
|
||||
/>
|
||||
<Box clear="both" />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
maxWidth={props.maxWidth || (window.innerWidth / 2 + "px")}
|
||||
maxHeight={props.maxHeight || (window.innerHeight / 2 + "px")}
|
||||
onEnter={modalOnEnter}
|
||||
mx="auto">
|
||||
<Box display="inline">
|
||||
{text}
|
||||
</Box>
|
||||
{modalBody}
|
||||
{modalFooter}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useBackend } from '../../backend';
|
||||
import { Box, Button, NoticeBox } from '../../components';
|
||||
|
||||
/**
|
||||
* Displays a notice box showing the
|
||||
* `authenticated` and `rank` data fields if they exist.
|
||||
*
|
||||
* Also gives an option to log off (calls `logout` TGUI action)
|
||||
* @param {object} _properties
|
||||
* @param {object} context
|
||||
*/
|
||||
export const LoginInfo = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
authenticated,
|
||||
rank,
|
||||
} = data;
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
return (
|
||||
<NoticeBox info>
|
||||
<Box display="inline-block" verticalAlign="middle">
|
||||
Logged in as: {authenticated} ({rank})
|
||||
</Box>
|
||||
<Button
|
||||
icon="sign-out-alt"
|
||||
content="Logout and Eject ID"
|
||||
color="good"
|
||||
float="right"
|
||||
onClick={() => act('logout')}
|
||||
/>
|
||||
<Box clear="both" />
|
||||
</NoticeBox>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
import { useBackend } from '../../backend';
|
||||
import { Box, Button, Flex, Icon, Section } from '../../components';
|
||||
|
||||
/**
|
||||
* Displays a login screen that users can interact with
|
||||
* using an ID card in their hand.
|
||||
* Required data fields:
|
||||
* * `scan` — The name of the currently inserted ID
|
||||
* * `isAI` — Whether the user is an AI. If true, shows "Login as AI"
|
||||
* * `isRobot` — Whether the user is a robot. If true, shows "Login as Cyborg"
|
||||
*
|
||||
* Clicking the main button calls the `scan` TGUI act.
|
||||
* Clicking either the AI or normal login button calls
|
||||
* the `login` TGUI act with the a `login_type` parameter with the value:
|
||||
* * 1 (LOGIN_TYPE_NORMAL) if it's an ID login
|
||||
* * 2 (LOGIN_TYPE_AI) if it's an AI login
|
||||
* * 3 (LOGIN_TYPE_ROBOT) if it's a robot login
|
||||
*
|
||||
* You will have to handle the AI login case in the same action.
|
||||
* The normal login button is only available when `scan` is not null.
|
||||
* The AI and robot login buttons are only visible if the user is one
|
||||
* @param {object} _properties
|
||||
* @param {object} context
|
||||
*/
|
||||
export const LoginScreen = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
scan,
|
||||
isAI,
|
||||
isRobot,
|
||||
} = data;
|
||||
return (
|
||||
<Section title="Welcome" height="100%" stretchContents>
|
||||
<Flex height="100%" align="center" justify="center">
|
||||
<Flex.Item textAlign="center" mt="-2rem">
|
||||
<Box fontSize="1.5rem" bold>
|
||||
<Icon
|
||||
name="user-circle"
|
||||
verticalAlign="middle"
|
||||
size={3}
|
||||
mr="1rem"
|
||||
/>
|
||||
Guest
|
||||
</Box>
|
||||
<Box color="label" my="1rem">
|
||||
ID:
|
||||
<Button
|
||||
icon="id-card"
|
||||
content={scan ? scan : "----------"}
|
||||
ml="0.5rem"
|
||||
onClick={() => act('scan')}
|
||||
/>
|
||||
</Box>
|
||||
<Button
|
||||
icon="sign-in-alt"
|
||||
disabled={!scan}
|
||||
content="Login"
|
||||
onClick={() => act('login', {
|
||||
login_type: 1,
|
||||
})}
|
||||
/>
|
||||
{!!isAI && (
|
||||
<Button
|
||||
icon="sign-in-alt"
|
||||
content="Login as AI"
|
||||
onClick={() => act('login', {
|
||||
login_type: 2,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{!!isRobot && (
|
||||
<Button
|
||||
icon="sign-in-alt"
|
||||
content="Login as Cyborg"
|
||||
onClick={() => act('login', {
|
||||
login_type: 3,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useBackend } from "../../backend";
|
||||
import { Box, Button, NoticeBox } from "../../components";
|
||||
|
||||
/**
|
||||
* Displays a notice box with text and style dictated by the
|
||||
* `temp` data field if it exists.
|
||||
*
|
||||
* A valid `temp` object contains:
|
||||
*
|
||||
* - `style` — The style of the NoticeBox
|
||||
* - `text` — The text to display
|
||||
*
|
||||
* Allows clearing the notice through the `cleartemp` TGUI act
|
||||
* @param {object} _properties
|
||||
* @param {object} context
|
||||
*/
|
||||
export const TemporaryNotice = (_properties, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const { temp } = data;
|
||||
if (!temp) {
|
||||
return;
|
||||
}
|
||||
const temporaryProperty = { [temp.style]: true };
|
||||
return (
|
||||
<NoticeBox {...temporaryProperty}>
|
||||
<Box display="inline-block" verticalAlign="middle">
|
||||
{temp.text}
|
||||
</Box>
|
||||
<Button
|
||||
icon="times-circle"
|
||||
float="right"
|
||||
onClick={() => act('cleartemp')} />
|
||||
<Box clear="both" />
|
||||
</NoticeBox>
|
||||
);
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -33,4 +33,12 @@
|
||||
margin: 0 3px * $i;
|
||||
}
|
||||
}
|
||||
|
||||
.Flex--spacingPrecise--#{$i} {
|
||||
margin: -1px * $i -1px * $i;
|
||||
|
||||
& > .Flex__item {
|
||||
margin: 1px * $i 1px * $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ $inner-padding: 0.1em;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.Knob__popupValue {
|
||||
.Knob__popupValue, .Knob__popupValue--right {
|
||||
position: absolute;
|
||||
top: -2rem;
|
||||
right: 50%;
|
||||
@@ -71,6 +71,11 @@ $inner-padding: 0.1em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.Knob__popupValue--right {
|
||||
top: 0.25rem;
|
||||
right: -50%;
|
||||
}
|
||||
|
||||
.Knob__ring {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
@@ -41,3 +41,8 @@
|
||||
padding-top: 1px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.LabeledList__breakContents {
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
@@ -47,8 +47,17 @@ $color-separator: colors.$primary !default;
|
||||
}
|
||||
}
|
||||
|
||||
.Section--flex {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
.Section--flex .Section__content {
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.Section__title {
|
||||
position: relative;
|
||||
padding: 6px;
|
||||
border-bottom: 2px solid $color-separator;
|
||||
}
|
||||
@@ -69,6 +78,14 @@ $color-separator: colors.$primary !default;
|
||||
padding: 8px 6px;
|
||||
}
|
||||
|
||||
.Section__content--noTopPadding {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.Section__content--stretchContents {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Section--level--1 .Section__titleText {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,26 @@ $border-radius: base.$border-radius !default;
|
||||
transform: translateX(-50%) translateY(-8px);
|
||||
}
|
||||
|
||||
.Tooltip--top-left::after {
|
||||
bottom: 100%;
|
||||
right: 50%;
|
||||
transform: translateX(12px) translateY(-8px);
|
||||
}
|
||||
|
||||
.Tooltip--top-left:hover::after {
|
||||
transform: translateX(12px) translateY(8px);
|
||||
}
|
||||
|
||||
.Tooltip--top-right::after {
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-12px) translateY(-8px);
|
||||
}
|
||||
|
||||
.Tooltip--top-right:hover::after {
|
||||
transform: translateX(-12px) translateY(8px);
|
||||
}
|
||||
|
||||
.Tooltip--bottom::after {
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
|
||||
Reference in New Issue
Block a user