/obj/machinery/mecha_part_fabricator icon = 'icons/obj/robotics.dmi' icon_state = "mechfab-idle" name = "Exosuit Fabricator" desc = "A machine used for construction of mechas." density = 1 anchored = 1 use_power = USE_POWER_IDLE idle_power_usage = 20 active_power_usage = 5000 req_access = list(access_robotics) circuit = /obj/item/weapon/circuitboard/mechfab var/speed = 1 var/mat_efficiency = 1 var/list/materials = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0, "plastic" = 0, MAT_GRAPHITE = 0, MAT_PLASTEEL = 0, "gold" = 0, "silver" = 0, MAT_LEAD = 0, "osmium" = 0, "diamond" = 0, MAT_DURASTEEL = 0, "phoron" = 0, "uranium" = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, MAT_SUPERMATTER = 0) var/list/hidden_materials = list(MAT_PLASTEEL, MAT_DURASTEEL, MAT_GRAPHITE, MAT_VERDANTIUM, MAT_MORPHIUM, MAT_METALHYDROGEN, MAT_SUPERMATTER) var/res_max_amount = 200000 var/datum/research/files var/list/datum/design/queue = list() var/progress = 0 var/busy = 0 var/list/categories = list() var/category = null var/sync_message = "" /obj/machinery/mecha_part_fabricator/Initialize() . = ..() // Go through all materials, and add them to the possible storage, but hide them unless we contain them. for(var/Name in name_to_material) if(Name in materials) continue hidden_materials |= Name materials[Name] = 0 default_apply_parts() files = new /datum/research(src) //Setup the research data holder. update_categories() /obj/machinery/mecha_part_fabricator/process() ..() if(stat) return if(busy) update_use_power(USE_POWER_ACTIVE) progress += speed check_build() else update_use_power(USE_POWER_IDLE) update_icon() /obj/machinery/mecha_part_fabricator/update_icon() overlays.Cut() if(panel_open) icon_state = "mechfab-o" else icon_state = "mechfab-idle" if(busy) overlays += "mechfab-active" /obj/machinery/mecha_part_fabricator/dismantle() for(var/f in materials) eject_materials(f, -1) ..() /obj/machinery/mecha_part_fabricator/RefreshParts() res_max_amount = 0 for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) res_max_amount += M.rating * 100000 // 200k -> 600k var/T = 0 for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) T += M.rating mat_efficiency = max(1 - (T - 1) / 4, 0.2) // 1 -> 0.2 for(var/obj/item/weapon/stock_parts/micro_laser/M in component_parts) // Not resetting T is intended; speed is affected by both T += M.rating speed = T / 2 // 1 -> 3 /obj/machinery/mecha_part_fabricator/attack_hand(var/mob/user) if(..()) return if(!allowed(user)) return ui_interact(user) /obj/machinery/mecha_part_fabricator/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] var/datum/design/current = queue.len ? queue[1] : null if(current) data["current"] = current.name data["queue"] = get_queue_names() data["buildable"] = get_build_options() data["category"] = category data["categories"] = categories data["materials"] = get_materials() data["maxres"] = res_max_amount data["sync"] = sync_message if(current) data["builtperc"] = round((progress / current.time) * 100) ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) ui = new(user, src, ui_key, "mechfab.tmpl", "Exosuit Fabricator UI", 800, 600) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) /obj/machinery/mecha_part_fabricator/Topic(href, href_list) if(..()) return if(href_list["build"]) add_to_queue(text2num(href_list["build"])) if(href_list["remove"]) remove_from_queue(text2num(href_list["remove"])) if(href_list["category"]) if(href_list["category"] in categories) category = href_list["category"] if(href_list["eject"]) eject_materials(href_list["eject"], text2num(href_list["amount"])) if(href_list["sync"]) sync() else sync_message = "" return 1 /obj/machinery/mecha_part_fabricator/attackby(var/obj/item/I, var/mob/user) if(busy) to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") return 1 if(default_deconstruction_screwdriver(user, I)) return if(default_deconstruction_crowbar(user, I)) return if(default_part_replacement(user, I)) return if(istype(I,/obj/item/stack/material)) var/obj/item/stack/material/S = I if(!(S.material.name in materials)) to_chat(user, "The [src] doesn't accept [S.material]!") return var/sname = "[S.name]" var/amnt = S.perunit if(materials[S.material.name] + amnt <= res_max_amount) if(S && S.get_amount() >= 1) var/count = 0 overlays += "mechfab-load-metal" spawn(10) overlays -= "mechfab-load-metal" while(materials[S.material.name] + amnt <= res_max_amount && S.get_amount() >= 1) materials[S.material.name] += amnt S.use(1) count++ to_chat(user, "You insert [count] [sname] into the fabricator.") update_busy() else to_chat(user, "The fabricator cannot hold more [sname].") return ..() /obj/machinery/mecha_part_fabricator/emag_act(var/remaining_charges, var/mob/user) switch(emagged) if(0) emagged = 0.5 visible_message("[bicon(src)] [src] beeps: \"DB error \[Code 0x00F1\]\"") sleep(10) visible_message("[bicon(src)] [src] beeps: \"Attempting auto-repair\"") sleep(15) visible_message("[bicon(src)] [src] beeps: \"User DB corrupted \[Code 0x00FA\]. Truncating data structure...\"") sleep(30) visible_message("[bicon(src)] [src] beeps: \"User DB truncated. Please contact your [using_map.company_name] system operator for future assistance.\"") req_access = null emagged = 1 return 1 if(0.5) visible_message("[bicon(src)] [src] beeps: \"DB not responding \[Code 0x0003\]...\"") if(1) visible_message("[bicon(src)] [src] beeps: \"No records in User DB\"") /obj/machinery/mecha_part_fabricator/proc/update_busy() if(queue.len) if(can_build(queue[1])) busy = 1 else busy = 0 else busy = 0 /obj/machinery/mecha_part_fabricator/proc/add_to_queue(var/index) var/datum/design/D = files.known_designs[index] queue += D update_busy() /obj/machinery/mecha_part_fabricator/proc/remove_from_queue(var/index) if(index == 1) progress = 0 queue.Cut(index, index + 1) update_busy() /obj/machinery/mecha_part_fabricator/proc/can_build(var/datum/design/D) for(var/M in D.materials) if(materials[M] < (D.materials[M] * mat_efficiency)) return 0 return 1 /obj/machinery/mecha_part_fabricator/proc/check_build() if(!queue.len) progress = 0 return var/datum/design/D = queue[1] if(!can_build(D)) progress = 0 return if(D.time > progress) return for(var/M in D.materials) materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency) if(D.build_path) var/obj/new_item = D.Fabricate(get_step(get_turf(src), src.dir), src) visible_message("\The [src] pings, indicating that \the [D] is complete.", "You hear a ping.") if(mat_efficiency != 1) if(new_item.matter && new_item.matter.len > 0) for(var/i in new_item.matter) new_item.matter[i] = new_item.matter[i] * mat_efficiency remove_from_queue(1) /obj/machinery/mecha_part_fabricator/proc/get_queue_names() . = list() for(var/i = 2 to queue.len) var/datum/design/D = queue[i] . += D.name /obj/machinery/mecha_part_fabricator/proc/get_build_options() . = list() for(var/i = 1 to files.known_designs.len) var/datum/design/D = files.known_designs[i] if(!D.build_path || !(D.build_type & MECHFAB)) continue . += list(list("name" = D.name, "id" = i, "category" = D.category, "resourses" = get_design_resourses(D), "time" = get_design_time(D))) /obj/machinery/mecha_part_fabricator/proc/get_design_resourses(var/datum/design/D) var/list/F = list() for(var/T in D.materials) F += "[capitalize(T)]: [D.materials[T] * mat_efficiency]" return english_list(F, and_text = ", ") /obj/machinery/mecha_part_fabricator/proc/get_design_time(var/datum/design/D) return time2text(round(10 * D.time / speed), "mm:ss") /obj/machinery/mecha_part_fabricator/proc/update_categories() categories = list() for(var/datum/design/D in files.known_designs) if(!D.build_path || !(D.build_type & MECHFAB)) continue categories |= D.category if(!category || !(category in categories)) category = categories[1] /obj/machinery/mecha_part_fabricator/proc/get_materials() . = list() for(var/T in materials) var/hidden_mat = FALSE for(var/HM in hidden_materials) // Direct list contents comparison was failing. if(T == HM && materials[T] == 0) hidden_mat = TRUE continue if(!hidden_mat) . += list(list("mat" = capitalize(T), "amt" = materials[T])) /obj/machinery/mecha_part_fabricator/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything var/recursive = amount == -1 ? 1 : 0 var/matstring = lowertext(material) var/datum/material/M = get_material_by_name(matstring) var/obj/item/stack/material/S = M.place_sheet(get_turf(src)) if(amount <= 0) amount = S.max_amount var/ejected = min(round(materials[matstring] / S.perunit), amount) S.amount = min(ejected, amount) if(S.amount <= 0) qdel(S) return materials[matstring] -= ejected * S.perunit if(recursive && materials[matstring] >= S.perunit) eject_materials(matstring, -1) update_busy() /obj/machinery/mecha_part_fabricator/proc/sync() sync_message = "Error: no console found." for(var/obj/machinery/computer/rdconsole/RDC in get_area_all_atoms(get_area(src))) if(!RDC.sync) continue for(var/datum/tech/T in RDC.files.known_tech) files.AddTech2Known(T) for(var/datum/design/D in RDC.files.known_designs) files.AddDesign2Known(D) files.RefreshResearch() sync_message = "Sync complete." update_categories()