Merge pull request #851 from ArchieBeepBoop/tguisecondary

Bringing TGUI to the Medbay + TGUI Uplink + Extras
This commit is contained in:
QuoteFox
2021-01-09 21:33:07 +00:00
committed by GitHub
14 changed files with 1000 additions and 259 deletions
+26 -16
View File
@@ -25,6 +25,8 @@ GLOBAL_LIST_EMPTY(uplinks)
var/unlock_code
var/failsafe_code
var/datum/ui_state/checkstate
var/compact_mode = FALSE
var/debug = FALSE
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate)
if(!isitem(parent))
@@ -121,7 +123,7 @@ GLOBAL_LIST_EMPTY(uplinks)
active = TRUE
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "uplink", name, 450, 750, master_ui, state)
ui = new(user, src, ui_key, "uplink", name, 620, 580, master_ui, state)
ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
ui.set_style("syndicate")
ui.open()
@@ -138,29 +140,35 @@ GLOBAL_LIST_EMPTY(uplinks)
var/list/data = list()
data["telecrystals"] = telecrystals
data["lockable"] = lockable
data["compact_mode"] = compact_mode
return data
/datum/component/uplink/ui_static_data(mob/user)
var/list/data = list()
data["categories"] = list()
for(var/category in uplink_items)
var/list/cat = list(
"name" = category,
"items" = (category == selected_cat ? list() : null))
if(category == selected_cat)
for(var/item in uplink_items[category])
var/datum/uplink_item/I = uplink_items[category][item]
if(I.limited_stock == 0)
for(var/item in uplink_items[category])
var/datum/uplink_item/I = uplink_items[category][item]
if(I.limited_stock == 0)
continue
if(I.restricted_roles.len)
var/is_inaccessible = TRUE
for(var/R in I.restricted_roles)
if(R == user.mind.assigned_role || debug)
is_inaccessible = FALSE
if(is_inaccessible)
continue
if(I.restricted_roles.len)
var/is_inaccessible = 1
for(var/R in I.restricted_roles)
if(R == user.mind.assigned_role)
is_inaccessible = 0
if(is_inaccessible)
continue
cat["items"] += list(list(
"name" = I.name,
"cost" = I.cost,
"desc" = I.desc,
))
cat["items"] += list(list(
"name" = I.name,
"cost" = I.cost,
"desc" = I.desc,
))
data["categories"] += list(cat)
return data
@@ -188,6 +196,8 @@ GLOBAL_LIST_EMPTY(uplinks)
SStgui.close_uis(src)
if("select")
selected_cat = params["category"]
if("compact_toggle")
compact_mode = !compact_mode
return TRUE
/datum/component/uplink/proc/MakePurchase(mob/user, datum/uplink_item/U)
@@ -294,4 +304,4 @@ GLOBAL_LIST_EMPTY(uplinks)
if(!T)
return
explosion(T,1,2,3)
qdel(parent) //Alternatively could brick the uplink.
qdel(parent) //Alternatively could brick the uplink.
@@ -381,6 +381,7 @@
playsound(src, 'sound/machines/nuke/confirm_beep.ogg', 50, FALSE)
set_active()
update_ui_mode()
. = TRUE
else
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
if("anchor")
@@ -270,7 +270,7 @@
if(!is_operational() || recording_recipe)
return
var/amount = text2num(params["amount"])
if(beaker && amount in beaker.possible_transfer_amounts)
if(beaker && (amount in beaker.possible_transfer_amounts))
beaker.reagents.remove_all(amount)
work_animation()
. = TRUE
@@ -408,7 +408,7 @@
if(beaker)
var/obj/item/reagent_containers/B = beaker
B.forceMove(drop_location())
if(user && Adjacent(user) && !issiliconoradminghost(user))
if(user && Adjacent(user) && user.can_hold_items())
user.put_in_hands(B)
if(new_beaker)
beaker = new_beaker
@@ -426,10 +426,9 @@
/obj/machinery/chem_dispenser/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
replace_beaker(user)
return TRUE
if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
replace_beaker(user)
return TRUE
/obj/machinery/chem_dispenser/drinks/Initialize()
. = ..()
@@ -488,7 +487,6 @@
/datum/reagent/consumable/pwr_game,
/datum/reagent/consumable/shamblers,
/datum/reagent/consumable/sugar,
/datum/reagent/consumable/applejuice,
/datum/reagent/consumable/pineapplejuice,
/datum/reagent/consumable/orangejuice,
/datum/reagent/consumable/grenadine,
@@ -498,18 +496,23 @@
/datum/reagent/consumable/menthol
)
upgrade_reagents = list(
/datum/reagent/drug/mushroomhallucinogen,
/datum/reagent/consumable/nothing,
/datum/reagent/medicine/cryoxadone,
/datum/reagent/consumable/vanilla,
/datum/reagent/consumable/peachjuice
)
upgrade_reagents2 = list(
/datum/reagent/consumable/banana,
/datum/reagent/consumable/berryjuice,
/datum/reagent/consumable/strawberryjuice
)
upgrade_reagents3 = null
upgrade_reagents2 = list(
/datum/reagent/consumable/applejuice,
/datum/reagent/consumable/carrotjuice,
/datum/reagent/consumable/pumpkinjuice,
/datum/reagent/consumable/watermelonjuice
)
upgrade_reagents3 = list(
/datum/reagent/drug/mushroomhallucinogen,
/datum/reagent/consumable/nothing,
/datum/reagent/medicine/cryoxadone,
/datum/reagent/consumable/peachjuice,
/datum/reagent/consumable/vanilla
)
emagged_reagents = list(
/datum/reagent/consumable/ethanol/thirteenloko,
/datum/reagent/consumable/ethanol/changelingsting,
@@ -556,9 +559,9 @@
/datum/reagent/consumable/ethanol/ale,
/datum/reagent/consumable/ethanol/absinthe,
/datum/reagent/consumable/ethanol/hcider,
/datum/reagent/consumable/ethanol/creme_de_coconut,
/datum/reagent/consumable/ethanol/creme_de_menthe,
/datum/reagent/consumable/ethanol/creme_de_cacao,
/datum/reagent/consumable/ethanol/creme_de_coconut,
/datum/reagent/consumable/ethanol/triple_sec,
/datum/reagent/consumable/ethanol/sake,
/datum/reagent/consumable/ethanol/applejack
@@ -624,7 +627,7 @@
/datum/reagent/ammonia,
/datum/reagent/ash,
/datum/reagent/diethylamine)
//same as above.
//same as above.
upgrade_reagents = null
upgrade_reagents2 = null
upgrade_reagents3 = null
@@ -32,7 +32,7 @@
for (var/x in 1 to PILL_STYLE_COUNT)
var/list/SL = list()
SL["id"] = x
SL["htmltag"] = assets.icon_tag("pill[x]")
SL["className"] = assets.icon_class_name("pill[x]") //Hyper edit. Fixes pill icons.
pillStyles += list(SL)
. = ..()
@@ -129,7 +129,7 @@
if(beaker)
var/obj/item/reagent_containers/B = beaker
B.forceMove(drop_location())
if(user && Adjacent(user) && !issiliconoradminghost(user))
if(user && Adjacent(user) && user.can_hold_items())
user.put_in_hands(B)
if(new_beaker)
beaker = new_beaker
@@ -139,7 +139,7 @@
if(bottle)
var/obj/item/storage/pill_bottle/B = bottle
B.forceMove(drop_location())
if(user && Adjacent(user) && !issiliconoradminghost(user))
if(user && Adjacent(user) && user.can_hold_items())
user.put_in_hands(B)
else
adjust_item_drop_location(B)
@@ -188,97 +188,140 @@
for(var/datum/reagent/R in beaker.reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "id" = R.type, "volume" = R.volume))) // list in a list because Byond merges the first list...
//"id" was changed to R.Type as id is now obsolete. This will allow special reagents such as synthtissue to be extracted in a chem master.
data["beakerContents"] = beakerContents
data["beakerContents"] = beakerContents
var/bufferContents[0]
if(reagents.total_volume)
for(var/datum/reagent/N in reagents.reagent_list)
bufferContents.Add(list(list("name" = N.name, "id" = N.type, "volume" = N.volume))) // ^
// ^
data["bufferContents"] = bufferContents
data["bufferContents"] = bufferContents
//Calculated at init time as it never changes
data["pillStyles"] = pillStyles
return data
/obj/machinery/chem_master/ui_act(action, params)
if(..())
return
switch(action)
if("eject")
replace_beaker(usr)
. = TRUE
if("ejectp")
if("ejectPillBottle")
replace_pillbottle(usr)
. = TRUE
if("transferToBuffer")
if(beaker)
var/reagent = text2path(params["id"]) //This change was necessary due to some byond fuckery with reagents being translated back to their paths. Please do not modify this under any circumstance, otherwise you will break synthtissue.
var/amount = text2num(params["amount"])
if (amount > 0)
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, amount)
. = TRUE
else if (amount == -1) // -1 means custom amount
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
if (useramount > 0)
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, useramount)
. = TRUE
if("transferFromBuffer")
if("transfer")
if(!beaker)
return FALSE
var/reagent = text2path(params["id"]) //This change was necessary due to some byond fuckery with reagents being translated back to their paths. Please do not modify this under any circumstance, otherwise you will break synthtissue.
var/amount = text2num(params["amount"])
if (amount > 0)
if(mode)
reagents.trans_id_to(beaker, reagent, amount)
. = TRUE
else
reagents.remove_reagent(reagent, amount)
. = TRUE
else if (amount == -1) // -1 means custom amount
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
if (useramount > 0)
end_fermi_reaction()
reagents.trans_id_to(beaker, reagent, useramount)
. = TRUE
var/to_container = params["to"]
// Custom amount
if (amount == -1)
amount = text2num(input(
"Enter the amount you want to transfer:",
name, ""))
if (amount == null || amount <= 0)
return FALSE
if (to_container == "buffer")
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, amount)
return TRUE
if (to_container == "beaker" && mode)
end_fermi_reaction()
reagents.trans_id_to(beaker, reagent, amount)
return TRUE
if (to_container == "beaker" && !mode)
end_fermi_reaction()
reagents.remove_reagent(reagent, amount)
return TRUE
return FALSE
if("toggleMode")
mode = !mode
. = TRUE
if("createPill")
var/many = params["many"]
if("pillStyle")
var/id = text2num(params["id"])
chosenPillStyle = id
return TRUE
if("create")
if(reagents.total_volume == 0)
return
if(!condi)
var/amount = 1
var/vol_each = min(reagents.total_volume, 50)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many pills?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 50)
var/name = html_decode(stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
return FALSE
var/item_type = params["type"]
// Get amount of items
var/amount = text2num(params["amount"])
if(amount == null)
amount = text2num(input(usr,
"Max 10. Buffer content will be split evenly.",
"How many to make?", 1))
amount = clamp(round(amount), 0, 10)
if (amount <= 0)
return FALSE
// Get units per item
var/vol_each = text2num(params["volume"])
var/vol_each_text = params["volume"]
var/vol_each_max = reagents.total_volume / amount
if (item_type == "pill")
vol_each_max = min(50, vol_each_max)
else if (item_type == "patch")
vol_each_max = min(40, vol_each_max)
else if (item_type == "bottle")
vol_each_max = min(30, vol_each_max)
else if (item_type == "condimentPack")
vol_each_max = min(10, vol_each_max)
else if (item_type == "condimentBottle")
vol_each_max = min(50, vol_each_max)
else if (item_type == "hypoVial")
vol_each_max = min(60, vol_each_max)
else if (item_type == "smartDart")
vol_each_max = min(20, vol_each_max)
else
return FALSE
if(vol_each_text == "auto")
vol_each = vol_each_max
if(vol_each == null)
vol_each = text2num(input(usr,
"Maximum [vol_each_max] units per item.",
"How many units to fill?",
vol_each_max))
vol_each = clamp(vol_each, 0, vol_each_max)
if(vol_each <= 0)
return FALSE
// Get item name
var/name = params["name"]
var/name_has_units = item_type == "pill" || item_type == "patch"
if(!name)
var/name_default = reagents.get_master_reagent_name()
if (name_has_units)
name_default += " ([vol_each]u)"
name = stripped_input(usr,
"Name:",
"Give it a name!",
name_default,
MAX_NAME_LEN)
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return FALSE
// Start filling
if(item_type == "pill")
var/obj/item/reagent_containers/pill/P
var/target_loc = drop_location()
var/drop_threshold = INFINITY
if(bottle)
var/datum/component/storage/STRB = bottle.GetComponent(/datum/component/storage)
var/datum/component/storage/STRB = bottle.GetComponent(
/datum/component/storage)
if(STRB)
drop_threshold = STRB.max_items - bottle.contents.len
target_loc = bottle
for(var/i in 1 to amount)
if(i <= drop_threshold)
P = new(target_loc)
for(var/i = 0; i < amount; i++)
if(i < drop_threshold)
P = new/obj/item/reagent_containers/pill(target_loc)
else
P = new(drop_location())
P = new/obj/item/reagent_containers/pill(drop_location())
P.name = trim("[name] pill")
if(chosenPillStyle == RANDOM_PILL_STYLE)
P.icon_state ="pill[rand(1,21)]"
@@ -287,171 +330,62 @@
if(P.icon_state == "pill4")
P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality."
adjust_item_drop_location(P)
reagents.trans_to(P,vol_each)
else
var/name = html_decode(stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
P.originalname = name
P.name = trim("[name] pack")
P.desc = "A small condiment pack. The label says it contains [name]."
reagents.trans_to(P,10)
. = TRUE
if("pillStyle")
var/id = text2num(params["id"])
chosenPillStyle = id
if("createPatch")
var/many = params["many"]
if(reagents.total_volume == 0)
return
var/amount = 1
var/vol_each = min(reagents.total_volume, 40)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many patches?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 40)
var/name = html_decode(stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/pill/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/pill/patch(drop_location())
P.name = trim("[name] patch")
adjust_item_drop_location(P)
reagents.trans_to(P,vol_each)
. = TRUE
if("createBottle")
var/many = params["many"]
if(reagents.total_volume == 0)
return
if(condi)
var/name = html_decode(stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/food/condiment/P = new(drop_location())
P.originalname = name
P.name = trim("[name] bottle")
reagents.trans_to(P, P.volume)
else
var/amount_full = 0
var/vol_part = min(reagents.total_volume, 30)
if(text2num(many))
amount_full = round(reagents.total_volume / 30)
vol_part = ((reagents.total_volume*1000) % 30000) / 1000 //% operator doesn't support decimals.
var/name = html_decode(stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "patch")
var/obj/item/reagent_containers/pill/patch/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/pill/patch(drop_location())
P.name = trim("[name] patch")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "bottle")
var/obj/item/reagent_containers/glass/bottle/P
for(var/i = 0; i < amount_full; i++)
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/glass/bottle(drop_location())
P.name = trim("[name] bottle")
adjust_item_drop_location(P)
reagents.trans_to(P, 30)
if(vol_part)
P = new/obj/item/reagent_containers/glass/bottle(drop_location())
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "condimentPack")
var/obj/item/reagent_containers/food/condiment/pack/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
P.originalname = name
P.name = trim("[name] pack")
P.desc = "A small condiment pack. The label says it contains [name]."
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "condimentBottle")
var/obj/item/reagent_containers/food/condiment/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/food/condiment(drop_location())
P.originalname = name
P.name = trim("[name] bottle")
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "hypoVial")
var/obj/item/reagent_containers/glass/bottle/vial/small/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_part)
. = TRUE
//CITADEL ADD Hypospray Vials
if("createVial")
var/many = params["many"]
if(reagents.total_volume == 0)
return
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "smartDart")
var/obj/item/reagent_containers/syringe/dart/P
for(var/i = 0; i < amount; i++)
P = new /obj/item/reagent_containers/syringe/dart(drop_location())
P.name = trim("[name] SmartDart")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_each)
P.mode=!mode
P.update_icon()
return TRUE
return FALSE
var/amount_full = 0
var/vol_part = min(reagents.total_volume, 60)
if(text2num(many))
amount_full = round(reagents.total_volume / 60)
vol_part = reagents.total_volume % 60
var/name = html_decode(stripped_input(usr, "Name:","Name your hypovial!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/glass/bottle/vial/small/P
for(var/i = 0; i < amount_full; i++)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, 60)
if(vol_part)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_part)
. = TRUE
if("createDart")
for(var/datum/reagent/R in reagents.reagent_list)
if(!(istype(R, /datum/reagent/medicine)))
visible_message("<b>The [src]</b> beeps, \"<span class='warning'>SmartDarts are insoluble with non-medicinal compounds.\"</span>")
return
var/many = params["many"]
if(reagents.total_volume == 0)
return
var/amount = 1
var/vol_each = min(reagents.total_volume, 20)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many darts?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 20)
var/name = html_decode(stripped_input(usr,"Name:","Name your SmartDart!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/syringe/dart/D
for(var/i = 0; i < amount; i++)
D = new /obj/item/reagent_containers/syringe/dart(drop_location())
D.name = trim("[name] SmartDart")
adjust_item_drop_location(D)
reagents.trans_to(D, vol_each)
D.mode=!mode
D.update_icon()
. = TRUE
//END CITADEL ADDITIONS
if("analyzeBeak")
var/datum/reagent/R = text2path(params["id"])
if(R)
var/state = "Unknown"
if(initial(R.reagent_state) == 1)
state = "Solid"
else if(initial(R.reagent_state) == 2)
state = "Liquid"
else if(initial(R.reagent_state) == 3)
state = "Gas"
var/const/P = 3 //The number of seconds between life ticks
var/T = initial(R.metabolization_rate) * (60 / P)
var/datum/chemical_reaction/Rcr = get_chemical_reaction(R)
if(Rcr && Rcr.FermiChem)
fermianalyze = TRUE
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
var/datum/reagent/targetReagent = beaker.reagents.has_reagent(R)
if(!targetReagent)
CRASH("Tried to find a reagent that doesn't exist in the chem_master!")
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = targetReagent.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
else
fermianalyze = FALSE
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
screen = "analyze"
return
if("analyzeBuff")
if("analyze")
var/datum/reagent/R = text2path(params["id"])
if(R)
var/state = "Unknown"
@@ -467,23 +401,18 @@
fermianalyze = TRUE
var/datum/chemical_reaction/Rcr = get_chemical_reaction(R)
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
var/datum/reagent/targetReagent = reagents.has_reagent(R)
if(!targetReagent)
CRASH("Tried to find a reagent that doesn't exist in the chem_master!")
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = targetReagent.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
else
fermianalyze = FALSE
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
screen = "analyze"
return
return TRUE
if("goScreen")
screen = params["screen"]
. = TRUE
/obj/machinery/chem_master/proc/end_fermi_reaction()//Ends any reactions upon moving.
if(beaker && beaker.reagents.fermiIsReacting)
beaker.reagents.fermiEnd()
@@ -527,4 +456,4 @@
condi = TRUE
#undef PILL_STYLE_COUNT
#undef RANDOM_PILL_STYLE
#undef RANDOM_PILL_STYLE
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,54 @@
import { useBackend } from '../backend';
import { Button, LabeledList, NumberInput, Section } from '../components';
export const AtmosRelief = props => {
const { act, data } = useBackend(props);
return (
<Section>
<LabeledList>
<LabeledList.Item label="Open Pressure">
<NumberInput
animated
value={parseFloat(data.open_pressure)}
unit="kPa"
width="75px"
minValue={0}
maxValue={4500}
step={10}
onChange={(e, value) => act('open_pressure', {
open_pressure: value,
})} />
<Button
ml={1}
icon="plus"
content="Max"
disabled={data.open_pressure === data.max_pressure}
onClick={() => act('open_pressure', {
open_pressure: 'max',
})} />
</LabeledList.Item>
<LabeledList.Item label="Close Pressure">
<NumberInput
animated
value={parseFloat(data.close_pressure)}
unit="kPa"
width="75px"
minValue={0}
maxValue={data.open_pressure}
step={10}
onChange={(e, value) => act('close_pressure', {
close_pressure: value,
})} />
<Button
ml={1}
icon="plus"
content="Max"
disabled={data.close_pressure === data.open_pressure}
onClick={() => act('close_pressure', {
close_pressure: 'max',
})} />
</LabeledList.Item>
</LabeledList>
</Section>
);
};
@@ -0,0 +1,180 @@
import { toFixed } from 'common/math';
import { toTitleCase } from 'common/string';
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { AnimatedNumber, Box, Button, Icon, LabeledList, ProgressBar, Section } from '../components';
export const ChemDispenser = props => {
const { act, data } = useBackend(props);
const recording = !!data.recordingRecipe;
// TODO: Change how this piece of shit is built on server side
// It has to be a list, not a fucking OBJECT!
const recipes = Object.keys(data.recipes)
.map(name => ({
name,
contents: data.recipes[name],
}));
const beakerTransferAmounts = data.beakerTransferAmounts || [];
const beakerContents = recording
&& Object.keys(data.recordingRecipe)
.map(id => ({
id,
name: toTitleCase(id.replace(/_/, ' ')),
volume: data.recordingRecipe[id],
}))
|| data.beakerContents
|| [];
return (
<Fragment>
<Section
title="Status"
buttons={recording && (
<Box inline mx={1} color="red">
<Icon name="circle" mr={1} />
Recording
</Box>
)}>
<LabeledList>
<LabeledList.Item label="Energy">
<ProgressBar
value={data.energy / data.maxEnergy}
content={toFixed(data.energy) + ' units'} />
</LabeledList.Item>
</LabeledList>
</Section>
<Section
title="Recipes"
buttons={(
<Fragment>
{!recording && (
<Box inline mx={1}>
<Button
color="transparent"
content="Clear recipes"
onClick={() => act('clear_recipes')} />
</Box>
)}
{!recording && (
<Button
icon="circle"
disabled={!data.isBeakerLoaded}
content="Record"
onClick={() => act('record_recipe')} />
)}
{recording && (
<Button
icon="ban"
color="transparent"
content="Discard"
onClick={() => act('cancel_recording')} />
)}
{recording && (
<Button
icon="save"
color="green"
content="Save"
onClick={() => act('save_recording')} />
)}
</Fragment>
)}>
<Box mr={-1}>
{recipes.map(recipe => (
<Button key={recipe.name}
icon="tint"
width="129.5px"
lineHeight="21px"
content={recipe.name}
onClick={() => act('dispense_recipe', {
recipe: recipe.name,
})} />
))}
{recipes.length === 0 && (
<Box color="light-gray">
No recipes.
</Box>
)}
</Box>
</Section>
<Section
title="Dispense"
buttons={(
beakerTransferAmounts.map(amount => (
<Button key={amount}
icon="plus"
selected={amount === data.amount}
content={amount}
onClick={() => act('amount', {
target: amount,
})} />
))
)}>
<Box mr={-1}>
{data.chemicals.map(chemical => (
<Button key={chemical.id}
icon="tint"
width="129.5px"
lineHeight="21px"
content={chemical.title}
onClick={() => act('dispense', {
reagent: chemical.id,
})} />
))}
</Box>
</Section>
<Section
title="Beaker"
buttons={(
beakerTransferAmounts.map(amount => (
<Button key={amount}
icon="minus"
disabled={recording}
content={amount}
onClick={() => act('remove', { amount })} />
))
)}>
<LabeledList>
<LabeledList.Item
label="Beaker"
buttons={!!data.isBeakerLoaded && (
<Button
icon="eject"
content="Eject"
disabled={!data.isBeakerLoaded}
onClick={() => act('eject')} />
)}>
{recording
&& 'Virtual beaker'
|| data.isBeakerLoaded
&& (
<Fragment>
<AnimatedNumber
initial={0}
value={data.beakerCurrentVolume} />
/{data.beakerMaxVolume} units, {data.beakerCurrentpH} pH
</Fragment>
)
|| 'No beaker'}
</LabeledList.Item>
<LabeledList.Item
label="Contents">
<Box color="label">
{(!data.isBeakerLoaded && !recording) && 'N/A'
|| beakerContents.length === 0 && 'Nothing'}
</Box>
{beakerContents.map(chemical => (
<Box
key={chemical.name}
color="label">
<AnimatedNumber
initial={0}
value={chemical.volume} />
{' '}
units of {chemical.name}
</Box>
))}
</LabeledList.Item>
</LabeledList>
</Section>
</Fragment>
);
};
@@ -0,0 +1,87 @@
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 './common/BeakerContents';
export const ChemHeater = props => {
const { act, data } = useBackend(props);
const {
targetTemp,
isActive,
isBeakerLoaded,
currentTemp,
currentpH,
beakerCurrentVolume,
beakerMaxVolume,
beakerContents = [],
} = data;
return (
<Fragment>
<Section
title="Thermostat"
buttons={(
<Button
icon={isActive ? 'power-off' : 'times'}
selected={isActive}
content={isActive ? 'On' : 'Off'}
onClick={() => act('power')} />
)}>
<LabeledList>
<LabeledList.Item label="Target">
<NumberInput
width="65px"
unit="K"
step={2}
stepPixelSize={1}
value={round(targetTemp)}
minValue={0}
maxValue={1000}
onDrag={(e, value) => act('temperature', {
target: value,
})} />
</LabeledList.Item>
<LabeledList.Item label="Temperature">
<Box
width="60px"
textAlign="right">
{isBeakerLoaded && (
<AnimatedNumber
value={currentTemp}
format={value => toFixed(value) + ' K'} />
) || '—'}
</Box>
</LabeledList.Item>
<LabeledList.Item label="pH">
<Box
width="60px"
textAlign="right">
{isBeakerLoaded && (
<AnimatedNumber
value={currentpH}
format={value => toFixed(value) + ' pH'} />
) || '-'}
</Box>
</LabeledList.Item>
</LabeledList>
</Section>
<Section
title="Beaker"
buttons={!!isBeakerLoaded && (
<Fragment>
<Box inline color="label" mr={2}>
{beakerCurrentVolume} / {beakerMaxVolume} units
</Box>
<Button
icon="eject"
content="Eject"
onClick={() => act('eject')} />
</Fragment>
)}>
<BeakerContents
beakerLoaded={isBeakerLoaded}
beakerContents={beakerContents} />
</Section>
</Fragment>
);
};
@@ -0,0 +1,450 @@
import { Component, Fragment } from 'inferno';
import { act } from '../byond';
import { AnimatedNumber, Box, Button, ColorBox, LabeledList, NumberInput, Section, Table } from '../components';
export const ChemMaster = props => {
const { state } = props;
const { config, data } = state;
const { ref } = config;
const {
screen,
beakerContents = [],
bufferContents = [],
beakerCurrentVolume,
beakerMaxVolume,
isBeakerLoaded,
isPillBottleLoaded,
pillBottleCurrentAmount,
pillBottleMaxAmount,
} = data;
if (screen === "analyze") {
return <AnalysisResults state={state} />;
}
return (
<Fragment>
<Section
title="Beaker"
buttons={!!data.isBeakerLoaded && (
<Fragment>
<Box inline color="label" mr={2}>
<AnimatedNumber
value={beakerCurrentVolume}
initial={0} />
{` / ${beakerMaxVolume} units`}
</Box>
<Button
icon="eject"
content="Eject"
onClick={() => act(ref, 'eject')} />
</Fragment>
)}>
{!isBeakerLoaded && (
<Box color="label" mt="3px" mb="5px">
No beaker loaded.
</Box>
)}
{!!isBeakerLoaded && beakerContents.length === 0 && (
<Box color="label" mt="3px" mb="5px">
Beaker is empty.
</Box>
)}
<ChemicalBuffer>
{beakerContents.map(chemical => (
<ChemicalBufferEntry
key={chemical.id}
state={state}
chemical={chemical}
transferTo="buffer" />
))}
</ChemicalBuffer>
</Section>
<Section
title="Buffer"
buttons={(
<Fragment>
<Box inline color="label" mr={1}>
Mode:
</Box>
<Button
color={data.mode ? 'good' : 'bad'}
icon={data.mode ? 'exchange-alt' : 'times'}
content={data.mode ? 'Transfer' : 'Destroy'}
onClick={() => act(ref, 'toggleMode')} />
</Fragment>
)}>
{bufferContents.length === 0 && (
<Box color="label" mt="3px" mb="5px">
Buffer is empty.
</Box>
)}
<ChemicalBuffer>
{bufferContents.map(chemical => (
<ChemicalBufferEntry
key={chemical.id}
state={state}
chemical={chemical}
transferTo="beaker" />
))}
</ChemicalBuffer>
</Section>
<Section
title="Packaging">
<PackagingControls state={state} />
</Section>
{!!isPillBottleLoaded && (
<Section
title="Pill Bottle"
buttons={(
<Fragment>
<Box inline color="label" mr={2}>
{pillBottleCurrentAmount} / {pillBottleMaxAmount} pills
</Box>
<Button
icon="eject"
content="Eject"
onClick={() => act(ref, 'ejectPillBottle')} />
</Fragment>
)} />
)}
</Fragment>
);
};
const ChemicalBuffer = Table;
const ChemicalBufferEntry = props => {
const { state, chemical, transferTo } = props;
const { ref } = state.config;
return (
<Table.Row key={chemical.id}>
<Table.Cell color="label">
<AnimatedNumber
value={chemical.volume}
initial={0} />
{` units of ${chemical.name}`}
</Table.Cell>
<Table.Cell collapsing>
<Button
content="1"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: 1,
to: transferTo,
})} />
<Button
content="5"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: 5,
to: transferTo,
})} />
<Button
content="10"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: 10,
to: transferTo,
})} />
<Button
content="All"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: 1000,
to: transferTo,
})} />
<Button
icon="ellipsis-h"
title="Custom amount"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: -1,
to: transferTo,
})} />
<Button
icon="question"
title="Analyze"
onClick={() => act(ref, 'analyze', {
id: chemical.id,
})} />
</Table.Cell>
</Table.Row>
);
};
const PackagingControlsItem = props => {
const {
label,
amountUnit,
amount,
onChangeAmount,
onCreate,
sideNote,
} = props;
return (
<LabeledList.Item label={label}>
<NumberInput
width={14}
unit={amountUnit}
step={1}
stepPixelSize={15}
value={amount}
minValue={1}
maxValue={10}
onChange={onChangeAmount} />
<Button ml={1}
content="Create"
onClick={onCreate} />
<Box inline ml={1}
color="label"
content={sideNote} />
</LabeledList.Item>
);
};
class PackagingControls extends Component {
constructor() {
super();
this.state = {
pillAmount: 1,
patchAmount: 1,
bottleAmount: 1,
packAmount: 1,
vialAmount: 1,
dartAmount: 1,
};
}
render() {
const { state, props } = this;
const { ref } = props.state.config;
const {
pillAmount,
patchAmount,
bottleAmount,
packAmount,
vialAmount,
dartAmount,
} = this.state;
const {
condi,
chosenPillStyle,
pillStyles = [],
} = props.state.data;
return (
<LabeledList>
{!condi && (
<LabeledList.Item label="Pill type">
{pillStyles.map(pill => (
<Button
key={pill.id}
width={5}
selected={pill.id === chosenPillStyle}
textAlign="center"
color="transparent"
onClick={() => act(ref, 'pillStyle', { id: pill.id })}>
<Box mx={-1} className={pill.className} />
</Button>
))}
</LabeledList.Item>
)}
{!condi && (
<PackagingControlsItem
label="Pills"
amount={pillAmount}
amountUnit="pills"
sideNote="max 50u"
onChangeAmount={(e, value) => this.setState({
pillAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'pill',
amount: pillAmount,
volume: 'auto',
})} />
)}
{!condi && (
<PackagingControlsItem
label="Patches"
amount={patchAmount}
amountUnit="patches"
sideNote="max 40u"
onChangeAmount={(e, value) => this.setState({
patchAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'patch',
amount: patchAmount,
volume: 'auto',
})} />
)}
{!condi && (
<PackagingControlsItem
label="Bottles"
amount={bottleAmount}
amountUnit="bottles"
sideNote="max 30u"
onChangeAmount={(e, value) => this.setState({
bottleAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'bottle',
amount: bottleAmount,
volume: 'auto',
})} />
)}
{!condi && (
<PackagingControlsItem
label="Hypovials"
amount={vialAmount}
amountUnit="vials"
sideNote="max 60u"
onChangeAmount={(e, value) => this.setState({
vialAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'hypoVial',
amount: vialAmount,
volume: 'auto',
})} />
)}
{!condi && (
<PackagingControlsItem
label="Smartdarts"
amount={dartAmount}
amountUnit="darts"
sideNote="max 20u"
onChangeAmount={(e, value) => this.setState({
dartAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'smartDart',
amount: dartAmount,
volume: 'auto',
})} />
)}
{!!condi && (
<PackagingControlsItem
label="Packs"
amount={packAmount}
amountUnit="packs"
sideNote="max 10u"
onChangeAmount={(e, value) => this.setState({
packAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'condimentPack',
amount: packAmount,
volume: 'auto',
})} />
)}
{!!condi && (
<PackagingControlsItem
label="Bottles"
amount={bottleAmount}
amountUnit="bottles"
sideNote="max 50u"
onChangeAmount={(e, value) => this.setState({
bottleAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'condimentBottle',
amount: bottleAmount,
volume: 'auto',
})} />
)}
</LabeledList>
);
}
}
const AnalysisResults = props => {
const { state } = props;
const { ref } = state.config;
const { analyzeVars, fermianalyze } = state.data;
return (
<Section
title="Analysis Results"
buttons={(
<Button
icon="arrow-left"
content="Back"
onClick={() => act(ref, 'goScreen', {
screen: 'home',
})} />
)}>
{!fermianalyze && (
<LabeledList>
<LabeledList.Item label="Name">
{analyzeVars.name}
</LabeledList.Item>
<LabeledList.Item label="State">
{analyzeVars.state}
</LabeledList.Item>
<LabeledList.Item label="Color">
<ColorBox color={analyzeVars.color} mr={1} />
{analyzeVars.color}
</LabeledList.Item>
<LabeledList.Item label="Description">
{analyzeVars.description}
</LabeledList.Item>
<LabeledList.Item label="Metabolization Rate">
{analyzeVars.metaRate} u/minute
</LabeledList.Item>
<LabeledList.Item label="Overdose Threshold">
{analyzeVars.overD}
</LabeledList.Item>
<LabeledList.Item label="Addiction Threshold">
{analyzeVars.addicD}
</LabeledList.Item>
</LabeledList>
)}
{!!fermianalyze && (
<LabeledList>
<LabeledList.Item label="Name">
{analyzeVars.name}
</LabeledList.Item>
<LabeledList.Item label="State">
{analyzeVars.state}
</LabeledList.Item>
<LabeledList.Item label="Color">
<ColorBox color={analyzeVars.color} mr={1} />
{analyzeVars.color}
</LabeledList.Item>
<LabeledList.Item label="Description">
{analyzeVars.description}
</LabeledList.Item>
<LabeledList.Item label="Metabolization Rate">
{analyzeVars.metaRate} u/minute
</LabeledList.Item>
<LabeledList.Item label="Overdose Threshold">
{analyzeVars.overD}
</LabeledList.Item>
<LabeledList.Item label="Addiction Threshold">
{analyzeVars.addicD}
</LabeledList.Item>
<LabeledList.Item label="Purity">
{analyzeVars.purityF}
</LabeledList.Item>
<LabeledList.Item label="Inverse Ratio">
{analyzeVars.inverseRatioF}
</LabeledList.Item>
<LabeledList.Item label="Purity E">
{analyzeVars.purityE}
</LabeledList.Item>
<LabeledList.Item label="Lower Optimal Temperature">
{analyzeVars.minTemp}
</LabeledList.Item>
<LabeledList.Item label="Upper Optimal Temperature">
{analyzeVars.maxTemp}
</LabeledList.Item>
<LabeledList.Item label="Explosive Temperature">
{analyzeVars.eTemp}
</LabeledList.Item>
<LabeledList.Item label="pH Peak">
{analyzeVars.pHpeak}
</LabeledList.Item>
</LabeledList>
)}
</Section>
);
};
@@ -103,6 +103,7 @@ export class Uplink extends Component {
compact={compact_mode}
items={items}
hoveredItem={hoveredItem}
telecrystals={telecrystals}
onBuyMouseOver={item => this.setHoveredItem(item)}
onBuyMouseOut={item => this.setHoveredItem({})}
onBuy={item => act(ref, 'buy', {
@@ -15,7 +15,7 @@ export const BeakerContents = props => {
)}
{beakerContents.map(chemical => (
<Box key={chemical.name} color="label">
{chemical.volume} units of {chemical.name}
{chemical.volume} units of {chemical.name}, Purity: {chemical.purity}
</Box>
))}
</Box>
File diff suppressed because one or more lines are too long
+26
View File
@@ -19,7 +19,10 @@ import { CellularEmporium } from './interfaces/CellularEmporium';
import { CentcomPodLauncher } from './interfaces/CentcomPodLauncher';
import { ChemAcclimator } from './interfaces/ChemAcclimator';
import { ChemDebugSynthesizer } from './interfaces/ChemDebugSynthesizer';
import { ChemDispenser } from './interfaces/ChemDispenser';
import { ChemFilter } from './interfaces/ChemFilter';
import { ChemHeater } from './interfaces/ChemHeater';
import { ChemMaster } from './interfaces/ChemMaster';
import { ChemPress } from './interfaces/ChemPress';
import { ChemReactionChamber } from './interfaces/ChemReactionChamber';
import { ChemSplitter } from './interfaces/ChemSplitter';
@@ -86,8 +89,10 @@ import { TankDispenser } from './interfaces/TankDispenser';
import { Teleporter } from './interfaces/Teleporter';
import { ThermoMachine } from './interfaces/ThermoMachine';
import { TurbineComputer } from './interfaces/TurbineComputer';
import { Uplink } from './interfaces/Uplink';
import { VaultController } from './interfaces/VaultController';
import { Wires } from './interfaces/Wires';
import { AtmosRelief } from './interfaces/AtmosRelief';
const ROUTES = {
achievements: {
@@ -130,6 +135,10 @@ const ROUTES = {
component: () => AtmosPump,
scrollable: false,
},
atmos_relief: {
component: () => AtmosRelief,
scrollable: false,
},
bepis: {
component: () => Bepis,
scrollable: false,
@@ -174,10 +183,22 @@ const ROUTES = {
component: () => ChemAcclimator,
scrollable: false,
},
chem_dispenser: {
component: () => ChemDispenser,
scrollable: true,
},
chemical_filter: {
component: () => ChemFilter,
scrollable: true,
},
chem_heater: {
component: () => ChemHeater,
scrollable: true,
},
chem_master: {
component: () => ChemMaster,
scrollable: true,
},
chem_press: {
component: () => ChemPress,
scrollable: false,
@@ -470,6 +491,11 @@ const ROUTES = {
component: () => TurbineComputer,
scrollable: false,
},
uplink: {
component: () => Uplink,
scrollable: true,
theme: 'syndicate',
},
vault_controller: {
component: () => VaultController,
scrollable: false,