mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-26 21:48:21 +01:00
TGUI Medical: ChemMaster 3000
This commit is contained in:
@@ -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,287 +146,93 @@
|
||||
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(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 += "<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)
|
||||
@@ -434,27 +244,28 @@
|
||||
/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
|
||||
@@ -468,9 +279,252 @@
|
||||
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_DELEGATE)
|
||||
// Do something after successful delegate call
|
||||
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
|
||||
if(TGUI_MODAL_CLOSE)
|
||||
//
|
||||
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
|
||||
|
||||
+28
-26
@@ -137,8 +137,8 @@ GLOBAL_LIST(tgui_modals)
|
||||
* * 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
|
||||
* * value - The default value of the bento
|
||||
* * choices - The list of available choices in the bento
|
||||
*/
|
||||
/proc/tgui_modal_bento(datum/source = src, id, text = "Default modal message", delegate, arguments, value, choices)
|
||||
ASSERT(length(id))
|
||||
@@ -162,7 +162,7 @@ GLOBAL_LIST(tgui_modals)
|
||||
/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, arguments, delegate_no, yes_text, no_text)
|
||||
var/datum/tgui_modal/boolean/modal = new(id, text, delegate, delegate_no, arguments, yes_text, no_text)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
@@ -182,6 +182,8 @@ GLOBAL_LIST(tgui_modals)
|
||||
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)
|
||||
@@ -227,18 +229,28 @@ GLOBAL_LIST(tgui_modals)
|
||||
* 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, arguments)
|
||||
/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
|
||||
*
|
||||
@@ -247,18 +259,9 @@ GLOBAL_LIST(tgui_modals)
|
||||
*/
|
||||
/datum/tgui_modal/proc/on_answer(answer)
|
||||
if(delegate)
|
||||
return call(src, delegate)(answer, arguments)
|
||||
return call(owning_source, delegate)(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* 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, MAX_MESSAGE_LEN) // bleh
|
||||
|
||||
/**
|
||||
* Creates a list that describes a modal visually to be passed to JS
|
||||
*/
|
||||
@@ -277,20 +280,20 @@ GLOBAL_LIST(tgui_modals)
|
||||
var/value
|
||||
var/max_length
|
||||
|
||||
/datum/tgui_modal/input/New(id, text, delegate, arguments, value, 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/to_data()
|
||||
. = ..()
|
||||
.["value"] = value
|
||||
|
||||
/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
|
||||
*/
|
||||
@@ -298,7 +301,7 @@ GLOBAL_LIST(tgui_modals)
|
||||
modal_type = "choice"
|
||||
var/choices
|
||||
|
||||
/datum/tgui_modal/input/choice/New(id, text, delegate, arguments, value, 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
|
||||
|
||||
@@ -320,15 +323,14 @@ GLOBAL_LIST(tgui_modals)
|
||||
modal_type = "bento"
|
||||
var/choices
|
||||
|
||||
/datum/tgui_modal/input/bento/New(id, text, delegate, arguments, value, 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 reject_bad_text(answer, MAX_MESSAGE_LEN) // bleh
|
||||
return text2num(answer) || 0
|
||||
|
||||
/datum/tgui_modal/input/bento/on_answer(answer)
|
||||
answer = text2num(answer) || 0
|
||||
if(answer >= 1 && answer <= length(choices)) // Make sure the answer index is actually in our indexes!
|
||||
return ..(answer, arguments)
|
||||
return FALSE
|
||||
@@ -346,20 +348,20 @@ GLOBAL_LIST(tgui_modals)
|
||||
var/yes_text
|
||||
var/no_text
|
||||
|
||||
/datum/tgui_modal/boolean/New(id, text, delegate, delegate_no, arguments, yes_text, 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/input/bento/preprocess_answer(answer)
|
||||
/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(src, delegate_no)(arguments)
|
||||
return call(owning_source, delegate_no)(arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/boolean/to_data()
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1,406 @@
|
||||
import { round, toFixed } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Window } from "../layouts";
|
||||
import { Box, Button, Flex, Icon, Section, LabeledList } from "../components";
|
||||
import { BeakerContents } from './common/BeakerContents';
|
||||
import { modalOpen, modalRegisterBodyOverride, ComplexModal } 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;
|
||||
modalRegisterBodyOverride('analyze', analyzeModalBodyOverride);
|
||||
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"
|
||||
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"
|
||||
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)"
|
||||
mr="0.5rem"
|
||||
onClick={() => modalOpen(context, 'create_pill')}
|
||||
/>
|
||||
<Button
|
||||
icon="plus-circle"
|
||||
content="Multiple"
|
||||
mb="0.5rem"
|
||||
onClick={() => modalOpen(context, 'create_pill_multiple')}
|
||||
/><br />
|
||||
<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')}
|
||||
/><br />
|
||||
<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"}
|
||||
mb="0.5rem"
|
||||
onClick={() => act('ejectp')}
|
||||
/><br />
|
||||
<Button
|
||||
disabled={!data.loaded_pill_bottle}
|
||||
icon="palette"
|
||||
content="Change wrapper"
|
||||
mb="0"
|
||||
onClick={() => modalOpen(context, 'change_pill_bottle_style')}
|
||||
/>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
@@ -3,7 +3,7 @@ import { Box } from '../../components';
|
||||
const formatUnits = a => a + ' unit' + (a === 1 ? '' : 's');
|
||||
|
||||
export const BeakerContents = props => {
|
||||
const { beakerLoaded, beakerContents, buttons } = props;
|
||||
const { beakerLoaded, beakerContents = [], buttons } = props;
|
||||
return (
|
||||
<Box>
|
||||
{!beakerLoaded && (
|
||||
@@ -15,18 +15,17 @@ export const BeakerContents = props => {
|
||||
Beaker is empty.
|
||||
</Box>
|
||||
)}
|
||||
{beakerContents.map(chemical => (
|
||||
<Box key={chemical.name} clear="both">
|
||||
<Box color="label" float="left">
|
||||
<Box verticalAlign="middle">
|
||||
{formatUnits(chemical.volume)} of {chemical.name}
|
||||
</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">
|
||||
{buttons(chemical)}
|
||||
<Box float="right" display="inline">
|
||||
{buttons(chemical, i)}
|
||||
</Box>
|
||||
)}
|
||||
<Box clear="both" />
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useBackend } from "../../backend";
|
||||
import { Box, Button, Dropdown, Flex, Input, Modal } from '../../components';
|
||||
|
||||
let bodyOverrides = {};
|
||||
|
||||
export const modalOpen = (context, id, args) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const newArgs = Object.assign(data.modal
|
||||
? data.modal.args
|
||||
: {},
|
||||
args || {}
|
||||
);
|
||||
const newArgs = Object.assign(data.modal ? data.modal.args : {}, args || {});
|
||||
|
||||
act('modal_open', {
|
||||
id: id,
|
||||
@@ -15,6 +13,10 @@ export const modalOpen = (context, id, args) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const modalRegisterBodyOverride = (id, bodyOverride) => {
|
||||
bodyOverrides[id] = bodyOverride;
|
||||
};
|
||||
|
||||
const modalAnswer = (context, id, answer, args) => {
|
||||
const { act, data } = useBackend(context);
|
||||
if (!data.modal) {
|
||||
@@ -60,7 +62,9 @@ export const ComplexModal = (props, context) => {
|
||||
);
|
||||
|
||||
// Different contents depending on the type
|
||||
if (type === "input") {
|
||||
if (bodyOverrides[id]) {
|
||||
modalBody = bodyOverrides[id](data.modal, context);
|
||||
} else if (type === "input") {
|
||||
modalBody = (
|
||||
<Input
|
||||
value={data.modal.value}
|
||||
@@ -72,9 +76,12 @@ export const ComplexModal = (props, context) => {
|
||||
/>
|
||||
);
|
||||
} else if (type === "choice") {
|
||||
const realChoices = (typeof data.modal.choices === "object")
|
||||
? Object.values(data.modal.choices)
|
||||
: data.modal.choices;
|
||||
modalBody = (
|
||||
<Dropdown
|
||||
options={data.modal.choices.split(',')}
|
||||
options={realChoices}
|
||||
selected={data.modal.value}
|
||||
width="100%"
|
||||
my="0.5rem"
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -41,3 +41,8 @@
|
||||
padding-top: 1px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.LabeledList__breakContents {
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user