/obj/machinery/rnd/production name = "technology fabricator" desc = "Makes researched and prototype items with materials and energy." container_type = OPENCONTAINER var/consoleless_interface = FALSE //Whether it can be used without a console. var/efficiency_coeff = 1 //Materials needed / coeff = actual. var/list/categories = list() var/datum/component/material_container/materials //Store for hyper speed! 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 /obj/machinery/rnd/production/Initialize() . = ..() create_reagents(0) materials = AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE, MAT_PLASTIC), 0, FALSE, list(/obj/item/stack), CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert)) materials.precise_insertion = TRUE RefreshParts() matching_designs = list() cached_designs = list() stored_research = new host_research = SSresearch.science_tech update_research() /obj/machinery/rnd/production/proc/update_research() 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 = stored_research.researched_designs[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/attack_hand(mob/user) interact(user) //remove this snowflake shit when the refactor of storage components or some other pr that unsnowflakes attack_hand on machinery is in /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/Destroy() QDEL_NULL(stored_research) return ..() /obj/machinery/rnd/production/proc/calculate_efficiency() efficiency_coeff = 1 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) materials.max_amount = 0 for(var/obj/item/stock_parts/matter_bin/M in component_parts) materials.max_amount += M.rating * 75000 var/total_rating = 0 for(var/obj/item/stock_parts/manipulator/M in component_parts) total_rating += M.rating total_rating = max(1, total_rating) efficiency_coeff = total_rating //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) materials.retrieve_all() return ..() /obj/machinery/rnd/production/proc/do_print(path, amount, list/matlist, notify_admins) if(notify_admins) investigate_log("[key_name(usr)] built [amount] of [path] at [src]([type]).", INVESTIGATE_RESEARCH) message_admins("[ADMIN_LOOKUPFLW(usr)] has built [amount] of [path] at a [src]([type]).") for(var/i in 1 to amount) var/obj/item/I = new path(get_turf(src)) if(!istype(I, /obj/item/stack/sheet) && !istype(I, /obj/item/stack/ore/bluespace_crystal)) I.materials = matlist.Copy() SSblackbox.record_feedback("nested tally", "item_printed", amount, list("[type]", "[path]")) /obj/machinery/rnd/production/proc/check_mat(datum/design/being_built, M) // now returns how many times the item can be built with the material var/list/all_materials = being_built.reagents_list + being_built.materials var/A = materials.amount(M) if(!A) A = reagents.get_reagent_amount(M) return round(A / max(1, (all_materials[M]/efficiency_coeff))) /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] : get_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 Nanotrasen Support!") 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 Nanotrasen Support!") 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/list/efficient_mats = list() for(var/MAT in D.materials) efficient_mats[MAT] = D.materials[MAT]/efficiency_coeff if(!materials.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/efficiency_coeff)) say("Not enough reagents to complete prototype[amount > 1? "s" : ""].") return FALSE materials.use_amount(efficient_mats, amount) for(var/R in D.reagents_list) reagents.remove_reagent(R, D.reagents_list[R]*amount/efficiency_coeff) busy = TRUE if(production_animation) flick(production_animation, src) var/timecoeff = D.lathe_time_factor / efficiency_coeff addtimer(CALLBACK(src, .proc/reset_busy), (30 * timecoeff * amount) ** 0.5) addtimer(CALLBACK(src, .proc/do_print, D.build_path, amount, efficient_mats, D.dangerous_construction), (32 * timecoeff * amount) ** 0.8) return TRUE /obj/machinery/rnd/production/proc/search(string) matching_designs.Cut() for(var/v in stored_research.researched_designs) var/datum/design/D = stored_research.researched_designs[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 += "
[host_research.organization] [department_tag] Department Lathe" l += "Security protocols: [(obj_flags & EMAGGED)? "Disabled" : "Enabled"]" l += "Material Amount: [materials.total_amount] / [materials.max_amount]" l += "Chemical volume: [reagents.total_volume] / [reagents.maximum_volume]" l += "Synchronize Research" l += "Main Screen
[RDSCREEN_NOBREAK]" return l /obj/machinery/rnd/production/proc/ui_screen_materials() var/list/l = list() l += "

Material Storage:

