/obj/machinery/rnd/production
name = "technology fabricator"
desc = "Makes researched and prototype items with materials and energy."
layer = BELOW_OBJ_LAYER
var/consoleless_interface = TRUE //Whether it can be used without a console.
var/print_cost_coeff = 1 //Materials needed * coeff = actual.
var/list/categories = list()
var/datum/component/remote_materials/materials
var/allowed_department_flags = ALL
var/production_animation //What's flick()'d on print.
var/allowed_buildtypes = NONE
var/list/datum/design/cached_designs
var/list/datum/design/matching_designs
var/department_tag = "Unidentified" //used for material distribution among other things.
var/datum/techweb/stored_research
var/datum/techweb/host_research
var/screen = RESEARCH_FABRICATOR_SCREEN_MAIN
var/selected_category
var/offstation_security_levels
/obj/machinery/rnd/production/Initialize(mapload)
if(mapload && offstation_security_levels)
log_mapping("Depricated var named \"offstation_security_levels\" at ([x], [y], [z])!")
. = ..()
create_reagents(0, OPENCONTAINER)
matching_designs = list()
cached_designs = list()
stored_research = new
host_research = SSresearch.science_tech
update_research()
materials = AddComponent(/datum/component/remote_materials, "lathe", mapload, _after_insert=CALLBACK(src, PROC_REF(AfterMaterialInsert)))
RefreshParts()
/obj/machinery/rnd/production/Destroy()
materials = null
cached_designs = null
matching_designs = null
QDEL_NULL(stored_research)
host_research = null
return ..()
/obj/machinery/rnd/production/proc/update_research()
set waitfor = FALSE
host_research.copy_research_to(stored_research, TRUE)
update_designs()
/obj/machinery/rnd/production/proc/update_designs()
cached_designs.Cut()
for(var/i in stored_research.researched_designs)
var/datum/design/d = SSresearch.techweb_design_by_id(i)
if((isnull(allowed_department_flags) || (d.departmental_flags & allowed_department_flags)) && (d.build_type & allowed_buildtypes))
cached_designs |= d
/obj/machinery/rnd/production/RefreshParts()
calculate_efficiency()
/obj/machinery/rnd/production/ui_interact(mob/user)
if(!consoleless_interface)
return ..()
user.set_machine(src)
var/datum/browser/popup = new(user, "rndconsole", name, 460, 550)
popup.set_content(generate_ui())
popup.open()
/obj/machinery/rnd/production/proc/calculate_efficiency()
var/total_manip_rating = 0
var/manips = 0
if(reagents) //If reagents/materials aren't initialized, don't bother, we'll be doing this again after reagents init anyways.
reagents.maximum_volume = 0
for(var/obj/item/reagent_containers/glass/G in component_parts)
reagents.maximum_volume += G.volume
G.reagents.trans_to(src, G.reagents.total_volume)
if(materials)
var/total_storage = 0
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
total_storage += M.rating * 75000
materials.set_local_size(total_storage)
for(var/obj/item/stock_parts/manipulator/M in component_parts)
total_manip_rating += M.rating
manips++
print_cost_coeff = STANDARD_PART_LEVEL_LATHE_COEFFICIENT(total_manip_rating / (manips? manips : 1))
/obj/machinery/rnd/production/examine(mob/user)
. = ..()
var/datum/component/remote_materials/materials = GetComponent(/datum/component/remote_materials)
if(in_range(user, src) || isobserver(user))
. += "The status display reads: Storing up to [materials.local_size] material units locally.
Material usage cost at [print_cost_coeff*100]%."
//we eject the materials upon deconstruction.
/obj/machinery/rnd/production/on_deconstruction()
for(var/obj/item/reagent_containers/glass/G in component_parts)
reagents.trans_to(G, G.reagents.maximum_volume)
return ..()
/obj/machinery/rnd/production/proc/do_print(path, amount, list/matlist, notify_admins, mob/user)
if(notify_admins)
message_admins("[ADMIN_LOOKUPFLW(user)] has built [amount] of [path] at a [src]([type]).")
for(var/i in 1 to amount)
var/obj/O = new path(get_turf(src))
if(efficient_with(O.type))
O.set_custom_materials(matlist)
O.rnd_crafted(src)
SSblackbox.record_feedback("nested tally", "item_printed", amount, list("[type]", "[path]"))
investigate_log("[key_name(user)] built [amount] of [path] at [src]([type]).", INVESTIGATE_RESEARCH)
/obj/machinery/rnd/production/proc/check_mat(datum/design/being_built, var/mat) // now returns how many times the item can be built with the material
if (!materials.mat_container) // no connected silo
return FALSE
var/list/all_materials = being_built.reagents_list + being_built.materials
var/A = materials.mat_container.get_material_amount(mat)
if(!A)
A = reagents.get_reagent_amount(mat)
// these types don't have their .materials set in do_print, so don't allow
// them to be constructed efficiently
var/ef = efficient_with(being_built.build_path) ? print_cost_coeff : 1
return round(A / max(1, all_materials[mat] * ef))
/obj/machinery/rnd/production/proc/efficient_with(path)
return !ispath(path, /obj/item/stack/sheet) && !ispath(path, /obj/item/stack/ore/bluespace_crystal) && !ispath(path, /obj/item/stack/ducts)
/obj/machinery/rnd/production/proc/user_try_print_id(id, amount)
if((!istype(linked_console) && requires_console) || !id)
return FALSE
if(istext(amount))
amount = text2num(amount)
if(isnull(amount))
amount = 1
var/datum/design/D = (linked_console || requires_console)? (linked_console.stored_research.researched_designs[id]? SSresearch.techweb_design_by_id(id) : null) : SSresearch.techweb_design_by_id(id)
if(!istype(D))
return FALSE
if(!(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags)))
say("Warning: Printing failed: This fabricator does not have the necessary keys to decrypt design schematics. Please update the research data with the on-screen button and contact GATO Support!") //GS13 - Nanotrasen to GATO
return FALSE
if(D.build_type && !(D.build_type & allowed_buildtypes))
say("This machine does not have the necessary manipulation systems for this design. Please contact GATO Support!") //GS13 - Nanotrasen to GATO
return FALSE
if(!(obj_flags & EMAGGED) && (offstation_security_levels || is_station_level(z)))
if(GLOB.security_level < D.min_security_level)
say("Minimum security alert level required to print this design not met, please contact the command staff.")
return FALSE
if(GLOB.security_level > D.max_security_level)
say("Exceeded maximum security alert level required to print this design, please contact the command staff.")
if(!materials.mat_container)
say("No connection to material storage, please contact the quartermaster.")
return FALSE
if(materials.on_hold())
say("Mineral access is on hold, please contact the quartermaster.")
return FALSE
var/power = 1000
amount = clamp(amount, 1, 50)
for(var/M in D.materials)
power += round(D.materials[M] * amount / 35)
power = min(3000, power)
use_power(power)
var/coeff = efficient_with(D.build_path) ? print_cost_coeff : 1
var/list/efficient_mats = list()
for(var/MAT in D.materials)
efficient_mats[MAT] = D.materials[MAT] * coeff
if(!materials.mat_container.has_materials(efficient_mats, amount))
say("Not enough materials to complete prototype[amount > 1? "s" : ""].")
return FALSE
for(var/R in D.reagents_list)
if(!reagents.has_reagent(R, D.reagents_list[R] * amount * coeff))
say("Not enough reagents to complete prototype[amount > 1? "s" : ""].")
return FALSE
materials.mat_container.use_materials(efficient_mats, amount)
materials.silo_log(src, "built", -amount, "[D.name]", efficient_mats)
for(var/R in D.reagents_list)
reagents.remove_reagent(R, D.reagents_list[R] * amount * coeff)
busy = TRUE
if(production_animation)
flick(production_animation, src)
var/timecoeff = D.lathe_time_factor * print_cost_coeff
addtimer(CALLBACK(src, PROC_REF(reset_busy)), (20 * timecoeff * amount) ** 0.5)
addtimer(CALLBACK(src, PROC_REF(do_print), D.build_path, amount, efficient_mats, D.dangerous_construction, usr), (20 * timecoeff * amount) ** 0.5)
return TRUE
/obj/machinery/rnd/production/proc/search(string)
matching_designs.Cut()
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(D.build_type & allowed_buildtypes) || !(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags)))
continue
if(findtext(D.name,string))
matching_designs.Add(D)
/obj/machinery/rnd/production/proc/generate_ui()
var/list/ui = list()
ui += ui_header()
switch(screen)
if(RESEARCH_FABRICATOR_SCREEN_MATERIALS)
ui += ui_screen_materials()
if(RESEARCH_FABRICATOR_SCREEN_CHEMICALS)
ui += ui_screen_chemicals()
if(RESEARCH_FABRICATOR_SCREEN_SEARCH)
ui += ui_screen_search()
if(RESEARCH_FABRICATOR_SCREEN_CATEGORYVIEW)
ui += ui_screen_category_view()
else
ui += ui_screen_main()
for(var/i in 1 to length(ui))
if(!findtextEx(ui[i], RDSCREEN_NOBREAK))
ui[i] += "
"
ui[i] = replacetextEx(ui[i], RDSCREEN_NOBREAK, "")
return ui.Join("")
/obj/machinery/rnd/production/proc/ui_header()
var/list/l = list()
l += "
| [C] | " line_length++ l += "