mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-30 15:38:02 +01:00
@@ -443,3 +443,48 @@
|
||||
|
||||
/datum/asset/nanoui/send(client)
|
||||
send_asset_list(client, common)
|
||||
|
||||
//Pill sprites for UIs
|
||||
/datum/asset/chem_master
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/chem_master/register()
|
||||
for(var/i = 1 to 24)
|
||||
assets["pill[i].png"] = icon('icons/obj/chemical.dmi', "pill[i]")
|
||||
|
||||
for(var/i = 1 to 4)
|
||||
assets["bottle-[i].png"] = icon('icons/obj/chemical.dmi', "bottle-[i]")
|
||||
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/chem_master/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
|
||||
//Cloning pod sprites for UIs
|
||||
/datum/asset/cloning
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/cloning/register()
|
||||
assets["pod_idle.gif"] = icon('icons/obj/cloning.dmi', "pod_idle")
|
||||
assets["pod_cloning.gif"] = icon('icons/obj/cloning.dmi', "pod_cloning")
|
||||
assets["pod_mess.gif"] = icon('icons/obj/cloning.dmi', "pod_mess")
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/cloning/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
|
||||
// VOREStation Add
|
||||
/datum/asset/cloning/resleeving
|
||||
/datum/asset/cloning/resleeving/register()
|
||||
// This intentionally does not call the parent. Duplicate assets are not allowed.
|
||||
assets["sleeve_empty.gif"] = icon('icons/obj/machines/implantchair.dmi', "implantchair")
|
||||
assets["sleeve_occupied.gif"] = icon('icons/obj/machines/implantchair.dmi', "implantchair_on")
|
||||
assets["synthprinter.gif"] = icon('icons/obj/machines/synthpod.dmi', "pod_0")
|
||||
assets["synthprinter_working.gif"] = icon('icons/obj/machines/synthpod.dmi', "pod_1")
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
// VOREStation Add End
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
return get_turf(src)
|
||||
|
||||
/mob/proc/say_test(var/text)
|
||||
/proc/say_test(var/text)
|
||||
var/ending = copytext(text, length(text))
|
||||
if(ending == "?")
|
||||
return "1"
|
||||
|
||||
@@ -140,6 +140,13 @@
|
||||
crash_with("[my_atom] attempted to add a reagent called '[id]' which doesn't exist. ([usr])")
|
||||
return 0
|
||||
|
||||
/datum/reagents/proc/isolate_reagent(reagent)
|
||||
for(var/A in reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(R.id != reagent)
|
||||
del_reagent(R.id)
|
||||
update_total()
|
||||
|
||||
/datum/reagents/proc/remove_reagent(var/id, var/amount, var/safety = 0)
|
||||
if(!isnum(amount))
|
||||
return 0
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
#define LIQUID 2
|
||||
#define GAS 3
|
||||
|
||||
#define MAX_PILL_SPRITE 24 //max icon state of the pill sprites
|
||||
#define MAX_BOTTLE_SPRITE 4 //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 60 // Max amount of units in a pill
|
||||
#define MAX_UNITS_PER_PATCH 60 // Max amount of units in a patch
|
||||
#define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -24,11 +31,11 @@
|
||||
var/condi = 0
|
||||
var/useramount = 15 // Last used amount
|
||||
var/pillamount = 10
|
||||
var/bottlesprite = "1"
|
||||
var/pillsprite = "1"
|
||||
var/list/bottle_styles
|
||||
var/bottlesprite = 1
|
||||
var/pillsprite = 1
|
||||
var/max_pill_count = 20
|
||||
var/tab = "home"
|
||||
var/analyze_data[0]
|
||||
var/printing = FALSE
|
||||
flags = OPENCONTAINER
|
||||
clicksound = "button"
|
||||
|
||||
@@ -48,6 +55,9 @@
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/machinery/chem_master/update_icon()
|
||||
icon_state = "mixer[beaker ? "1" : "0"]"
|
||||
|
||||
/obj/machinery/chem_master/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob)
|
||||
|
||||
if(istype(B, /obj/item/weapon/reagent_containers/glass) || istype(B, /obj/item/weapon/reagent_containers/food))
|
||||
@@ -59,7 +69,7 @@
|
||||
user.drop_item()
|
||||
B.loc = src
|
||||
to_chat(user, "You add \the [B] to the machine.")
|
||||
icon_state = "mixer1"
|
||||
update_icon()
|
||||
|
||||
else if(istype(B, /obj/item/weapon/storage/pill_bottle))
|
||||
|
||||
@@ -85,247 +95,395 @@
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
user.set_machine(src)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_master/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/chem_master),
|
||||
)
|
||||
|
||||
/obj/machinery/chem_master/tgui_interact(mob/user, datum/tgui/ui = null)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ChemMaster", name)
|
||||
ui.open()
|
||||
|
||||
/**
|
||||
* Display the NanoUI window for the chem master.
|
||||
*
|
||||
* See NanoUI documentation for details.
|
||||
*/
|
||||
/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
user.set_machine(src)
|
||||
|
||||
/obj/machinery/chem_master/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["tab"] = tab
|
||||
|
||||
data["condi"] = condi
|
||||
|
||||
data["loaded_pill_bottle"] = !!loaded_pill_bottle
|
||||
if(loaded_pill_bottle)
|
||||
data["pillBottle"] = list("total" = loaded_pill_bottle.contents.len, "max" = loaded_pill_bottle.max_storage_space)
|
||||
else
|
||||
data["pillBottle"] = null
|
||||
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.max_storage_space
|
||||
|
||||
data["beaker"] = !!beaker
|
||||
if(beaker)
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/ui_reagent_beaker_list[0]
|
||||
for(var/datum/reagent/G in R.reagent_list)
|
||||
ui_reagent_beaker_list[++ui_reagent_beaker_list.len] = list("name" = G.name, "volume" = G.volume, "description" = G.description, "id" = G.id)
|
||||
var/list/beaker_reagents_list = list()
|
||||
data["beaker_reagents"] = beaker_reagents_list
|
||||
for(var/datum/reagent/R in beaker.reagents.reagent_list)
|
||||
beaker_reagents_list[++beaker_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "description" = R.description, "id" = R.id)
|
||||
|
||||
data["beaker"] = list("total_volume" = R.total_volume, "reagent_list" = ui_reagent_beaker_list)
|
||||
else
|
||||
data["beaker"] = null
|
||||
|
||||
if(reagents.total_volume)
|
||||
var/ui_reagent_list[0]
|
||||
for(var/datum/reagent/N in reagents.reagent_list)
|
||||
ui_reagent_list[++ui_reagent_list.len] = list("name" = N.name, "volume" = N.volume, "description" = N.description, "id" = N.id)
|
||||
|
||||
data["reagents"] = list("total_volume" = reagents.total_volume, "reagent_list" = ui_reagent_list)
|
||||
else
|
||||
data["reagents"] = null
|
||||
var/list/buffer_reagents_list = list()
|
||||
data["buffer_reagents"] = buffer_reagents_list
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
buffer_reagents_list[++buffer_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "id" = R.id, "description" = R.description)
|
||||
|
||||
data["pillsprite"] = pillsprite
|
||||
data["bottlesprite"] = bottlesprite
|
||||
data["mode"] = mode
|
||||
data["printing"] = printing
|
||||
|
||||
if(analyze_data)
|
||||
data["analyzeData"] = list("name" = analyze_data["name"], "desc" = analyze_data["desc"], "blood_type" = analyze_data["blood_type"], "blood_DNA" = analyze_data["blood_DNA"])
|
||||
else
|
||||
data["analyzeData"] = null
|
||||
// Transfer modal information if there is one
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
|
||||
data["pillSprite"] = pillsprite
|
||||
data["bottleSprite"] = bottlesprite
|
||||
return data
|
||||
|
||||
var/P[24] //how many pill sprites there are. Sprites are taken from chemical.dmi and can be found in nano/images/pill.png
|
||||
for(var/i = 1 to P.len)
|
||||
P[i] = i
|
||||
data["pillSpritesAmount"] = P
|
||||
/**
|
||||
* 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
|
||||
|
||||
data["bottleSpritesAmount"] = list(1, 2, 3, 4) //how many bottle sprites there are. Sprites are taken from chemical.dmi and can be found in nano/images/pill.png
|
||||
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"]
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "chem_master.tmpl", src.name, 575, 400)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(5)
|
||||
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")
|
||||
var/list/choices = list()
|
||||
for(var/i = 1 to MAX_BOTTLE_SPRITE)
|
||||
choices += "bottle-[i].png"
|
||||
tgui_modal_bento(src, id, "Please select the new style for bottles:", null, arguments, bottlesprite, choices)
|
||||
else
|
||||
return FALSE
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
var/answer = params["answer"]
|
||||
switch(id)
|
||||
// if("change_pill_bottle_style")
|
||||
// if(!pill_bottle_wrappers || !loaded_pill_bottle) // wat?
|
||||
// return
|
||||
// var/color = "CLEAR"
|
||||
// for(var/col in pill_bottle_wrappers)
|
||||
// var/col_name = pill_bottle_wrappers[col]
|
||||
// if(col_name == answer)
|
||||
// color = col
|
||||
// break
|
||||
// if(length(color) && color != "CLEAR")
|
||||
// loaded_pill_bottle.wrapper_color = color
|
||||
// loaded_pill_bottle.apply_wrap()
|
||||
// else
|
||||
// loaded_pill_bottle.wrapper_color = null
|
||||
// loaded_pill_bottle.cut_overlays()
|
||||
if("addcustom")
|
||||
var/amount = isgoodnumber(text2num(answer))
|
||||
if(!amount || !arguments["id"])
|
||||
return
|
||||
tgui_act("add", list("id" = arguments["id"], "amount" = amount), ui, state)
|
||||
if("removecustom")
|
||||
var/amount = isgoodnumber(text2num(answer))
|
||||
if(!amount || !arguments["id"])
|
||||
return
|
||||
tgui_act("remove", list("id" = arguments["id"], "amount" = amount), ui, state)
|
||||
if("create_condi_pack")
|
||||
if(!condi || !reagents.total_volume)
|
||||
return
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/obj/item/weapon/reagent_containers/pill/P = new(loc)
|
||||
P.name = "[answer] pack"
|
||||
P.desc = "A small condiment pack. The label says it contains [answer]."
|
||||
P.icon_state = "bouilloncube"//Reskinned monkey cube
|
||||
reagents.trans_to_obj(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
|
||||
|
||||
/obj/machinery/chem_master/Topic(href, href_list)
|
||||
if(stat & (BROKEN|NOPOWER)) return
|
||||
if(usr.stat || usr.restrained()) return
|
||||
if(!in_range(src, usr)) 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
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
var/obj/item/weapon/reagent_containers/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]"
|
||||
if(P.icon_state in list("pill1", "pill2", "pill3", "pill4")) // if using greyscale, take colour from reagent
|
||||
P.color = reagents.get_color()
|
||||
reagents.trans_to_obj(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.max_storage_space)
|
||||
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/weapon/reagent_containers/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_obj(P, amount_per_patch)
|
||||
// if(is_medical_patch)
|
||||
// P.instant_application = TRUE
|
||||
// P.icon_state = "bandaid_med"
|
||||
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/weapon/reagent_containers/glass/bottle/P = new(loc)
|
||||
P.name = "[answer] bottle"
|
||||
P.pixel_x = rand(-7, 7) // random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = "bottle-[bottlesprite]" || "bottle-1"
|
||||
reagents.trans_to_obj(P, 60)
|
||||
P.update_icon()
|
||||
if("change_bottle_style")
|
||||
var/new_style = CLAMP(text2num(answer) || 0, 0, MAX_BOTTLE_SPRITE)
|
||||
if(!new_style)
|
||||
return
|
||||
bottlesprite = new_style
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/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["tab_select"])
|
||||
tab = href_list["tab_select"]
|
||||
|
||||
if (href_list["ejectp"])
|
||||
if(loaded_pill_bottle)
|
||||
loaded_pill_bottle.forceMove(get_turf(src))
|
||||
|
||||
if(Adjacent(usr))
|
||||
usr.put_in_hands(loaded_pill_bottle)
|
||||
|
||||
loaded_pill_bottle = null
|
||||
|
||||
if(beaker)
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
if (tab == "analyze")
|
||||
analyze_data["name"] = href_list["name"]
|
||||
analyze_data["desc"] = href_list["desc"]
|
||||
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
|
||||
analyze_data["name"] = G.name
|
||||
analyze_data["blood_type"] = G.data["blood_type"]
|
||||
analyze_data["blood_DNA"] = G.data["blood_DNA"]
|
||||
|
||||
else if (href_list["add"])
|
||||
|
||||
if(href_list["amount"])
|
||||
var/id = href_list["add"]
|
||||
var/amount = CLAMP((text2num(href_list["amount"])), 0, 200)
|
||||
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 = CLAMP(useramount, 0, 200)
|
||||
src.Topic(null, list("amount" = "[useramount]", "add" = "[id]"))
|
||||
|
||||
else if (href_list["remove"])
|
||||
|
||||
if(href_list["amount"])
|
||||
var/id = href_list["remove"]
|
||||
var/amount = CLAMP((text2num(href_list["amount"])), 0, 200)
|
||||
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 = CLAMP(useramount, 0, 200)
|
||||
src.Topic(null, list("amount" = "[useramount]", "remove" = "[id]"))
|
||||
|
||||
else if (href_list["toggle"])
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("toggle")
|
||||
mode = !mode
|
||||
|
||||
else if (href_list["eject"])
|
||||
if(beaker)
|
||||
beaker.forceMove(get_turf(src))
|
||||
|
||||
if(Adjacent(usr)) // So the AI doesn't get a beaker somehow.
|
||||
usr.put_in_hands(beaker)
|
||||
|
||||
beaker = null
|
||||
reagents.clear_reagents()
|
||||
icon_state = "mixer0"
|
||||
else if (href_list["createpill"] || href_list["createpill_multiple"])
|
||||
var/count = 1
|
||||
|
||||
if(reagents.total_volume/count < 1) //Sanity checking.
|
||||
if("ejectp")
|
||||
if(loaded_pill_bottle)
|
||||
loaded_pill_bottle.forceMove(loc)
|
||||
loaded_pill_bottle = null
|
||||
if("print")
|
||||
if(printing || condi)
|
||||
return
|
||||
|
||||
if (href_list["createpill_multiple"])
|
||||
count = input("Select the number of pills to make.", "Max [max_pill_count]", pillamount) as null|num
|
||||
if(!count) //Covers 0 and cancel
|
||||
return
|
||||
count = CLAMP(round(count), 1, max_pill_count) // Fix decimals input and clamp to reasonable amounts
|
||||
|
||||
if(reagents.total_volume/count < 1) //Sanity checking.
|
||||
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/amount_per_pill = reagents.total_volume/count
|
||||
if (amount_per_pill > 60) amount_per_pill = 60
|
||||
var/datum/reagent/R = reagent_list[idx]
|
||||
|
||||
var/pill_cube = "pill"
|
||||
if(condi)//For the condimaster
|
||||
pill_cube = "cube"
|
||||
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/weapon/paper/P = new /obj/item/weapon/paper(loc)
|
||||
P.info = "<center><b>Chemical Analysis</b></center><br>"
|
||||
P.info += "<b>Time of analysis:</b> [worldtime2stationtime(world.time)]<br><br>"
|
||||
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
|
||||
pill_cube = "pill"
|
||||
P.info += "<b>Description:</b> [R.description]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Chemical Analysis - [R.name]"
|
||||
spawn(50)
|
||||
printing = FALSE
|
||||
else
|
||||
. = FALSE
|
||||
|
||||
var/name = sanitizeSafe(input(usr,"Name:","Name your [pill_cube]!","[reagents.get_master_reagent_name()] ([amount_per_pill]u)") as null|text, MAX_NAME_LEN)
|
||||
if(. || !beaker)
|
||||
return
|
||||
|
||||
if(!name) //Blank name (sanitized to nothing, or left empty) or cancel
|
||||
. = TRUE
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
switch(action)
|
||||
if("add")
|
||||
var/id = params["id"]
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!id || !amount)
|
||||
return
|
||||
|
||||
|
||||
if(reagents.total_volume/count < 1) //Sanity checking.
|
||||
R.trans_id_to(src, id, amount)
|
||||
if("remove")
|
||||
var/id = params["id"]
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!id || !amount)
|
||||
return
|
||||
while(count-- > 0) // Will definitely eventually stop.
|
||||
var/obj/item/weapon/reagent_containers/pill/P = new/obj/item/weapon/reagent_containers/pill(src.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)
|
||||
if(!condi) //If normal
|
||||
P.icon_state = "pill"+pillsprite
|
||||
else //If condi is on
|
||||
P.icon_state = "bouilloncube"//Reskinned monkey cube
|
||||
P.desc = "A dissolvable cube."
|
||||
|
||||
if(P.icon_state in list("pill1", "pill2", "pill3", "pill4")) // if using greyscale, take colour from reagent
|
||||
P.color = reagents.get_color()
|
||||
|
||||
reagents.trans_to_obj(P,amount_per_pill)
|
||||
if(src.loaded_pill_bottle)
|
||||
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.max_storage_space)
|
||||
P.loc = loaded_pill_bottle
|
||||
|
||||
else if (href_list["createbottle"])
|
||||
if(!condi)
|
||||
var/name = sanitizeSafe(input(usr,"Name:","Name your bottle!",reagents.get_master_reagent_name()), MAX_NAME_LEN)
|
||||
var/obj/item/weapon/reagent_containers/glass/bottle/P = new/obj/item/weapon/reagent_containers/glass/bottle(src.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 = "bottle-"+bottlesprite
|
||||
reagents.trans_to_obj(P,60)
|
||||
P.update_icon()
|
||||
if(mode)
|
||||
reagents.trans_id_to(beaker, id, amount)
|
||||
else
|
||||
var/obj/item/weapon/reagent_containers/food/condiment/P = new/obj/item/weapon/reagent_containers/food/condiment(src.loc)
|
||||
reagents.trans_to_obj(P,50)
|
||||
|
||||
else if (href_list["createpatch"])
|
||||
if(reagents.total_volume < 1) //Sanity checking.
|
||||
reagents.remove_reagent(id, amount)
|
||||
if("eject")
|
||||
if(!beaker)
|
||||
return
|
||||
|
||||
var/name = sanitizeSafe(input(usr,"Name:","Name your patch!","[reagents.get_master_reagent_name()] ([round(reagents.total_volume)]u)") as null|text, MAX_NAME_LEN)
|
||||
|
||||
if(!name) //Blank name (sanitized to nothing, or left empty) or cancel
|
||||
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/weapon/reagent_containers/food/condiment/P = new(loc)
|
||||
reagents.trans_to_obj(P, 50)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(reagents.total_volume < 1) //Sanity checking.
|
||||
return
|
||||
var/obj/item/weapon/reagent_containers/pill/patch/P = new/obj/item/weapon/reagent_containers/pill/patch(src.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)
|
||||
/obj/machinery/chem_master/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
reagents.trans_to_obj(P, 60)
|
||||
if(src.loaded_pill_bottle)
|
||||
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.max_storage_space)
|
||||
P.loc = loaded_pill_bottle
|
||||
/obj/machinery/chem_master/proc/isgoodnumber(num)
|
||||
if(isnum(num))
|
||||
if(num > 200)
|
||||
num = 200
|
||||
else if(num < 0)
|
||||
num = 1
|
||||
return num
|
||||
else
|
||||
return FALSE
|
||||
|
||||
else if(href_list["pill_sprite"])
|
||||
pillsprite = href_list["pill_sprite"]
|
||||
else if(href_list["bottle_sprite"])
|
||||
bottlesprite = href_list["bottle_sprite"]
|
||||
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
/obj/machinery/chem_master/attack_ai(mob/user as mob)
|
||||
return src.attack_hand(user)
|
||||
// /obj/machinery/chem_master/proc/chemical_safety_check(datum/reagents/R)
|
||||
// var/all_safe = TRUE
|
||||
// for(var/datum/reagent/A in R.reagent_list)
|
||||
// if(!GLOB.safe_chem_list.Find(A.id))
|
||||
// all_safe = FALSE
|
||||
// return all_safe
|
||||
|
||||
/obj/machinery/chem_master/condimaster
|
||||
name = "CondiMaster 3000"
|
||||
@@ -365,11 +523,41 @@
|
||||
/obj/item/stack/material/glass/phoronglass = list("platinum", "silicon", "silicon", "silicon"), //5 platinum, 15 silicon,
|
||||
)
|
||||
|
||||
var/static/radial_examine = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_examine")
|
||||
var/static/radial_eject = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_eject")
|
||||
var/static/radial_grind = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_grind")
|
||||
// var/static/radial_juice = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_juice")
|
||||
// var/static/radial_mix = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_mix")
|
||||
|
||||
/obj/machinery/reagentgrinder/Initialize()
|
||||
. = ..()
|
||||
beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/reagentgrinder/examine(mob/user)
|
||||
. = ..()
|
||||
if(!in_range(user, src) && !issilicon(user) && !isobserver(user))
|
||||
. += "<span class='warning'>You're too far away to examine [src]'s contents and display!</span>"
|
||||
return
|
||||
|
||||
if(inuse)
|
||||
. += "<span class='warning'>\The [src] is operating.</span>"
|
||||
return
|
||||
|
||||
if(beaker || length(holdingitems))
|
||||
. += "<span class='notice'>\The [src] contains:</span>"
|
||||
if(beaker)
|
||||
. += "<span class='notice'>- \A [beaker].</span>"
|
||||
for(var/i in holdingitems)
|
||||
var/obj/item/O = i
|
||||
. += "<span class='notice'>- \A [O.name].</span>"
|
||||
|
||||
if(!(stat & (NOPOWER|BROKEN)))
|
||||
. += "<span class='notice'>The status display reads:</span>\n"
|
||||
if(beaker)
|
||||
for(var/datum/reagent/R in beaker.reagents.reagent_list)
|
||||
. += "<span class='notice'>- [R.volume] units of [R.name].</span>"
|
||||
|
||||
/obj/machinery/reagentgrinder/update_icon()
|
||||
icon_state = "juicer"+num2text(!isnull(beaker))
|
||||
return
|
||||
@@ -450,93 +638,66 @@
|
||||
user.remove_from_mob(O)
|
||||
O.loc = src
|
||||
holdingitems += O
|
||||
src.updateUsrDialog()
|
||||
return 0
|
||||
|
||||
/obj/machinery/reagentgrinder/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(user.incapacitated() || !Adjacent(user))
|
||||
return
|
||||
replace_beaker(user)
|
||||
|
||||
/obj/machinery/reagentgrinder/attack_hand(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/reagentgrinder/interact(mob/user as mob) // The microwave Menu
|
||||
var/is_chamber_empty = 0
|
||||
var/is_beaker_ready = 0
|
||||
var/processing_chamber = ""
|
||||
var/beaker_contents = ""
|
||||
var/dat = ""
|
||||
/obj/machinery/reagentgrinder/interact(mob/user as mob) // The microwave Menu //I am reasonably certain that this is not a microwave
|
||||
if(inuse || user.incapacitated())
|
||||
return
|
||||
|
||||
if(!inuse)
|
||||
for (var/obj/item/O in holdingitems)
|
||||
processing_chamber += "\A [O.name]<BR>"
|
||||
var/list/options = list()
|
||||
|
||||
if (!processing_chamber)
|
||||
is_chamber_empty = 1
|
||||
processing_chamber = "Nothing."
|
||||
if (!beaker)
|
||||
beaker_contents = "<B>No beaker attached.</B><br>"
|
||||
else
|
||||
is_beaker_ready = 1
|
||||
beaker_contents = "<B>The beaker contains:</B><br>"
|
||||
var/anything = 0
|
||||
for(var/datum/reagent/R in beaker.reagents.reagent_list)
|
||||
anything = 1
|
||||
beaker_contents += "[R.volume] - [R.name]<br>"
|
||||
if(!anything)
|
||||
beaker_contents += "Nothing<br>"
|
||||
if(beaker || length(holdingitems))
|
||||
options["eject"] = radial_eject
|
||||
|
||||
if(isAI(user))
|
||||
if(stat & NOPOWER)
|
||||
return
|
||||
options["examine"] = radial_examine
|
||||
|
||||
dat = {"
|
||||
<b>Processing chamber contains:</b><br>
|
||||
[processing_chamber]<br>
|
||||
[beaker_contents]<hr>
|
||||
"}
|
||||
if (is_beaker_ready && !is_chamber_empty && !(stat & (NOPOWER|BROKEN)))
|
||||
dat += "<A href='?src=\ref[src];action=grind'>Process the reagents</a><BR>"
|
||||
if(holdingitems && holdingitems.len > 0)
|
||||
dat += "<A href='?src=\ref[src];action=eject'>Eject the reagents</a><BR>"
|
||||
if (beaker)
|
||||
dat += "<A href='?src=\ref[src];action=detach'>Detach the beaker</a><BR>"
|
||||
// if there is no power or it's broken, the procs will fail but the buttons will still show
|
||||
if(length(holdingitems))
|
||||
options["grind"] = radial_grind
|
||||
|
||||
var/choice
|
||||
|
||||
if(length(options) < 1)
|
||||
return
|
||||
if(length(options) == 1)
|
||||
for(var/key in options)
|
||||
choice = key
|
||||
else
|
||||
dat += "Please wait..."
|
||||
user << browse("<HEAD><TITLE>All-In-One Grinder</TITLE></HEAD><TT>[dat]</TT>", "window=reagentgrinder")
|
||||
onclose(user, "reagentgrinder")
|
||||
return
|
||||
choice = show_radial_menu(user, src, options, require_near = !issilicon(user))
|
||||
|
||||
|
||||
/obj/machinery/reagentgrinder/Topic(href, href_list)
|
||||
if(..())
|
||||
// post choice verification
|
||||
if(inuse || (isAI(user) && stat & NOPOWER) || user.incapacitated())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
switch(href_list["action"])
|
||||
if ("grind")
|
||||
grind()
|
||||
|
||||
switch(choice)
|
||||
if("eject")
|
||||
eject()
|
||||
if ("detach")
|
||||
detach()
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
eject(user)
|
||||
if("grind")
|
||||
grind(user)
|
||||
if("examine")
|
||||
examine(user)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/detach()
|
||||
|
||||
if (usr.stat != 0)
|
||||
/obj/machinery/reagentgrinder/proc/eject(mob/user)
|
||||
if(user.incapacitated())
|
||||
return
|
||||
if (!beaker)
|
||||
return
|
||||
beaker.loc = src.loc
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/eject()
|
||||
|
||||
if (usr.stat != 0)
|
||||
return
|
||||
if (!holdingitems || holdingitems.len == 0)
|
||||
return
|
||||
|
||||
for(var/obj/item/O in holdingitems)
|
||||
O.loc = src.loc
|
||||
holdingitems -= O
|
||||
holdingitems.Cut()
|
||||
if(beaker)
|
||||
replace_beaker(user)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/grind()
|
||||
|
||||
@@ -554,7 +715,6 @@
|
||||
// Reset the machine.
|
||||
spawn(60)
|
||||
inuse = 0
|
||||
interact(usr)
|
||||
|
||||
// Process.
|
||||
for (var/obj/item/O in holdingitems)
|
||||
@@ -581,13 +741,26 @@
|
||||
continue
|
||||
|
||||
if(O.reagents)
|
||||
O.reagents.trans_to(beaker, min(O.reagents.total_volume, remaining_volume))
|
||||
O.reagents.trans_to_obj(beaker, min(O.reagents.total_volume, remaining_volume))
|
||||
if(O.reagents.total_volume == 0)
|
||||
holdingitems -= O
|
||||
qdel(O)
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/replace_beaker(mob/living/user, obj/item/weapon/reagent_containers/new_beaker)
|
||||
if(!user)
|
||||
return FALSE
|
||||
if(beaker)
|
||||
if(!user.incapacitated() && Adjacent(user))
|
||||
user.put_in_hands(beaker)
|
||||
else
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
if(new_beaker)
|
||||
beaker = new_beaker
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
///////////////
|
||||
///////////////
|
||||
@@ -653,4 +826,11 @@
|
||||
to_chat(user, span("notice", "Scanning of \the [I] complete."))
|
||||
analyzing = FALSE
|
||||
update_icon()
|
||||
return
|
||||
return
|
||||
|
||||
#undef MAX_PILL_SPRITE
|
||||
#undef MAX_BOTTLE_SPRITE
|
||||
#undef MAX_MULTI_AMOUNT
|
||||
#undef MAX_UNITS_PER_PILL
|
||||
#undef MAX_UNITS_PER_PATCH
|
||||
#undef MAX_CUSTOM_NAME_LEN
|
||||
@@ -68,12 +68,12 @@
|
||||
C.loc = src
|
||||
cartridges[C.label] = C
|
||||
cartridges = sortAssoc(cartridges)
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/chemical_dispenser/proc/remove_cartridge(label)
|
||||
. = cartridges[label]
|
||||
cartridges -= label
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/chemical_dispenser/attackby(obj/item/weapon/W, mob/user)
|
||||
if(W.is_wrench())
|
||||
@@ -119,25 +119,26 @@
|
||||
user.drop_from_inventory(RC)
|
||||
RC.loc = src
|
||||
to_chat(user, "<span class='notice'>You set \the [RC] on \the [src].</span>")
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chemical_dispenser/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(stat & (BROKEN|NOPOWER)) return
|
||||
if(user.stat || user.restrained()) return
|
||||
/obj/machinery/chemical_dispenser/tgui_interact(mob/user, datum/tgui/ui = null)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ChemDispenser", ui_title) // 390, 655
|
||||
ui.open()
|
||||
|
||||
// this is the data which will be sent to the ui
|
||||
/obj/machinery/chemical_dispenser/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["amount"] = amount
|
||||
data["isBeakerLoaded"] = container ? 1 : 0
|
||||
data["glass"] = accept_drinking
|
||||
var beakerD[0]
|
||||
|
||||
var/beakerContents[0]
|
||||
if(container && container.reagents && container.reagents.reagent_list.len)
|
||||
for(var/datum/reagent/R in container.reagents.reagent_list)
|
||||
beakerD[++beakerD.len] = list("name" = R.name, "volume" = R.volume)
|
||||
data["beakerContents"] = beakerD
|
||||
beakerContents.Add(list(list("name" = R.name, "id" = R.id, "volume" = R.volume))) // list in a list because Byond merges the first list...
|
||||
data["beakerContents"] = beakerContents
|
||||
|
||||
if(container)
|
||||
data["beakerCurrentVolume"] = container.reagents.total_volume
|
||||
@@ -146,50 +147,59 @@
|
||||
data["beakerCurrentVolume"] = null
|
||||
data["beakerMaxVolume"] = null
|
||||
|
||||
var chemicals[0]
|
||||
var/chemicals[0]
|
||||
for(var/label in cartridges)
|
||||
var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label]
|
||||
chemicals[++chemicals.len] = list("label" = label, "amount" = C.reagents.total_volume)
|
||||
chemicals.Add(list(list("title" = label, "id" = label, "amount" = C.reagents.total_volume))) // list in a list because Byond merges the first list...
|
||||
data["chemicals"] = chemicals
|
||||
return data
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "chem_disp.tmpl", ui_title, 390, 680)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
/obj/machinery/chemical_dispenser/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
/obj/machinery/chemical_dispenser/Topic(href, href_list)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return 0 // don't update UIs attached to this object
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("amount")
|
||||
amount = clamp(round(text2num(params["amount"]), 1), 0, 120) // round to nearest 1 and clamp 0 - 120
|
||||
if("dispense")
|
||||
var/label = params["reagent"]
|
||||
if(cartridges[label] && container && container.is_open_container())
|
||||
var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label]
|
||||
playsound(src, 'sound/machines/reagent_dispense.ogg', 25, 1)
|
||||
C.reagents.trans_to(container, amount)
|
||||
if("remove")
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!container || !amount)
|
||||
return
|
||||
var/datum/reagents/R = container.reagents
|
||||
var/id = params["reagent"]
|
||||
if(amount > 0)
|
||||
R.remove_reagent(id, amount)
|
||||
else if(amount == -1) // Isolate
|
||||
R.isolate_reagent(id)
|
||||
if("ejectBeaker")
|
||||
if(container)
|
||||
container.forceMove(get_turf(src))
|
||||
|
||||
if(href_list["amount"])
|
||||
amount = round(text2num(href_list["amount"]), 1) // round to nearest 1
|
||||
amount = max(0, min(120, amount)) // Since the user can actually type the commands himself, some sanity checking
|
||||
if(Adjacent(usr)) // So the AI doesn't get a beaker somehow.
|
||||
usr.put_in_hands(container)
|
||||
|
||||
else if(href_list["dispense"])
|
||||
var/label = href_list["dispense"]
|
||||
if(cartridges[label] && container && container.is_open_container())
|
||||
var/obj/item/weapon/reagent_containers/chem_disp_cartridge/C = cartridges[label]
|
||||
playsound(src, 'sound/machines/reagent_dispense.ogg', 25, 1)
|
||||
C.reagents.trans_to(container, amount)
|
||||
|
||||
else if(href_list["ejectBeaker"])
|
||||
if(container)
|
||||
container.forceMove(get_turf(src))
|
||||
|
||||
if(Adjacent(usr)) // So the AI doesn't get a beaker somehow.
|
||||
usr.put_in_hands(container)
|
||||
|
||||
container = null
|
||||
container = null
|
||||
else
|
||||
return FALSE
|
||||
|
||||
add_fingerprint(usr)
|
||||
return 1 // update UIs attached to this object
|
||||
|
||||
/obj/machinery/chemical_dispenser/attack_ai(mob/user as mob)
|
||||
src.attack_hand(user)
|
||||
|
||||
/obj/machinery/chemical_dispenser/attack_hand(mob/user as mob)
|
||||
/obj/machinery/chemical_dispenser/attack_ghost(mob/user)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chemical_dispenser/attack_ai(mob/user)
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/chemical_dispenser/attack_hand(mob/user)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
tgui_interact(user)
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#define MENU_MAIN 1
|
||||
#define MENU_BODY 2
|
||||
#define MENU_MIND 3
|
||||
|
||||
/obj/machinery/computer/transhuman/resleeving
|
||||
name = "resleeving control console"
|
||||
catalogue_data = list(/datum/category_item/catalogue/information/organization/khi,
|
||||
@@ -7,19 +11,25 @@
|
||||
light_color = "#315ab4"
|
||||
circuit = /obj/item/weapon/circuitboard/resleeving_control
|
||||
req_access = list(access_heads) //Only used for record deletion right now.
|
||||
var/list/pods = list() //Linked grower pods.
|
||||
var/list/spods = list()
|
||||
var/list/sleevers = list() //Linked resleeving booths.
|
||||
var/temp = ""
|
||||
var/menu = 1 //Which menu screen to display
|
||||
var/list/pods = null //Linked grower pods.
|
||||
var/list/spods = null
|
||||
var/list/sleevers = null //Linked resleeving booths.
|
||||
var/list/temp = null
|
||||
var/menu = MENU_MAIN //Which menu screen to display
|
||||
var/datum/transhuman/body_record/active_br = null
|
||||
var/datum/transhuman/mind_record/active_mr = null
|
||||
var/organic_capable = 1
|
||||
var/synthetic_capable = 1
|
||||
var/obj/item/weapon/disk/transcore/disk
|
||||
var/obj/machinery/clonepod/transhuman/selected_pod
|
||||
var/obj/machinery/transhuman/synthprinter/selected_printer
|
||||
var/obj/machinery/transhuman/resleever/selected_sleever
|
||||
|
||||
/obj/machinery/computer/transhuman/resleeving/Initialize()
|
||||
. = ..()
|
||||
pods = list()
|
||||
spods = list()
|
||||
sleevers = list()
|
||||
updatemodules()
|
||||
|
||||
/obj/machinery/computer/transhuman/resleeving/Destroy()
|
||||
@@ -85,7 +95,6 @@
|
||||
user.unEquip(W)
|
||||
W.forceMove(get_turf(src)) // Drop on top of us
|
||||
active_br = new /datum/transhuman/body_record(brDisk.stored) // Loads a COPY!
|
||||
menu = 4
|
||||
to_chat(user, "<span class='notice'>\The [src] loads the body record from \the [W] before ejecting it.</span>")
|
||||
attack_hand(user)
|
||||
else
|
||||
@@ -103,282 +112,357 @@
|
||||
return
|
||||
|
||||
updatemodules()
|
||||
tgui_interact(user)
|
||||
|
||||
ui_interact(user)
|
||||
/obj/machinery/computer/transhuman/resleeving/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/cloning),
|
||||
get_asset_datum(/datum/asset/cloning/resleeving),
|
||||
)
|
||||
|
||||
/obj/machinery/computer/transhuman/resleeving/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
user.set_machine(src)
|
||||
/obj/machinery/computer/transhuman/resleeving/tgui_interact(mob/user, datum/tgui/ui = null)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ResleevingConsole", "Resleeving Console")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/transhuman/resleeving/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["menu"] = menu
|
||||
|
||||
var/list/temppods[0]
|
||||
for(var/obj/machinery/clonepod/transhuman/pod in pods)
|
||||
var/status = "idle"
|
||||
if(pod.mess)
|
||||
status = "mess"
|
||||
else if(pod.occupant && !(pod.stat & NOPOWER))
|
||||
status = "cloning"
|
||||
temppods.Add(list(list(
|
||||
"pod" = "\ref[pod]",
|
||||
"name" = sanitize(capitalize(pod.name)),
|
||||
"biomass" = pod.get_biomass(),
|
||||
"status" = status,
|
||||
"progress" = (pod.occupant && pod.occupant.stat != DEAD) ? pod.get_completion() : 0
|
||||
)))
|
||||
data["pods"] = temppods.Copy()
|
||||
temppods.Cut()
|
||||
|
||||
for(var/obj/machinery/transhuman/synthprinter/spod in spods)
|
||||
temppods.Add(list(list(
|
||||
"spod" = "\ref[spod]",
|
||||
"name" = sanitize(capitalize(spod.name)),
|
||||
"busy" = spod.busy,
|
||||
"steel" = spod.stored_material[DEFAULT_WALL_MATERIAL],
|
||||
"glass" = spod.stored_material["glass"]
|
||||
)))
|
||||
data["spods"] = temppods.Copy()
|
||||
temppods.Cut()
|
||||
|
||||
for(var/obj/machinery/transhuman/resleever/resleever in sleevers)
|
||||
temppods.Add(list(list(
|
||||
"sleever" = "\ref[resleever]",
|
||||
"name" = sanitize(capitalize(resleever.name)),
|
||||
"occupied" = !!resleever.occupant,
|
||||
"occupant" = resleever.occupant ? resleever.occupant.real_name : "None"
|
||||
)))
|
||||
data["sleevers"] = temppods.Copy()
|
||||
temppods.Cut()
|
||||
|
||||
data["coredumped"] = SStranscore.core_dumped
|
||||
data["emergency"] = disk
|
||||
data["temp"] = temp
|
||||
data["selected_pod"] = "\ref[selected_pod]"
|
||||
data["selected_printer"] = "\ref[selected_printer]"
|
||||
data["selected_sleever"] = "\ref[selected_sleever]"
|
||||
|
||||
var/bodyrecords_list_ui[0]
|
||||
for(var/N in SStranscore.body_scans)
|
||||
var/datum/transhuman/body_record/BR = SStranscore.body_scans[N]
|
||||
bodyrecords_list_ui[++bodyrecords_list_ui.len] = list("name" = N, "recref" = "\ref[BR]")
|
||||
data["bodyrecords"] = bodyrecords_list_ui
|
||||
|
||||
var/mindrecords_list_ui[0]
|
||||
for(var/N in SStranscore.backed_up)
|
||||
var/datum/transhuman/mind_record/MR = SStranscore.backed_up[N]
|
||||
mindrecords_list_ui[++mindrecords_list_ui.len] = list("name" = N, "recref" = "\ref[MR]")
|
||||
data["mindrecords"] = mindrecords_list_ui
|
||||
|
||||
var/pods_list_ui[0]
|
||||
for(var/obj/machinery/clonepod/transhuman/pod in pods)
|
||||
pods_list_ui[++pods_list_ui.len] = list("pod" = pod, "biomass" = pod.get_biomass())
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
return data
|
||||
|
||||
var/spods_list_ui[0]
|
||||
for(var/obj/machinery/transhuman/synthprinter/spod in spods)
|
||||
spods_list_ui[++spods_list_ui.len] = list("spod" = spod, "steel" = spod.stored_material[DEFAULT_WALL_MATERIAL], "glass" = spod.stored_material["glass"])
|
||||
|
||||
var/sleevers_list_ui[0]
|
||||
for(var/obj/machinery/transhuman/resleever/resleever in sleevers)
|
||||
sleevers_list_ui[++sleevers_list_ui.len] = list("sleever" = resleever, "occupant" = resleever.occupant ? resleever.occupant.real_name : "None")
|
||||
|
||||
if(pods)
|
||||
data["pods"] = pods_list_ui
|
||||
else
|
||||
data["pods"] = null
|
||||
|
||||
if(spods)
|
||||
data["spods"] = spods_list_ui
|
||||
else
|
||||
data["spods"] = null
|
||||
|
||||
if(sleevers)
|
||||
data["sleevers"] = sleevers_list_ui
|
||||
else
|
||||
data["pods"] = null
|
||||
|
||||
if(bodyrecords_list_ui.len)
|
||||
data["bodyrecords"] = bodyrecords_list_ui
|
||||
else
|
||||
data["bodyrecords"] = null
|
||||
|
||||
if(mindrecords_list_ui.len)
|
||||
data["mindrecords"] = mindrecords_list_ui
|
||||
else
|
||||
data["mindrecords"] = null
|
||||
|
||||
|
||||
if(active_br)
|
||||
var/can_grow_active = 1
|
||||
if(!synthetic_capable && active_br.synthetic) //Disqualified due to being synthetic in an organic only.
|
||||
can_grow_active = 0
|
||||
else if(!organic_capable && !active_br.synthetic) //Disqualified for the opposite.
|
||||
can_grow_active = 0
|
||||
else if(!synthetic_capable && !organic_capable) //What have you done??
|
||||
can_grow_active = 0
|
||||
else if(active_br.toocomplex)
|
||||
can_grow_active = 0
|
||||
|
||||
data["activeBodyRecord"] = list("real_name" = active_br.mydna.name, \
|
||||
"speciesname" = active_br.speciesname ? active_br.speciesname : active_br.mydna.dna.species, \
|
||||
"gender" = active_br.bodygender, \
|
||||
"synthetic" = active_br.synthetic ? "Yes" : "No", \
|
||||
"locked" = active_br.locked ? "Low" : "High", \
|
||||
"cando" = can_grow_active,
|
||||
"booc" = active_br.body_oocnotes)
|
||||
else
|
||||
data["activeRecord"] = null
|
||||
|
||||
if(active_mr)
|
||||
var/can_sleeve_current = 1
|
||||
if(!sleevers.len)
|
||||
can_sleeve_current = 0
|
||||
data["activeMindRecord"] = list("charname" = active_mr.mindname, \
|
||||
"obviously_dead" = active_mr.dead_state == MR_DEAD ? "Past-due" : "Current", \
|
||||
"cando" = can_sleeve_current,
|
||||
"mooc" = active_mr.mind_oocnotes)
|
||||
else
|
||||
data["activeMindRecord"] = null
|
||||
|
||||
|
||||
data["menu"] = menu
|
||||
data["podsLen"] = pods.len
|
||||
data["spodsLen"] = spods.len
|
||||
data["sleeversLen"] = sleevers.len
|
||||
data["temp"] = temp
|
||||
data["coredumped"] = SStranscore.core_dumped
|
||||
data["emergency"] = disk ? 1 : 0
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "sleever.tmpl", "Resleeving Control Console", 400, 450)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(5)
|
||||
|
||||
/obj/machinery/computer/transhuman/resleeving/Topic(href, href_list)
|
||||
/obj/machinery/computer/transhuman/resleeving/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
else if (href_list["view_brec"])
|
||||
active_br = locate(href_list["view_brec"])
|
||||
if(active_br && istype(active_br.mydna))
|
||||
menu = 4
|
||||
else
|
||||
active_br = null
|
||||
temp = "ERROR: Record missing."
|
||||
. = TRUE
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
// if(params["id"] == "del_rec" && active_record)
|
||||
// var/obj/item/weapon/card/id/C = usr.get_active_hand()
|
||||
// if(!istype(C) && !istype(C, /obj/item/device/pda))
|
||||
// set_temp("ID not in hand.", "bad")
|
||||
// return
|
||||
// if(check_access(C))
|
||||
// records.Remove(active_record)
|
||||
// qdel(active_record)
|
||||
// set_temp("Record deleted.", "success")
|
||||
// menu = MENU_RECORDS
|
||||
// else
|
||||
// set_temp("Access denied.", "bad")
|
||||
return
|
||||
|
||||
else if (href_list["view_mrec"])
|
||||
active_mr = locate(href_list["view_mrec"])
|
||||
if(active_mr && istype(active_mr))
|
||||
menu = 5
|
||||
else
|
||||
active_mr = null
|
||||
temp = "ERROR: Record missing."
|
||||
|
||||
else if (href_list["boocnotes"])
|
||||
menu = 6
|
||||
|
||||
else if (href_list["moocnotes"])
|
||||
menu = 7
|
||||
|
||||
else if (href_list["refresh"])
|
||||
updateUsrDialog()
|
||||
|
||||
else if (href_list["coredump"])
|
||||
if(disk)
|
||||
SStranscore.core_dump(disk)
|
||||
sleep(5)
|
||||
visible_message("<span class='warning'>\The [src] spits out \the [disk].</span>")
|
||||
switch(action)
|
||||
if("view_b_rec")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
active_br = locate(ref)
|
||||
if(istype(active_br))
|
||||
if(isnull(active_br.ckey))
|
||||
qdel(active_br)
|
||||
set_temp("Error: Record corrupt.", "bad")
|
||||
else
|
||||
var/can_grow_active = 1
|
||||
if(!synthetic_capable && active_br.synthetic) //Disqualified due to being synthetic in an organic only.
|
||||
can_grow_active = 0
|
||||
set_temp("Error: Cannot grow [active_br.mydna.name] due to lack of synthfabs.", "bad")
|
||||
else if(!organic_capable && !active_br.synthetic) //Disqualified for the opposite.
|
||||
can_grow_active = 0
|
||||
set_temp("Error: Cannot grow [active_br.mydna.name] due to lack of cloners.", "bad")
|
||||
else if(!synthetic_capable && !organic_capable) //What have you done??
|
||||
can_grow_active = 0
|
||||
set_temp("Error: Cannot grow [active_br.mydna.name] due to lack of synthfabs and cloners.", "bad")
|
||||
else if(active_br.toocomplex)
|
||||
can_grow_active = 0
|
||||
set_temp("Error: Cannot grow [active_br.mydna.name] due to species complexity.", "bad")
|
||||
var/list/payload = list(
|
||||
activerecord = "\ref[active_br]",
|
||||
realname = sanitize(active_br.mydna.name),
|
||||
species = active_br.speciesname ? active_br.speciesname : active_br.mydna.dna.species,
|
||||
sex = active_br.bodygender,
|
||||
mind_compat = active_br.locked ? "Low" : "High",
|
||||
synthetic = active_br.synthetic,
|
||||
oocnotes = active_br.body_oocnotes ? active_br.body_oocnotes : "None",
|
||||
can_grow_active = can_grow_active,
|
||||
)
|
||||
tgui_modal_message(src, action, "", null, payload)
|
||||
else
|
||||
active_br = null
|
||||
set_temp("Error: Record missing.", "bad")
|
||||
if("view_m_rec")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
active_mr = locate(ref)
|
||||
if(istype(active_mr))
|
||||
if(isnull(active_mr.ckey))
|
||||
qdel(active_mr)
|
||||
set_temp("Error: Record corrupt.", "bad")
|
||||
else
|
||||
var/can_sleeve_active = 1
|
||||
if(!LAZYLEN(sleevers))
|
||||
can_sleeve_active = 0
|
||||
set_temp("Error: Cannot sleeve due to no sleevers.", "bad")
|
||||
if(!selected_sleever)
|
||||
can_sleeve_active = 0
|
||||
set_temp("Error: Cannot sleeve due to no selected sleever.", "bad")
|
||||
if(selected_sleever && !selected_sleever.occupant)
|
||||
can_sleeve_active = 0
|
||||
set_temp("Error: Cannot sleeve due to lack of sleever occupant.", "bad")
|
||||
var/list/payload = list(
|
||||
activerecord = "\ref[active_mr]",
|
||||
realname = sanitize(active_mr.mindname),
|
||||
obviously_dead = active_mr.dead_state == MR_DEAD ? "Past-due" : "Current",
|
||||
oocnotes = active_mr.mind_oocnotes ? active_mr.mind_oocnotes : "None.",
|
||||
can_sleeve_active = can_sleeve_active,
|
||||
)
|
||||
tgui_modal_message(src, action, "", null, payload)
|
||||
else
|
||||
active_mr = null
|
||||
set_temp("Error: Record missing.", "bad")
|
||||
if("coredump")
|
||||
if(disk)
|
||||
SStranscore.core_dump(disk)
|
||||
sleep(5)
|
||||
visible_message("<span class='warning'>\The [src] spits out \the [disk].</span>")
|
||||
disk.forceMove(get_turf(src))
|
||||
disk = null
|
||||
if("ejectdisk")
|
||||
disk.forceMove(get_turf(src))
|
||||
disk = null
|
||||
|
||||
else if (href_list["ejectdisk"])
|
||||
disk.forceMove(get_turf(src))
|
||||
disk = null
|
||||
|
||||
else if (href_list["create"])
|
||||
if(istype(active_br))
|
||||
//Tried to grow a synth but no synth pods.
|
||||
if(active_br.synthetic && !spods.len)
|
||||
temp = "Error: No SynthFabs detected."
|
||||
//Tried to grow an organic but no growpods.
|
||||
else if(!active_br.synthetic && !pods.len)
|
||||
temp = "Error: No growpods detected."
|
||||
//We have the machines. We can rebuild them. Probably.
|
||||
else
|
||||
//We're cloning a synth.
|
||||
if(active_br.synthetic)
|
||||
var/obj/machinery/transhuman/synthprinter/spod = spods[1]
|
||||
if (spods.len > 1)
|
||||
spod = input(usr,"Select a SynthFab to use", "Printer selection") as anything in spods
|
||||
|
||||
//Already doing someone.
|
||||
if(spod.busy)
|
||||
temp = "Error: SynthFab is currently busy."
|
||||
|
||||
//Not enough steel or glass
|
||||
else if(spod.stored_material[DEFAULT_WALL_MATERIAL] < spod.body_cost)
|
||||
temp = "Error: Not enough [DEFAULT_WALL_MATERIAL] in SynthFab."
|
||||
else if(spod.stored_material["glass"] < spod.body_cost)
|
||||
temp = "Error: Not enough glass in SynthFab."
|
||||
|
||||
//Gross pod (broke mid-cloning or something).
|
||||
else if(spod.broken)
|
||||
temp = "Error: SynthFab malfunction."
|
||||
|
||||
//Do the cloning!
|
||||
else if(spod.print(active_br))
|
||||
temp = "Initiating printing cycle..."
|
||||
menu = 1
|
||||
else
|
||||
temp = "Initiating printing cycle...<br>Error: Post-initialisation failed. Printing cycle aborted."
|
||||
|
||||
//We're cloning an organic.
|
||||
if("create")
|
||||
if(istype(active_br))
|
||||
//Tried to grow a synth but no synth pods.
|
||||
if(active_br.synthetic && !spods.len)
|
||||
set_temp("Error: No SynthFabs detected.", "bad")
|
||||
//Tried to grow an organic but no growpods.
|
||||
else if(!active_br.synthetic && !pods.len)
|
||||
set_temp("Error: No growpods detected.", "Bad")
|
||||
//We have the machines. We can rebuild them. Probably.
|
||||
else
|
||||
var/obj/machinery/clonepod/transhuman/pod = pods[1]
|
||||
if (pods.len > 1)
|
||||
pod = input(usr,"Select a growing pod to use", "Pod selection") as anything in pods
|
||||
//We're cloning a synth.
|
||||
if(active_br.synthetic)
|
||||
var/obj/machinery/transhuman/synthprinter/spod = selected_printer
|
||||
if(!istype(spod))
|
||||
set_temp("Error: No SynthFab selected.", "bad")
|
||||
return
|
||||
|
||||
//Already doing someone.
|
||||
if(pod.occupant)
|
||||
temp = "Error: Growpod is currently occupied."
|
||||
//Already doing someone.
|
||||
if(spod.busy)
|
||||
set_temp("Error: SynthFab is currently busy.", "bad")
|
||||
return
|
||||
|
||||
//Not enough materials.
|
||||
else if(pod.get_biomass() < CLONE_BIOMASS)
|
||||
temp = "Error: Not enough biomass."
|
||||
//Not enough steel or glass
|
||||
else if(spod.stored_material[DEFAULT_WALL_MATERIAL] < spod.body_cost)
|
||||
set_temp("Error: Not enough [DEFAULT_WALL_MATERIAL] in SynthFab.", "bad")
|
||||
return
|
||||
else if(spod.stored_material["glass"] < spod.body_cost)
|
||||
set_temp("Error: Not enough glass in SynthFab.", "bad")
|
||||
return
|
||||
|
||||
//Gross pod (broke mid-cloning or something).
|
||||
else if(pod.mess)
|
||||
temp = "Error: Growpod malfunction."
|
||||
//Gross pod (broke mid-cloning or something).
|
||||
else if(spod.broken)
|
||||
set_temp("Error: SynthFab malfunction.", "bad")
|
||||
return
|
||||
|
||||
//Disabled in config.
|
||||
else if(!config.revival_cloning)
|
||||
temp = "Error: Unable to initiate growing cycle."
|
||||
//Do the cloning!
|
||||
else if(spod.print(active_br))
|
||||
set_temp("Initiating printing cycle...", "good")
|
||||
menu = 1
|
||||
else
|
||||
set_temp("Initiating printing cycle... Error: Post-initialisation failed. Printing cycle aborted.", "bad")
|
||||
return
|
||||
|
||||
//Do the cloning!
|
||||
else if(pod.growclone(active_br))
|
||||
temp = "Initiating growing cycle..."
|
||||
menu = 1
|
||||
//We're cloning an organic.
|
||||
else
|
||||
temp = "Initiating growing cycle...<br>Error: Post-initialisation failed. Growing cycle aborted."
|
||||
var/obj/machinery/clonepod/transhuman/pod = selected_pod
|
||||
if(!istype(pod))
|
||||
set_temp("Error: No clonepod selected.", "bad")
|
||||
return
|
||||
|
||||
//The body record is broken somehow.
|
||||
else
|
||||
temp = "Error: Data corruption."
|
||||
//Already doing someone.
|
||||
if(pod.occupant)
|
||||
set_temp("Error: Growpod is currently occupied.", "bad")
|
||||
return
|
||||
|
||||
else if (href_list["sleeve"])
|
||||
if(istype(active_mr))
|
||||
if(!sleevers.len)
|
||||
temp = "Error: No sleevers detected."
|
||||
//Not enough materials.
|
||||
else if(pod.get_biomass() < CLONE_BIOMASS)
|
||||
set_temp("Error: Not enough biomass.", "bad")
|
||||
return
|
||||
|
||||
//Gross pod (broke mid-cloning or something).
|
||||
else if(pod.mess)
|
||||
set_temp("Error: Growpod malfunction.", "bad")
|
||||
return
|
||||
|
||||
//Disabled in config.
|
||||
else if(!config.revival_cloning)
|
||||
set_temp("Error: Unable to initiate growing cycle.", "bad")
|
||||
return
|
||||
|
||||
//Do the cloning!
|
||||
else if(pod.growclone(active_br))
|
||||
set_temp("Initiating growing cycle...", "good")
|
||||
menu = 1
|
||||
else
|
||||
set_temp("Initiating growing cycle... Error: Post-initialisation failed. Growing cycle aborted.", "bad")
|
||||
return
|
||||
|
||||
//The body record is broken somehow.
|
||||
else
|
||||
var/mode = text2num(href_list["sleeve"])
|
||||
var/override
|
||||
var/obj/machinery/transhuman/resleever/sleever = sleevers[1]
|
||||
if (sleevers.len > 1)
|
||||
sleever = input(usr,"Select a resleeving pod to use", "Resleever selection") as anything in sleevers
|
||||
set_temp("Error: Data corruption.", "bad")
|
||||
return
|
||||
|
||||
switch(mode)
|
||||
if(1) //Body resleeving
|
||||
//No body to sleeve into.
|
||||
if(!sleever.occupant)
|
||||
temp = "Error: Resleeving pod is not occupied."
|
||||
if("sleeve")
|
||||
if(istype(active_mr))
|
||||
if(!sleevers.len)
|
||||
set_temp("Error: No sleevers detected.", "bad")
|
||||
else
|
||||
var/mode = text2num(params["mode"])
|
||||
var/override
|
||||
var/obj/machinery/transhuman/resleever/sleever = selected_sleever
|
||||
if(!istype(sleever))
|
||||
set_temp("Error: No resleeving pod selected.", "bad")
|
||||
return
|
||||
|
||||
//OOC body lock thing.
|
||||
if(sleever.occupant.resleeve_lock && active_mr.ckey != sleever.occupant.resleeve_lock)
|
||||
temp = "Error: Mind incompatible with body."
|
||||
switch(mode)
|
||||
if(1) //Body resleeving
|
||||
//No body to sleeve into.
|
||||
if(!sleever.occupant)
|
||||
set_temp("Error: Resleeving pod is not occupied.", "bad")
|
||||
return
|
||||
|
||||
var/list/subtargets = list()
|
||||
for(var/mob/living/carbon/human/H in sleever.occupant)
|
||||
if(H.resleeve_lock && active_mr.ckey != H.resleeve_lock)
|
||||
continue
|
||||
subtargets += H
|
||||
if(subtargets.len)
|
||||
var/oc_sanity = sleever.occupant
|
||||
override = input(usr,"Multiple bodies detected. Select target for resleeving of [active_mr.mindname] manually. Sleeving of primary body is unsafe with sub-contents, and is not listed.", "Resleeving Target") as null|anything in subtargets
|
||||
if(!override || oc_sanity != sleever.occupant || !(override in sleever.occupant))
|
||||
temp = "Error: Target selection aborted."
|
||||
//OOC body lock thing.
|
||||
if(sleever.occupant.resleeve_lock && active_mr.ckey != sleever.occupant.resleeve_lock)
|
||||
set_temp("Error: Mind incompatible with body.", "bad")
|
||||
return
|
||||
|
||||
if(2) //Card resleeving
|
||||
if(sleever.sleevecards <= 0)
|
||||
temp = "Error: No available cards in resleever."
|
||||
var/list/subtargets = list()
|
||||
for(var/mob/living/carbon/human/H in sleever.occupant)
|
||||
if(H.resleeve_lock && active_mr.ckey != H.resleeve_lock)
|
||||
continue
|
||||
subtargets += H
|
||||
if(subtargets.len)
|
||||
var/oc_sanity = sleever.occupant
|
||||
override = input(usr,"Multiple bodies detected. Select target for resleeving of [active_mr.mindname] manually. Sleeving of primary body is unsafe with sub-contents, and is not listed.", "Resleeving Target") as null|anything in subtargets
|
||||
if(!override || oc_sanity != sleever.occupant || !(override in sleever.occupant))
|
||||
set_temp("Error: Target selection aborted.", "bad")
|
||||
return
|
||||
|
||||
//Body to sleeve into, but mind is in another living body.
|
||||
if(active_mr.mind_ref.current && active_mr.mind_ref.current.stat < DEAD) //Mind is in a body already that's alive
|
||||
var/answer = alert(active_mr.mind_ref.current,"Someone is attempting to restore a backup of your mind. Do you want to abandon this body, and move there? You MAY suffer memory loss! (Same rules as CMD apply)","Resleeving","No","Yes")
|
||||
if(2) //Card resleeving
|
||||
if(sleever.sleevecards <= 0)
|
||||
set_temp("Error: No available cards in resleever.", "bad")
|
||||
return
|
||||
|
||||
//They declined to be moved.
|
||||
if(answer == "No")
|
||||
temp = "Initiating resleeving...<br>Error: Post-initialisation failed. Resleeving cycle aborted."
|
||||
//Body to sleeve into, but mind is in another living body.
|
||||
if(active_mr.mind_ref.current && active_mr.mind_ref.current.stat < DEAD) //Mind is in a body already that's alive
|
||||
var/answer = alert(active_mr.mind_ref.current,"Someone is attempting to restore a backup of your mind. Do you want to abandon this body, and move there? You MAY suffer memory loss! (Same rules as CMD apply)","Resleeving","No","Yes")
|
||||
|
||||
//They declined to be moved.
|
||||
if(answer == "No")
|
||||
set_temp("Initiating resleeving... Error: Post-initialisation failed. Resleeving cycle aborted.", "bad")
|
||||
menu = MENU_MAIN
|
||||
return TRUE
|
||||
|
||||
//They were dead, or otherwise available.
|
||||
if(!temp)
|
||||
sleever.putmind(active_mr,mode,override)
|
||||
set_temp("Initiating resleeving...")
|
||||
menu = 1
|
||||
|
||||
//They were dead, or otherwise available.
|
||||
if(!temp)
|
||||
sleever.putmind(active_mr,mode,override)
|
||||
temp = "Initiating resleeving..."
|
||||
menu = 1
|
||||
|
||||
//IDK but it broke somehow.
|
||||
return
|
||||
if("refresh")
|
||||
SStgui.update_uis(src)
|
||||
if("selectpod")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
var/obj/machinery/clonepod/selected = locate(ref)
|
||||
if(istype(selected) && (selected in pods))
|
||||
selected_pod = selected
|
||||
if("selectprinter")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
var/obj/machinery/transhuman/synthprinter/selected = locate(ref)
|
||||
if(istype(selected) && (selected in spods))
|
||||
selected_printer = selected
|
||||
if("selectsleever")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
var/obj/machinery/transhuman/resleever/selected = locate(ref)
|
||||
if(istype(selected) && (selected in sleevers))
|
||||
selected_sleever = selected
|
||||
if("menu")
|
||||
menu = clamp(text2num(params["num"]), MENU_MAIN, MENU_MIND)
|
||||
if("cleartemp")
|
||||
temp = null
|
||||
else
|
||||
temp = "Error: Data corruption."
|
||||
|
||||
else if (href_list["menu"])
|
||||
menu = href_list["menu"]
|
||||
temp = ""
|
||||
|
||||
SSnanoui.update_uis(src)
|
||||
add_fingerprint(usr)
|
||||
return FALSE
|
||||
|
||||
// In here because only relevant to computer
|
||||
/obj/item/weapon/cmo_disk_holder
|
||||
@@ -409,3 +493,19 @@
|
||||
item_state = "card-id"
|
||||
w_class = ITEMSIZE_SMALL
|
||||
var/datum/transhuman/mind_record/list/stored = list()
|
||||
|
||||
/**
|
||||
* Sets a temporary message to display to the user
|
||||
*
|
||||
* Arguments:
|
||||
* * text - Text to display, null/empty to clear the message from the UI
|
||||
* * style - The style of the message: (color name), info, success, warning, danger
|
||||
*/
|
||||
/obj/machinery/computer/transhuman/resleeving/proc/set_temp(text = "", style = "info", update_now = FALSE)
|
||||
temp = list(text = text, style = style)
|
||||
if(update_now)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
#undef MENU_MAIN
|
||||
#undef MENU_BODY
|
||||
#undef MENU_MIND
|
||||
@@ -162,6 +162,11 @@
|
||||
|
||||
return
|
||||
|
||||
/obj/machinery/clonepod/transhuman/get_completion()
|
||||
if(occupant)
|
||||
return 100 * ((occupant.health + abs(config.health_threshold_dead)) / (occupant.maxHealth + abs(config.health_threshold_dead)))
|
||||
return 0
|
||||
|
||||
//Synthetic version
|
||||
/obj/machinery/transhuman/synthprinter
|
||||
name = "SynthFab 3000"
|
||||
@@ -437,28 +442,40 @@
|
||||
sickness_duration = (45 - (total_rating-4)*1.875) MINUTES // 45 minutes default, 30 minutes with max non-anomaly upgrades, 15 minutes with max anomaly ones
|
||||
|
||||
/obj/machinery/transhuman/resleever/attack_hand(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
var/health_text = ""
|
||||
var/mind_text = ""
|
||||
if(src.occupant)
|
||||
if(src.occupant.stat >= DEAD)
|
||||
health_text = "<FONT color=red>DEAD</FONT>"
|
||||
else if(src.occupant.health < 0)
|
||||
health_text = "<FONT color=red>[round(src.occupant.health,0.1)]</FONT>"
|
||||
else
|
||||
health_text = "[round(src.occupant.health,0.1)]"
|
||||
tgui_interact(user)
|
||||
|
||||
if(src.occupant.mind)
|
||||
mind_text = "Mind present: [occupant.mind.name]"
|
||||
else
|
||||
mind_text = "Mind absent."
|
||||
/obj/machinery/transhuman/resleever/tgui_interact(mob/user, datum/tgui/ui = null)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
var/dat ="<B>Resleever Status</B><BR>"
|
||||
dat +="<B>Current occupant:</B> [src.occupant ? "<BR>Name: [src.occupant]<BR>Health: [health_text]<BR>" : "<FONT color=red>None</FONT>"]<BR>"
|
||||
dat +="<B>Mind status:</B> [mind_text]<BR>"
|
||||
user.set_machine(src)
|
||||
user << browse(dat, "window=resleever")
|
||||
onclose(user, "resleever")
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ResleevingPod", "Resleever")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/transhuman/resleever/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["occupied"] = !!occupant
|
||||
if(occupant)
|
||||
data["name"] = occupant.name
|
||||
data["health"] = occupant.health
|
||||
data["maxHealth"] = occupant.maxHealth
|
||||
data["stat"] = occupant.stat
|
||||
data["mindStatus"] = !!occupant.mind
|
||||
data["mindName"] = occupant.mind?.name
|
||||
|
||||
if(occupant.has_modifier_of_type(/datum/modifier/resleeving_sickness) || occupant.has_modifier_of_type(/datum/modifier/faux_resleeving_sickness))
|
||||
data["resleeveSick"] = TRUE
|
||||
else
|
||||
data["resleeveSick"] = FALSE
|
||||
|
||||
if(occupant.confused || occupant.eye_blurry)
|
||||
data["initialSick"] = TRUE
|
||||
else
|
||||
data["initialSick"] = FALSE
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/transhuman/resleever/attackby(obj/item/W as obj, mob/user as mob)
|
||||
src.add_fingerprint(user)
|
||||
|
||||
@@ -119,6 +119,8 @@
|
||||
max_duration = 100
|
||||
|
||||
/datum/surgery_step/cavity/place_item/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
if(!istype(tool))
|
||||
return 0
|
||||
if(..())
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
if(istype(user,/mob/living/silicon/robot))
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
max_duration = 70
|
||||
|
||||
/datum/surgery_step/limb/attach/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
if(!istype(tool))
|
||||
return 0
|
||||
var/obj/item/organ/external/E = tool
|
||||
var/obj/item/organ/external/P = target.organs_by_name[E.parent_organ]
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
@@ -117,7 +119,7 @@
|
||||
max_duration = 100
|
||||
|
||||
/datum/surgery_step/limb/mechanize/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
if(..())
|
||||
if(..() && istype(tool))
|
||||
var/obj/item/robot_parts/p = tool
|
||||
if (p.part)
|
||||
if (!(target_zone in p.part))
|
||||
|
||||
@@ -164,6 +164,9 @@
|
||||
if (!..())
|
||||
return 0
|
||||
|
||||
if(!istype(tool))
|
||||
return 0
|
||||
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
|
||||
if(!(affected && !(affected.robotic >= ORGAN_ROBOT)))
|
||||
@@ -227,6 +230,9 @@
|
||||
if (!..())
|
||||
return 0
|
||||
|
||||
if(!istype(tool))
|
||||
return 0
|
||||
|
||||
target.op_stage.current_organ = null
|
||||
|
||||
var/list/removable_organs = list()
|
||||
@@ -281,7 +287,7 @@
|
||||
var/obj/item/organ/internal/O = tool
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
|
||||
if(!affected)
|
||||
if(!affected || !istype(O))
|
||||
return
|
||||
|
||||
var/organ_compatible
|
||||
@@ -361,6 +367,9 @@
|
||||
if (!..())
|
||||
return 0
|
||||
|
||||
if(!istype(tool))
|
||||
return 0
|
||||
|
||||
target.op_stage.current_organ = null
|
||||
|
||||
var/list/removable_organs = list()
|
||||
@@ -417,6 +426,9 @@
|
||||
if (!..())
|
||||
return 0
|
||||
|
||||
if(!istype(tool))
|
||||
return 0
|
||||
|
||||
target.op_stage.current_organ = null
|
||||
|
||||
var/list/removable_organs = list()
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* tgui modals
|
||||
*
|
||||
* Allows creation of modals within tgui.
|
||||
*/
|
||||
|
||||
GLOBAL_LIST(tgui_modals)
|
||||
|
||||
/**
|
||||
* Call this from a proc that is called in tgui_act() to process modal actions
|
||||
*
|
||||
* Example: /obj/machinery/chem_master/proc/tgui_act_modal
|
||||
* You can then switch based on the return value and show different
|
||||
* modals depending on the answer.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * action - The called action
|
||||
* * params - The params to the action
|
||||
*/
|
||||
/datum/proc/tgui_modal_act(datum/source = src, action = "", params)
|
||||
ASSERT(istype(source))
|
||||
|
||||
. = null
|
||||
switch(action)
|
||||
if("modal_open") // Params: id, arguments
|
||||
return TGUI_MODAL_OPEN
|
||||
if("modal_answer") // Params: id, answer, arguments
|
||||
params["answer"] = tgui_modal_preprocess_answer(source, params["answer"])
|
||||
if(tgui_modal_answer(source, params["id"], params["answer"])) // If there's a current modal with a delegate that returned TRUE, no need to continue
|
||||
. = TGUI_MODAL_DELEGATE
|
||||
else
|
||||
. = TGUI_MODAL_ANSWER
|
||||
tgui_modal_clear(source)
|
||||
if("modal_close") // Params: id
|
||||
tgui_modal_clear(source)
|
||||
return TGUI_MODAL_CLOSE
|
||||
|
||||
/**
|
||||
* Call this from tgui_data() to return modal information if needed
|
||||
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
*/
|
||||
/datum/proc/tgui_modal_data(datum/source = src)
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, REF(source))
|
||||
if(!current)
|
||||
return null
|
||||
|
||||
return current.to_data()
|
||||
|
||||
/**
|
||||
* Clears the current modal for a given datum
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
*/
|
||||
/datum/proc/tgui_modal_clear(datum/source = src)
|
||||
ASSERT(istype(source))
|
||||
|
||||
LAZYINITLIST(GLOB.tgui_modals)
|
||||
var/datum/tgui_modal/previous = GLOB.tgui_modals[REF(source)]
|
||||
if(!previous)
|
||||
return FALSE
|
||||
|
||||
for(var/i in 1 to length(GLOB.tgui_modals))
|
||||
var/key = GLOB.tgui_modals[i]
|
||||
if(previous == GLOB.tgui_modals[key])
|
||||
GLOB.tgui_modals.Cut(i, i + 1)
|
||||
break
|
||||
|
||||
SStgui.update_uis(source)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Opens a message TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when closed
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
*/
|
||||
/datum/proc/tgui_modal_message(datum/source = src, id, text = "Default modal message", delegate, arguments)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/modal = new(id, text, delegate, arguments)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a text input TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the input
|
||||
* * max_length - The maximum char length of the input
|
||||
*/
|
||||
/datum/proc/tgui_modal_input(datum/source = src, id, text = "Default modal message", delegate, arguments, value = "", max_length = TGUI_MODAL_INPUT_MAX_LENGTH)
|
||||
ASSERT(length(id))
|
||||
ASSERT(max_length > 0)
|
||||
|
||||
var/datum/tgui_modal/input/modal = new(id, text, delegate, arguments, value, max_length)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a dropdown input TGUI modal
|
||||
*
|
||||
* Internally checks if the answer is in the list of choices.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the dropdown
|
||||
* * choices - The list of available choices in the dropdown
|
||||
*/
|
||||
/datum/proc/tgui_modal_choice(datum/source = src, id, text = "Default modal message", delegate, arguments, value = "", choices)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/input/choice/modal = new(id, text, delegate, arguments, value, choices)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a bento input TGUI modal
|
||||
*
|
||||
* Internally checks if the answer is in the list of choices.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the bento
|
||||
* * choices - The list of available choices in the bento
|
||||
*/
|
||||
/datum/proc/tgui_modal_bento(datum/source = src, id, text = "Default modal message", delegate, arguments, value, choices)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/input/bento/modal = new(id, text, delegate, arguments, value, choices)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a yes/no TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when "Yes" is pressed
|
||||
* * delegate_no - The proc to call when "No" is pressed
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * yes_text - The text to show in the "Yes" button
|
||||
* * no_text - The text to show in the "No" button
|
||||
*/
|
||||
/datum/proc/tgui_modal_boolean(datum/source = src, id, text = "Default modal message", delegate, delegate_no, arguments, yes_text = "Yes", no_text = "No")
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/boolean/modal = new(id, text, delegate, delegate_no, arguments, yes_text, no_text)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Registers a given modal to a source. Private.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * modal - The datum/tgui_modal to register
|
||||
* * replace_previous - Whether any modal currently assigned to source should be replaced
|
||||
* * instant_update - Whether the changes should reflect immediately
|
||||
*/
|
||||
/datum/proc/tgui_modal_new(datum/source = src, datum/tgui_modal/modal = null, replace_previous = TRUE, instant_update = TRUE)
|
||||
ASSERT(istype(source))
|
||||
ASSERT(istype(modal))
|
||||
|
||||
var/datum/tgui_modal/previous = LAZYACCESS(GLOB.tgui_modals, REF(source))
|
||||
if(previous && !replace_previous)
|
||||
return FALSE
|
||||
|
||||
modal.owning_source = source
|
||||
|
||||
// Previous one should get GC'd
|
||||
LAZYSET(GLOB.tgui_modals, REF(source), modal)
|
||||
if(instant_update)
|
||||
SStgui.update_uis(source)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Calls the source's currently assigned modal's (if there is one) on_answer() proc. Private.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * answer - The provided answer
|
||||
*/
|
||||
/datum/proc/tgui_modal_answer(datum/source = src, id, answer = "")
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, REF(source))
|
||||
if(!current)
|
||||
return FALSE
|
||||
|
||||
return current.on_answer(answer)
|
||||
|
||||
/**
|
||||
* Passes an answer from JS through the modal's proc.
|
||||
*
|
||||
* Used namely for cutting the text short if it's longer
|
||||
* than an input modal's max_length.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * answer - The provided answer
|
||||
*/
|
||||
/datum/proc/tgui_modal_preprocess_answer(datum/source = src, answer = "")
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, REF(source))
|
||||
if(!current)
|
||||
return answer
|
||||
|
||||
return current.preprocess_answer(answer)
|
||||
|
||||
/**
|
||||
* Modal datum (contains base information for a modal)
|
||||
*/
|
||||
/datum/tgui_modal
|
||||
var/datum/owning_source
|
||||
var/id
|
||||
var/text
|
||||
var/delegate
|
||||
var/list/arguments
|
||||
var/modal_type = "message"
|
||||
|
||||
/datum/tgui_modal/New(id, text, delegate, list/arguments)
|
||||
src.id = id
|
||||
src.text = text
|
||||
src.delegate = delegate
|
||||
src.arguments = arguments
|
||||
|
||||
/**
|
||||
* Called when it's time to pre-process the answer before using it
|
||||
*
|
||||
* Arguments:
|
||||
* * answer - The answer, a nullable text
|
||||
*/
|
||||
/datum/tgui_modal/proc/preprocess_answer(answer)
|
||||
return reject_bad_text(answer, TGUI_MODAL_INPUT_MAX_LENGTH) // bleh
|
||||
|
||||
/**
|
||||
* Called when a modal receives an answer
|
||||
*
|
||||
* Arguments:
|
||||
* * answer - The answer, a nullable text
|
||||
*/
|
||||
/datum/tgui_modal/proc/on_answer(answer)
|
||||
if(delegate)
|
||||
return call(owning_source, delegate)(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Creates a list that describes a modal visually to be passed to JS
|
||||
*/
|
||||
/datum/tgui_modal/proc/to_data()
|
||||
. = list()
|
||||
.["id"] = id
|
||||
.["text"] = text
|
||||
.["args"] = arguments || list()
|
||||
.["type"] = modal_type
|
||||
|
||||
/**
|
||||
* Input modal - has a text entry that can be used to enter an answer
|
||||
*/
|
||||
/datum/tgui_modal/input
|
||||
modal_type = "input"
|
||||
var/value
|
||||
var/max_length
|
||||
|
||||
/datum/tgui_modal/input/New(id, text, delegate, list/arguments, value, max_length)
|
||||
..(id, text, delegate, arguments)
|
||||
src.value = value
|
||||
src.max_length = max_length
|
||||
|
||||
/datum/tgui_modal/input/preprocess_answer(answer)
|
||||
. = ..(answer)
|
||||
if(length(answer) > max_length)
|
||||
. = copytext(., 1, max_length + 1)
|
||||
|
||||
/datum/tgui_modal/input/to_data()
|
||||
. = ..()
|
||||
.["value"] = value
|
||||
|
||||
/**
|
||||
* Choice modal - has a dropdown menu that can be used to select an answer
|
||||
*/
|
||||
/datum/tgui_modal/input/choice
|
||||
modal_type = "choice"
|
||||
var/choices
|
||||
|
||||
/datum/tgui_modal/input/choice/New(id, text, delegate, list/arguments, value, choices)
|
||||
..(id, text, delegate, arguments, value, TGUI_MODAL_INPUT_MAX_LENGTH) // Max length doesn't really matter in dropdowns, but whatever
|
||||
src.choices = choices
|
||||
|
||||
/datum/tgui_modal/input/choice/on_answer(answer)
|
||||
if(answer in choices) // Make sure the answer is actually in our choices!
|
||||
return ..(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/input/choice/to_data()
|
||||
. = ..()
|
||||
.["choices"] = choices
|
||||
|
||||
/**
|
||||
* Bento modal - Similar to choice, it displays the choices in a grid of images
|
||||
*
|
||||
* The returned answer is the index of the choice.
|
||||
*/
|
||||
/datum/tgui_modal/input/bento
|
||||
modal_type = "bento"
|
||||
var/choices
|
||||
|
||||
/datum/tgui_modal/input/bento/New(id, text, delegate, list/arguments, value, choices)
|
||||
..(id, text, delegate, arguments, text2num(value), TGUI_MODAL_INPUT_MAX_LENGTH) // Max length doesn't really matter in here, but whatever
|
||||
src.choices = choices
|
||||
|
||||
/datum/tgui_modal/input/bento/preprocess_answer(answer)
|
||||
return text2num(answer) || 0
|
||||
|
||||
/datum/tgui_modal/input/bento/on_answer(answer)
|
||||
if(answer >= 1 && answer <= length(choices)) // Make sure the answer index is actually in our indexes!
|
||||
return ..(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/input/bento/to_data()
|
||||
. = ..()
|
||||
.["choices"] = choices
|
||||
|
||||
/**
|
||||
* Boolean modal - has yes/no buttons that do different actions depending on which is pressed
|
||||
*/
|
||||
/datum/tgui_modal/boolean
|
||||
modal_type = "boolean"
|
||||
var/delegate_no
|
||||
var/yes_text
|
||||
var/no_text
|
||||
|
||||
/datum/tgui_modal/boolean/New(id, text, delegate, delegate_no, list/arguments, yes_text, no_text)
|
||||
..(id, text, delegate, arguments)
|
||||
src.delegate_no = delegate_no
|
||||
src.yes_text = yes_text
|
||||
src.no_text = no_text
|
||||
|
||||
/datum/tgui_modal/boolean/preprocess_answer(answer)
|
||||
return text2num(answer) || FALSE
|
||||
|
||||
/datum/tgui_modal/boolean/on_answer(answer)
|
||||
if(answer)
|
||||
return ..(answer, arguments)
|
||||
else if(delegate_no)
|
||||
return call(owning_source, delegate_no)(arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/boolean/to_data()
|
||||
. = ..()
|
||||
.["yes_text"] = yes_text
|
||||
.["no_text"] = no_text
|
||||
Reference in New Issue
Block a user