" for(var/mat_id in materials.materials) var/datum/material/M = materials.materials[mat_id] l += "* [M.amount] of [M.name]: " if(M.amount >= MINERAL_MATERIAL_AMOUNT) l += "Eject [RDSCREEN_NOBREAK]" if(M.amount >= MINERAL_MATERIAL_AMOUNT*5) l += "5x [RDSCREEN_NOBREAK]" if(M.amount >= MINERAL_MATERIAL_AMOUNT) l += "All[RDSCREEN_NOBREAK]" l += "" l += "
[RDSCREEN_NOBREAK]" return l /obj/machinery/rnd/production/proc/ui_screen_chemicals() var/list/l = list() l += "
Disposal All Chemicals in Storage" l += "

Chemical Storage:

" for(var/datum/reagent/R in reagents.reagent_list) l += "[R.name]: [R.volume]" l += "Purge" l += "
" return l /obj/machinery/rnd/production/proc/ui_screen_search() var/list/l = list() var/coeff = efficiency_coeff l += "

Search Results:

" l += "
\ \ \ \ \

" for(var/datum/design/D in matching_designs) l += design_menu_entry(D, coeff) l += "" return l /obj/machinery/rnd/production/proc/design_menu_entry(datum/design/D, coeff) if(!istype(D)) return if(!coeff) coeff = efficiency_coeff var/list/l = list() var/temp_material var/c = 50 var/t var/all_materials = D.materials + D.reagents_list for(var/M in all_materials) t = check_mat(D, M) temp_material += " | " if (t < 1) temp_material += "[all_materials[M]/coeff] [CallMaterialName(M)]" else temp_material += " [all_materials[M]/coeff] [CallMaterialName(M)]" c = min(c,t) if (c >= 1) l += "[D.name][RDSCREEN_NOBREAK]" if(c >= 5) l += "x5[RDSCREEN_NOBREAK]" if(c >= 10) l += "x10[RDSCREEN_NOBREAK]" l += "[temp_material][RDSCREEN_NOBREAK]" else l += "[D.name][temp_material][RDSCREEN_NOBREAK]" l += "" return l /obj/machinery/rnd/production/Topic(raw, ls) if(..()) return add_fingerprint(usr) usr.set_machine(src) if(ls["switch_screen"]) screen = text2num(ls["switch_screen"]) if(ls["build"]) //Causes the Protolathe to build something. if(busy) say("Warning: Fabricators busy!") else user_try_print_id(ls["build"], ls["amount"]) if(ls["search"]) //Search for designs with name matching pattern search(ls["to_search"]) screen = RESEARCH_FABRICATOR_SCREEN_SEARCH if(ls["sync_research"]) update_research() say("Synchronizing research with host technology database.") if(ls["category"]) selected_category = ls["category"] if(ls["dispose"]) //Causes the protolathe to dispose of a single reagent (all of it) reagents.del_reagent(ls["dispose"]) if(ls["disposeall"]) //Causes the protolathe to dispose of all it's reagents. reagents.clear_reagents() if(ls["ejectsheet"]) //Causes the protolathe to eject a sheet of material materials.retrieve_sheets(text2num(ls["eject_amt"]), ls["ejectsheet"]) updateUsrDialog() /obj/machinery/rnd/production/proc/ui_screen_main() var/list/l = list() l += "
\ \ \ \ \ \

" l += list_categories(categories, RESEARCH_FABRICATOR_SCREEN_CATEGORYVIEW) return l /obj/machinery/rnd/production/proc/ui_screen_category_view() if(!selected_category) return ui_screen_main() var/list/l = list() l += "

Browsing [selected_category]:

" var/coeff = efficiency_coeff for(var/v in stored_research.researched_designs) var/datum/design/D = stored_research.researched_designs[v] if(!(selected_category in D.category)|| !(D.build_type & allowed_buildtypes)) continue if(!(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags))) continue l += design_menu_entry(D, coeff) l += "
" return l /obj/machinery/rnd/production/proc/list_categories(list/categories, menu_num) if(!categories) return var/line_length = 1 var/list/l = "" for(var/C in categories) if(line_length > 2) l += "" line_length = 1 l += "" line_length++ l += "
[C]
" return l