From a24d6f5adb160d28b15121c9fd66498548e22faf Mon Sep 17 00:00:00 2001 From: Timberpoes Date: Sat, 18 Jul 2020 17:09:24 +0100 Subject: [PATCH] Exosuit Fabricator tgui Total Conversion - An Ode to Roboticists (#52073) * First draft * tgui interface bluescreen guards * Preparing for cyborg module sub-categories * The rest of the owl * Stop duplicate say messgaes * Implement interface handling for obstructed exits * Pocket lint * Documentation and misc. code cleanup * Implement searching in interface * tgui pocket lint and build * Coding style consistency and changes. Rebuild tgui. * Update default bitflags * Address potential edge case bluescreen. * orange man good * Remove emag_act with obsolete functionality * Standardise variable naming conventions * tgui 4.0 update * tgui 4.0 update * Port a couple of usability improvements from concept branch. * Fix new ui_act input. * Actually fix new ui_act input * Port some small improvements from concept branch. * Rebuild tgui * Made department of redundancy department redundant. * Rebuild tgui. --- code/__DEFINES/exosuit_fab.dm | 32 + code/game/mecha/equipment/mecha_equipment.dm | 2 + .../mecha/equipment/tools/medical_tools.dm | 1 + .../mecha/equipment/tools/mining_tools.dm | 10 +- code/game/mecha/equipment/tools/work_tools.dm | 3 + code/game/mecha/equipment/weapons/weapons.dm | 11 +- code/game/mecha/mech_fabricator.dm | 773 +++++++++++------ .../objects/items/robot/robot_upgrades.dm | 16 + code/modules/asset_cache/asset_list_items.dm | 12 +- .../guns/energy/kinetic_accelerator.dm | 1 + code/modules/research/designs.dm | 2 + .../modules/research/designs/mecha_designs.dm | 12 +- .../designs/mechfabricator_designs.dm | 29 +- .../research/designs/medical_designs.dm | 46 +- tgstation.dme | 1 + .../tgui/interfaces/ExosuitFabricator.js | 796 ++++++++++++++++++ tgui/packages/tgui/public/tgui.bundle.js | 2 +- 17 files changed, 1425 insertions(+), 324 deletions(-) create mode 100644 code/__DEFINES/exosuit_fab.dm create mode 100644 tgui/packages/tgui/interfaces/ExosuitFabricator.js diff --git a/code/__DEFINES/exosuit_fab.dm b/code/__DEFINES/exosuit_fab.dm new file mode 100644 index 00000000000..a237d5b0fb1 --- /dev/null +++ b/code/__DEFINES/exosuit_fab.dm @@ -0,0 +1,32 @@ +/// Module is compatible with Security Cyborg models +#define BORG_MODULE_SECURITY (1<<0) +/// Module is compatible with Miner Cyborg models +#define BORG_MODULE_MINER (1<<1) +/// Module is compatible with Janitor Cyborg models +#define BORG_MODULE_JANITOR (1<<2) +/// Module is compatible with Medical Cyborg models +#define BORG_MODULE_MEDICAL (1<<3) +/// Module is compatible with Engineering Cyborg models +#define BORG_MODULE_ENGINEERING (1<<4) + +/// Module is compatible with Ripley Exosuit models +#define EXOSUIT_MODULE_RIPLEY (1<<0) +/// Module is compatible with Odyseeus Exosuit models +#define EXOSUIT_MODULE_ODYSSEUS (1<<1) +/// Module is compatible with Clarke Exosuit models +#define EXOSUIT_MODULE_CLARKE (1<<2) +/// Module is compatible with Gygax Exosuit models +#define EXOSUIT_MODULE_GYGAX (1<<3) +/// Module is compatible with Durand Exosuit models +#define EXOSUIT_MODULE_DURAND (1<<4) +/// Module is compatible with H.O.N.K Exosuit models +#define EXOSUIT_MODULE_HONK (1<<5) +/// Module is compatible with Phazon Exosuit models +#define EXOSUIT_MODULE_PHAZON (1<<6) + +/// Module is compatible with "Working" Exosuit models - Ripley and Clarke +#define EXOSUIT_MODULE_WORKING EXOSUIT_MODULE_RIPLEY | EXOSUIT_MODULE_CLARKE +/// Module is compatible with "Combat" Exosuit models - Gygax, H.O.N.K, Durand and Phazon +#define EXOSUIT_MODULE_COMBAT EXOSUIT_MODULE_GYGAX | EXOSUIT_MODULE_HONK | EXOSUIT_MODULE_DURAND | EXOSUIT_MODULE_PHAZON +/// Module is compatible with "Medical" Exosuit modelsm - Odysseus +#define EXOSUIT_MODULE_MEDICAL EXOSUIT_MODULE_ODYSSEUS diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index e9e3b335ffc..67df4e24b6d 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -13,6 +13,8 @@ var/obj/mecha/chassis = null ///Bitflag. Determines the range of the equipment. var/range = MECHA_MELEE + /// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this. + var/mech_flags = NONE var/salvageable = 1 var/detachable = TRUE // Set to FALSE for built-in equipment that cannot be removed var/selectable = 1 // Set to 0 for passive equipment such as mining scanner or armor plates diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index a96e1fa8c92..d1ba0ebf129 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -1,6 +1,7 @@ // Sleeper, Medical Beam, and Syringe gun /obj/item/mecha_parts/mecha_equipment/medical + mech_flags = EXOSUIT_MODULE_MEDICAL /obj/item/mecha_parts/mecha_equipment/medical/Initialize() . = ..() diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm index d445248b83f..274ccbbc9b8 100644 --- a/code/game/mecha/equipment/tools/mining_tools.dm +++ b/code/game/mecha/equipment/tools/mining_tools.dm @@ -17,6 +17,7 @@ toolspeed = 0.9 var/drill_delay = 7 var/drill_level = DRILL_BASIC + mech_flags = EXOSUIT_MODULE_WORKING | EXOSUIT_MODULE_COMBAT /obj/item/mecha_parts/mecha_equipment/drill/Initialize() . = ..() @@ -148,16 +149,23 @@ /obj/item/mecha_parts/mecha_equipment/mining_scanner name = "exosuit mining scanner" - desc = "Equipment for engineering and combat exosuits. It will automatically check surrounding rock for useful minerals." + desc = "Equipment for working exosuits. It will automatically check surrounding rock for useful minerals." icon_state = "mecha_analyzer" selectable = 0 equip_cooldown = 15 var/scanning_time = 0 + mech_flags = EXOSUIT_MODULE_WORKING /obj/item/mecha_parts/mecha_equipment/mining_scanner/Initialize() . = ..() START_PROCESSING(SSfastprocess, src) +/obj/item/mecha_parts/mecha_equipment/mining_scanner/can_attach(obj/mecha/M as obj) + if(..()) + if(istype(M, /obj/mecha/working)) + return TRUE + return FALSE + /obj/item/mecha_parts/mecha_equipment/mining_scanner/process() if(!loc) STOP_PROCESSING(SSfastprocess, src) diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm index 45f880d7659..9f028a65f80 100644 --- a/code/game/mecha/equipment/tools/work_tools.dm +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -13,6 +13,7 @@ var/dam_force = 20 var/obj/mecha/working/ripley/cargo_holder harmful = TRUE + mech_flags = EXOSUIT_MODULE_RIPLEY /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M as obj) if(..()) @@ -189,6 +190,7 @@ equip_cooldown = 5 energy_drain = 0 range = MECHA_MELEE|MECHA_RANGED + mech_flags = EXOSUIT_MODULE_WORKING /obj/item/mecha_parts/mecha_equipment/extinguisher/Initialize() . = ..() @@ -353,6 +355,7 @@ name = "Ripley MK-II Conversion Kit" desc = "A pressurized canopy attachment kit for an Autonomous Power Loader Unit \"Ripley\" MK-I mecha, to convert it to the slower, but space-worthy MK-II design. This kit cannot be removed, once applied." icon_state = "ripleyupgrade" + mech_flags = EXOSUIT_MODULE_RIPLEY /obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/mecha/working/ripley/M) if(M.type != /obj/mecha/working/ripley) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index af0bea78834..92fb564efcc 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -10,6 +10,7 @@ var/projectile_delay = 0 var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect //the visual effect appearing when the weapon is fired. var/kickback = TRUE //Will using this weapon in no grav push mecha back. + mech_flags = EXOSUIT_MODULE_COMBAT /obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/mecha/M) if(!..()) @@ -144,7 +145,7 @@ fire_sound = 'sound/weapons/plasma_cutter.ogg' harmful = TRUE -/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/working/M) +/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/M) if(..()) //combat mech return 1 else if(M.equipment.len < M.max_equip && istype(M)) @@ -169,6 +170,7 @@ equip_cooldown = 150 range = MECHA_MELEE|MECHA_RANGED kickback = FALSE + mech_flags = EXOSUIT_MODULE_HONK /obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/mecha/combat/honker/M) if(..()) @@ -422,6 +424,7 @@ missile_speed = 1.5 projectile_energy_cost = 100 equip_cooldown = 20 + mech_flags = EXOSUIT_MODULE_HONK /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/mecha/combat/honker/M) if(..()) @@ -439,6 +442,7 @@ missile_speed = 1.5 projectile_energy_cost = 100 equip_cooldown = 10 + mech_flags = EXOSUIT_MODULE_HONK /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/mecha/combat/honker/M) if(..()) @@ -466,9 +470,10 @@ harmful = TRUE diags_first = TRUE /// Damage done by the glove on contact. Also used to determine throw distance (damage / 5) - var/punch_damage = 35 + var/punch_damage = 35 /// TRUE - Can toggle between lethal and non-lethal || FALSE - Cannot toggle - var/can_toggle_lethal = TRUE + var/can_toggle_lethal = TRUE + mech_flags = EXOSUIT_MODULE_HONK /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/mecha/combat/honker/M) if(..()) diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index d45ee34a82c..5fc3c19b255 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -9,18 +9,41 @@ active_power_usage = 5000 req_access = list(ACCESS_ROBOTICS) circuit = /obj/item/circuitboard/machine/mechfab - var/time_coeff = 1 - var/component_coeff = 1 - var/datum/techweb/specialized/autounlocking/exofab/stored_research - var/sync = 0 - var/part_set - var/datum/design/being_built + processing_flags = START_PROCESSING_MANUALLY + + subsystem_type = /datum/controller/subsystem/processing/fastprocess + + /// Current items in the build queue. var/list/queue = list() - var/processing_queue = 0 - var/screen = "main" + /// Whether or not the machine is building the entire queue automagically. + var/process_queue = FALSE + + /// The current design datum that the machine is building. + var/datum/design/being_built + /// World time when the build will finish. + var/build_finish = 0 + /// World time when the build started. + var/build_start = 0 + /// Reference to all materials used in the creation of the item being_built. + var/list/build_materials + /// Part currently stored in the Exofab. + var/obj/item/stored_part + + /// Coefficient for the speed of item building. Based on the installed parts. + var/time_coeff = 1 + /// Coefficient for the efficiency of material usage in item building. Based on the installed parts. + var/component_coeff = 1 + + /// Copy of the currently synced techweb. + var/datum/techweb/specialized/autounlocking/exofab/stored_research + + /// Whether the Exofab links to the ore silo on init. Special derelict or maintanance variants should set this to FALSE. var/link_on_init = TRUE - var/temp + + /// Reference to a remote material inventory, such as an ore silo. var/datum/component/remote_materials/rmat + + /// A list of categories that valid MECHFAB design datums will broadly categorise themselves under. var/list/part_sets = list( "Cyborg", "Ripley", @@ -33,6 +56,9 @@ "Exosuit Equipment", "Exosuit Ammunition", "Cyborg Upgrade Modules", + "Cybernetics", + "Implants", + "Control Interfaces", "Misc" ) @@ -62,70 +88,152 @@ T += Ml.rating time_coeff = round(initial(time_coeff) - (initial(time_coeff)*(T))/5,0.01) + // Adjust the build time of any item currently being built. + if(being_built) + var/last_const_time = build_finish - build_start + var/new_const_time = get_construction_time_w_coeff(initial(being_built.construction_time)) + var/const_time_left = build_finish - world.time + var/new_build_time = (new_const_time / last_const_time) * const_time_left + build_finish = world.time + new_build_time + + update_static_data(usr) + /obj/machinery/mecha_part_fabricator/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) . += "The status display reads: Storing up to [rmat.local_size] material units.
Material consumption at [component_coeff*100]%.
Build time reduced by [100-time_coeff*100]%.
" -/obj/machinery/mecha_part_fabricator/emag_act() - if(obj_flags & EMAGGED) - return - obj_flags |= EMAGGED - req_access = list() - say("DB error \[Code 0x00F1\]") - sleep(10) - say("Attempting auto-repair...") - sleep(15) - say("User DB corrupted \[Code 0x00FA\]. Truncating data structure...") - sleep(30) - say("User DB truncated. Please contact your Nanotrasen system operator for future assistance.") - -/obj/machinery/mecha_part_fabricator/proc/output_parts_list(set_name) - var/output = "" - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(!(set_name in D.category)) - continue - output += "
[output_part_info(D)]
\[" - if(check_resources(D)) - output += "Build | " - output += "Add to queue\]\[?\]
" - return output - -/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D) - var/output = "[initial(D.name)] (Cost: [output_part_cost(D)]) [get_construction_time_w_coeff(D)/10]sec" - return output - -/obj/machinery/mecha_part_fabricator/proc/output_part_cost(datum/design/D) - var/i = 0 - var/output +/** + * Generates an info list for a given part. + * + * Returns a list of part information. + * * D - Design datum to get information on. + * * categories - Boolean, whether or not to parse snowflake categories into the part information list. + */ +/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D, var/categories = FALSE) + var/cost = list() for(var/c in D.materials) var/datum/material/M = c - output += "[i?" | ":null][get_resource_cost_w_coeff(D, M)] [M.name]" - i++ - return output + cost[M.name] = get_resource_cost_w_coeff(D, M) + var/obj/built_item = D.build_path + + var/list/category_override = null + var/list/sub_category = null + + if(categories) + // Handle some special cases to build up sub-categories for the fab interface. + // Start with checking if this design builds a cyborg module. + if(built_item in typesof(/obj/item/borg/upgrade)) + var/obj/item/borg/upgrade/U = built_item + var/module_types = initial(U.module_flags) + sub_category = list() + if(module_types) + if(module_types & BORG_MODULE_SECURITY) + sub_category += "Security" + if(module_types & BORG_MODULE_MINER) + sub_category += "Mining" + if(module_types & BORG_MODULE_JANITOR) + sub_category += "Janitor" + if(module_types & BORG_MODULE_MEDICAL) + sub_category += "Medical" + if(module_types & BORG_MODULE_ENGINEERING) + sub_category += "Engineering" + else + sub_category += "All Cyborgs" + // Else check if this design builds a piece of exosuit equipment. + else if(built_item in typesof(/obj/item/mecha_parts/mecha_equipment)) + var/obj/item/mecha_parts/mecha_equipment/E = built_item + var/mech_types = initial(E.mech_flags) + sub_category = "Equipment" + if(mech_types) + category_override = list() + if(mech_types & EXOSUIT_MODULE_RIPLEY) + category_override += "Ripley" + if(mech_types & EXOSUIT_MODULE_ODYSSEUS) + category_override += "Odysseus" + if(mech_types & EXOSUIT_MODULE_CLARKE) + category_override += "Clarke" + if(mech_types & EXOSUIT_MODULE_GYGAX) + category_override += "Gygax" + if(mech_types & EXOSUIT_MODULE_DURAND) + category_override += "Durand" + if(mech_types & EXOSUIT_MODULE_HONK) + category_override += "H.O.N.K" + if(mech_types & EXOSUIT_MODULE_PHAZON) + category_override += "Phazon" + + + var/list/part = list( + "name" = D.name, + "desc" = initial(built_item.desc), + "printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10, + "cost" = cost, + "id" = D.id, + "subCategory" = sub_category, + "categoryOverride" = category_override, + "searchMeta" = D.search_metadata + ) + + return part + +/** + * Generates a list of resources / materials available to this Exosuit Fab + * + * Returns null if there is no material container available. + * List format is list(material_name = list(amount = ..., ref = ..., etc.)) + */ /obj/machinery/mecha_part_fabricator/proc/output_available_resources() - var/output var/datum/component/material_container/materials = rmat.mat_container + var/list/material_data = list() + if(materials) for(var/mat_id in materials.materials) var/datum/material/M = mat_id + var/list/material_info = list() var/amount = materials.materials[mat_id] - var/ref = REF(M) - output += "[M.name]: [amount] cm³" - if(amount >= MINERAL_MATERIAL_AMOUNT) - output += "- Remove \[1\]" - if(amount >= (MINERAL_MATERIAL_AMOUNT * 10)) - output += " | \[10\]" - output += " | \[50\]" - output += "
" - else - output += "No material storage connected, please contact the quartermaster.
" - return output + material_info = list( + "name" = M.name, + "ref" = REF(M), + "amount" = amount, + "sheets" = round(amount / MINERAL_MATERIAL_AMOUNT), + "removable" = amount >= MINERAL_MATERIAL_AMOUNT + ) + + material_data += list(material_info) + + return material_data + + return null + +/** + * Intended to be called when an item starts printing. + * + * Adds the overlay to show the fab working and sets active power usage settings. + */ +/obj/machinery/mecha_part_fabricator/proc/on_start_printing() + add_overlay("fab-active") + use_power = ACTIVE_POWER_USE + +/** + * Intended to be called when the exofab has stopped working and is no longer printing items. + * + * Removes the overlay to show the fab working and sets idle power usage settings. Additionally resets the description and turns off queue processing. + */ +/obj/machinery/mecha_part_fabricator/proc/on_finish_printing() + cut_overlay("fab-active") + use_power = IDLE_POWER_USE + desc = initial(desc) + process_queue = FALSE + +/** + * Calculates resource/material costs for printing an item based on the machine's resource coefficient. + * + * Returns a list of k,v resources with their amounts. + * * D - Design datum to calculate the modified resource cost of. + */ /obj/machinery/mecha_part_fabricator/proc/get_resources_w_coeff(datum/design/D) var/list/resources = list() for(var/R in D.materials) @@ -133,272 +241,382 @@ resources[M] = get_resource_cost_w_coeff(D, M) return resources +/** + * Checks if the Exofab has enough resources to print a given item. + * + * Returns FALSE if the design has no reagents used in its construction (?) or if there are insufficient resources. + * Returns TRUE if there are sufficient resources to print the item. + * * D - Design datum to calculate the modified resource cost of. + */ /obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D) - if(D.reagents_list.len) // No reagents storage - no reagent designs. + if(length(D.reagents_list)) // No reagents storage - no reagent designs. return FALSE var/datum/component/material_container/materials = rmat.mat_container if(materials.has_materials(get_resources_w_coeff(D))) return TRUE return FALSE -/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D) - var/list/res_coef = get_resources_w_coeff(D) +/** + * Attempts to build the next item in the build queue. + * + * Returns FALSE if either there are no more parts to build or the next part is not buildable. + * Returns TRUE if the next part has started building. + * * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build. + */ +/obj/machinery/mecha_part_fabricator/proc/build_next_in_queue(verbose = TRUE) + if(!length(queue)) + return FALSE + + var/datum/design/D = queue[1] + if(build_part(D, verbose)) + remove_from_queue(1) + return TRUE + + return FALSE + +/** + * Starts the build process for a given design datum. + * + * Returns FALSE if the procedure fails. Returns TRUE when being_built is set. + * Uses materials. + * * D - Design datum to attempt to print. + * * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build. + */ +/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D, verbose = TRUE) + if(!D) + return FALSE var/datum/component/material_container/materials = rmat.mat_container if (!materials) - say("No access to material storage, please contact the quartermaster.") + if(verbose) + say("No access to material storage, please contact the quartermaster.") return FALSE if (rmat.on_hold()) - say("Mineral access is on hold, please contact the quartermaster.") + if(verbose) + say("Mineral access is on hold, please contact the quartermaster.") return FALSE if(!check_resources(D)) - say("Not enough resources. Queue processing stopped.") + if(verbose) + say("Not enough resources. Processing stopped.") return FALSE + + build_materials = get_resources_w_coeff(D) + + materials.use_materials(build_materials) being_built = D - desc = "It's building \a [initial(D.name)]." - materials.use_materials(res_coef) - rmat.silo_log(src, "built", -1, "[D.name]", res_coef) + build_finish = world.time + get_construction_time_w_coeff(initial(D.construction_time)) + build_start = world.time + desc = "It's building \a [D.name]." - add_overlay("fab-active") - use_power = ACTIVE_POWER_USE - updateUsrDialog() - sleep(get_construction_time_w_coeff(D)) - use_power = IDLE_POWER_USE - cut_overlay("fab-active") - desc = initial(desc) + rmat.silo_log(src, "built", -1, "[D.name]", build_materials) - var/location = get_step(src,(dir)) - var/obj/item/I = new D.build_path(location) - I.material_flags |= MATERIAL_NO_EFFECTS //Find a better way to do this. - I.set_custom_materials(res_coef) - say("\The [I] is complete.") - being_built = null - - updateUsrDialog() return TRUE -/obj/machinery/mecha_part_fabricator/proc/update_queue_on_page() - send_byjax(usr,"mecha_fabricator.browser","queue",list_queue()) - return +/obj/machinery/mecha_part_fabricator/process() + // If there's a stored part to dispense due to an obstruction, try to dispense it. + if(stored_part) + var/turf/exit = get_step(src,(dir)) + if(exit.density) + return TRUE -/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(set_name) - if(set_name in part_sets) - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(set_name in D.category) - add_to_queue(D) + say("Obstruction cleared. \The [stored_part] is complete.") + stored_part.forceMove(exit) + stored_part = null -/obj/machinery/mecha_part_fabricator/proc/add_to_queue(D) + // If there's nothing being built, try to build something + if(!being_built) + // If we're not processing the queue anymore or there's nothing to build, end processing. + if(!process_queue || !build_next_in_queue()) + on_finish_printing() + end_processing() + return TRUE + on_start_printing() + + // If there's an item being built, check if it is complete. + if(being_built && (build_finish < world.time)) + // Then attempt to dispense it and if appropriate build the next item. + dispense_built_part(being_built) + if(process_queue) + build_next_in_queue(FALSE) + return TRUE + +/** + * Dispenses a part to the tile infront of the Exosuit Fab. + * + * Returns FALSE is the machine cannot dispense the part on the appropriate turf. + * Return TRUE if the part was successfully dispensed. + * * D - Design datum to attempt to dispense. + */ +/obj/machinery/mecha_part_fabricator/proc/dispense_built_part(datum/design/D) + var/obj/item/I = new D.build_path(src) + I.material_flags |= MATERIAL_NO_EFFECTS //Find a better way to do this. + I.set_custom_materials(build_materials) + + being_built = null + + var/turf/exit = get_step(src,(dir)) + if(exit.density) + say("Error! Part outlet is obstructed.") + desc = "It's trying to dispense \a [D.name], but the part outlet is obstructed." + stored_part = I + return FALSE + + say("\The [I] is complete.") + I.forceMove(exit) + return TRUE + +/** + * Adds a list of datum designs to the build queue. + * + * Will only add designs that are in this machine's stored techweb. + * Does final checks for datum IDs and makes sure this machine can build the designs. + * * part_list - List of datum design ids for designs to add to the queue. + */ +/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(list/part_list) + for(var/v in stored_research.researched_designs) + var/datum/design/D = SSresearch.techweb_design_by_id(v) + if((D.build_type & MECHFAB) && (D.id in part_list)) + add_to_queue(D) + +/** + * Adds a datum design to the build queue. + * + * Returns TRUE if successful and FALSE if the design was not added to the queue. + * * D - Datum design to add to the queue. + */ +/obj/machinery/mecha_part_fabricator/proc/add_to_queue(datum/design/D) if(!istype(queue)) queue = list() if(D) queue[++queue.len] = D - return queue.len + return TRUE + return FALSE +/** + * Removes datum design from the build queue based on index. + * + * Returns TRUE if successful and FALSE if a design was not removed from the queue. + * * index - Index in the build queue of the element to remove. + */ /obj/machinery/mecha_part_fabricator/proc/remove_from_queue(index) - if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>queue.len)) + if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>length(queue))) return FALSE queue.Cut(index,++index) return TRUE -/obj/machinery/mecha_part_fabricator/proc/process_queue() - var/datum/design/D = queue[1] - if(!D) - remove_from_queue(1) - if(queue.len) - return process_queue() - else - return - temp = null - while(D) - if(machine_stat&(NOPOWER|BROKEN)) - return FALSE - if(build_part(D)) - remove_from_queue(1) - else - return FALSE - D = LAZYACCESS(queue, 1) - say("Queue processing finished successfully.") - +/** + * Generates a list of parts formatted for tgui based on the current build queue. + * + * Returns a formatted list of lists containing formatted part information for every part in the build queue. + */ /obj/machinery/mecha_part_fabricator/proc/list_queue() - var/output = "Queue contains:" - if(!istype(queue) || !queue.len) - output += "
Nothing" - else - output += "
    " - var/i = 0 - for(var/datum/design/D in queue) - i++ - var/obj/part = D.build_path - output += "" - output += initial(part.name) + " - " - output += "[i>1?"":null] " - output += "[i↓":null] " - output += "Remove" + if(!istype(queue) || !length(queue)) + return null - output += "
" - output += "\[Process queue | Clear queue\]" - return output + var/list/queued_parts = list() + for(var/datum/design/D in queue) + var/list/part = output_part_info(D) + queued_parts += list(part) + return queued_parts +/** + * Syncs machine with R&D servers. + * + * Requires an R&D Console visible within 7 tiles. Copies techweb research. Updates tgui's state data. + */ /obj/machinery/mecha_part_fabricator/proc/sync() - for(var/obj/machinery/computer/rdconsole/RDC in oview(7,src)) + for(var/obj/machinery/computer/rdconsole/RDC in orange(7,src)) RDC.stored_research.copy_research_to(stored_research) - updateUsrDialog() + update_static_data(usr) say("Successfully synchronized with R&D server.") return - temp = "Unable to connect to local R&D Database.
Please check your connections and try again.
Return" - updateUsrDialog() + say("Unable to connect to local R&D server.") return +/** + * Calculates the coefficient-modified resource cost of a single material component of a design's recipe. + * + * Returns coefficient-modified resource cost for the given material component. + * * D - Design datum to pull the resource cost from. + * * resource - Material datum reference to the resource to calculate the cost of. + * * roundto - Rounding value for round() proc + */ /obj/machinery/mecha_part_fabricator/proc/get_resource_cost_w_coeff(datum/design/D, var/datum/material/resource, roundto = 1) return round(D.materials[resource]*component_coeff, roundto) -/obj/machinery/mecha_part_fabricator/proc/get_construction_time_w_coeff(datum/design/D, roundto = 1) //aran - return round(initial(D.construction_time)*time_coeff, roundto) +/** + * Calculates the coefficient-modified build time of a design. + * + * Returns coefficient-modified build time of a given design. + * * D - Design datum to calculate the modified build time of. + * * roundto - Rounding value for round() proc + */ +/obj/machinery/mecha_part_fabricator/proc/get_construction_time_w_coeff(construction_time, roundto = 1) //aran + return round(construction_time*time_coeff, roundto) -/obj/machinery/mecha_part_fabricator/ui_interact(mob/user) - . = ..() - var/dat, left_part - user.set_machine(src) - var/turf/exit = get_step(src,(dir)) - if(exit.density) - say("Error! Part outlet is obstructed.") - return - if(temp) - left_part = temp - else if(being_built) - var/obj/I = being_built.build_path - left_part = {"Building [initial(I.name)].
- Please wait until completion...
"} +/obj/machinery/mecha_part_fabricator/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/sheetmaterials) + ) + +/obj/machinery/mecha_part_fabricator/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ExosuitFabricator") + ui.open() + +/obj/machinery/mecha_part_fabricator/ui_static_data(mob/user) + var/list/data = list() + + var/list/final_sets = list() + var/list/buildable_parts = list() + + for(var/part_set in part_sets) + final_sets += part_set + + for(var/v in stored_research.researched_designs) + var/datum/design/D = SSresearch.techweb_design_by_id(v) + if(D.build_type & MECHFAB) + // This is for us. + var/list/part = output_part_info(D, TRUE) + + if(part["category_override"]) + for(var/cat in part["category_override"]) + buildable_parts[cat] += list(part) + if(!(cat in part_sets)) + final_sets += cat + continue + + for(var/cat in part_sets) + // Find all matching categories. + if(!(cat in D.category)) + continue + + buildable_parts[cat] += list(part) + + data["partSets"] = final_sets + data["buildableParts"] = buildable_parts + + return data + +/obj/machinery/mecha_part_fabricator/ui_data(mob/user) + var/list/data = list() + + data["materials"] = output_available_resources() + + if(being_built) + var/list/part = list( + "name" = being_built.name, + "duration" = build_finish - world.time, + "printTime" = get_construction_time_w_coeff(initial(being_built.construction_time)) + ) + data["buildingPart"] = part else - switch(screen) - if("main") - left_part = output_available_resources()+"
" - left_part += "Sync with R&D servers
" - for(var/part_set in part_sets) - left_part += "[part_set] - \[Add all parts to queue\]
" - if("parts") - left_part += output_parts_list(part_set) - left_part += "
Return" - dat = {" - - - [name] - - - - - - - - - -
- [left_part] - - [list_queue()] -
- - "} - user << browse(dat, "window=mecha_fabricator;size=1000x430") - onclose(user, "mecha_fabricator") - return + data["buildingPart"] = null -/obj/machinery/mecha_part_fabricator/Topic(href, href_list) + data["queue"] = list_queue() + + if(stored_part) + data["storedPart"] = stored_part.name + else + data["storedPart"] = null + + data["isProcessingQueue"] = process_queue + + return data + +/obj/machinery/mecha_part_fabricator/ui_act(action, var/list/params) if(..()) - return - if(href_list["part_set"]) - var/tpart_set = href_list["part_set"] - if(tpart_set) - if(tpart_set=="clear") - part_set = null - else - part_set = tpart_set - screen = "parts" - if(href_list["part"]) - var/T = href_list["part"] - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(D.id == T) - if(!processing_queue) - build_part(D) - else - add_to_queue(D) - break - if(href_list["add_to_queue"]) - var/T = href_list["add_to_queue"] - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(D.id == T) + return TRUE + + . = TRUE + + add_fingerprint(usr) + usr.set_machine(src) + + switch(action) + if("sync_rnd") + // Sync with R&D Servers + sync() + return + if("add_queue_set") + // Add all parts of a set to queue + var/part_list = params["part_list"] + add_part_set_to_queue(part_list) + return + if("add_queue_part") + // Add a specific part to queue + var/T = params["id"] + for(var/v in stored_research.researched_designs) + var/datum/design/D = SSresearch.techweb_design_by_id(v) + if((D.build_type & MECHFAB) && (D.id == T)) add_to_queue(D) break - return update_queue_on_page() - if(href_list["remove_from_queue"]) - remove_from_queue(text2num(href_list["remove_from_queue"])) - return update_queue_on_page() - if(href_list["partset_to_queue"]) - add_part_set_to_queue(href_list["partset_to_queue"]) - return update_queue_on_page() - if(href_list["process_queue"]) - INVOKE_ASYNC(src, .proc/do_process_queue) - if(href_list["clear_temp"]) - temp = null - if(href_list["screen"]) - screen = href_list["screen"] - if(href_list["queue_move"] && href_list["index"]) - var/index = text2num(href_list["index"]) - var/new_index = index + text2num(href_list["queue_move"]) - if(isnum(index) && isnum(new_index) && ISINTEGER(index) && ISINTEGER(new_index)) - if(ISINRANGE(new_index,1,queue.len)) - queue.Swap(index,new_index) - return update_queue_on_page() - if(href_list["clear_queue"]) - queue = list() - return update_queue_on_page() - if(href_list["sync"]) - sync() - if(href_list["part_desc"]) - var/T = href_list["part_desc"] - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(D.build_type & MECHFAB) - if(D.id == T) - var/obj/part = D.build_path - temp = {"

[initial(part.name)] description:

- [initial(part.desc)]
- Return - "} - break + return + if("del_queue_part") + // Delete a specific from from the queue + var/index = text2num(params["index"]) + remove_from_queue(index) + return + if("clear_queue") + // Delete everything from queue + queue.Cut() + return + if("build_queue") + // Build everything in queue + if(process_queue) + return + process_queue = TRUE - if(href_list["remove_mat"] && href_list["material"]) - var/datum/material/Mat = locate(href_list["material"]) - eject_sheets(Mat, text2num(href_list["remove_mat"])) + if(!being_built) + begin_processing() + return + if("stop_queue") + // Pause queue building. Also known as stop. + process_queue = FALSE + return + if("build_part") + // Build a single part + if(being_built || process_queue) + return - updateUsrDialog() - return + var/id = params["id"] + var/datum/design/D = SSresearch.techweb_design_by_id(id) -/obj/machinery/mecha_part_fabricator/proc/do_process_queue() - if(processing_queue || being_built) - return FALSE - processing_queue = 1 - process_queue() - processing_queue = 0 + if(!(D.build_type & MECHFAB) || !(D.id == id)) + return + if(build_part(D)) + on_start_printing() + begin_processing() + + return + if("move_queue_part") + // Moves a part up or down in the queue. + var/index = text2num(params["index"]) + var/new_index = index + text2num(params["newindex"]) + if(isnum(index) && isnum(new_index) && ISINTEGER(index) && ISINTEGER(new_index)) + if(ISINRANGE(new_index,1,length(queue))) + queue.Swap(index,new_index) + return + if("remove_mat") + // Remove a material from the fab + var/mat_ref = params["ref"] + var/amount = text2num(params["amount"]) + var/datum/material/mat = locate(mat_ref) + eject_sheets(mat, amount) + return + + return FALSE + +/** + * Eject material sheets. + * + * Returns the number of sheets successfully ejected. + * eject_sheet - Byond REF of the material to eject. + * eject_amt - Number of sheets to attempt to eject. + */ /obj/machinery/mecha_part_fabricator/proc/eject_sheets(eject_sheet, eject_amt) var/datum/component/material_container/mat_container = rmat.mat_container if (!mat_container) @@ -417,17 +635,22 @@ var/datum/material/M = id_inserted add_overlay("fab-load-[M.name]") addtimer(CALLBACK(src, /atom/proc/cut_overlay, "fab-load-[M.name]"), 10) - updateUsrDialog() -/obj/machinery/mecha_part_fabricator/attackby(obj/item/W, mob/user, params) - if(default_deconstruction_screwdriver(user, "fab-o", "fab-idle", W)) +/obj/machinery/mecha_part_fabricator/screwdriver_act(mob/living/user, obj/item/I) + if(..()) return TRUE + if(being_built) + to_chat(user, "\The [src] is currently processing! Please wait until completion.") + return FALSE + return default_deconstruction_screwdriver(user, "fab-o", "fab-idle", I) - if(default_deconstruction_crowbar(W)) +/obj/machinery/mecha_part_fabricator/crowbar_act(mob/living/user, obj/item/I) + if(..()) return TRUE - - return ..() - + if(being_built) + to_chat(user, "\The [src] is currently processing! Please wait until completion.") + return FALSE + return default_deconstruction_crowbar(I) /obj/machinery/mecha_part_fabricator/proc/is_insertion_ready(mob/user) if(panel_open) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index f1227aa6b55..93c7f8e02b3 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -11,6 +11,8 @@ var/installed = 0 var/require_module = 0 var/list/module_type = null + /// Bitflags listing module compatibility. Used in the exosuit fabricator for creating sub-categories. + var/list/module_flags = NONE // if true, is not stored in the robot to be ejected // if module is reset var/one_use = FALSE @@ -72,6 +74,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/security) + module_flags = BORG_MODULE_SECURITY /obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -120,6 +123,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/miner) + module_flags = BORG_MODULE_MINER /obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -152,6 +156,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/miner) + module_flags = BORG_MODULE_MINER /obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R) . = ..() @@ -179,6 +184,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/janitor) + module_flags = BORG_MODULE_JANITOR /obj/item/borg/upgrade/tboh/action(mob/living/silicon/robot/R) . = ..() @@ -206,6 +212,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/janitor) + module_flags = BORG_MODULE_JANITOR /obj/item/borg/upgrade/amop/action(mob/living/silicon/robot/R) . = ..() @@ -255,6 +262,7 @@ resistance_flags = LAVA_PROOF | FIRE_PROOF require_module = 1 module_type = list(/obj/item/robot_module/miner) + module_flags = BORG_MODULE_MINER /obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -372,6 +380,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/medical) + module_flags = BORG_MODULE_MEDICAL var/list/additional_reagents = list() /obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr) @@ -428,6 +437,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/medical) + module_flags = BORG_MODULE_MEDICAL var/backpack = FALSE //True if we get the defib from a physical backpack unit rather than an upgrade card, so that we can return that upon deactivate() /obj/item/borg/upgrade/defib/backpack @@ -462,6 +472,7 @@ icon_state = "cyborg_upgrade3" require_module = 1 module_type = list(/obj/item/robot_module/medical, /obj/item/robot_module/syndicate_medical) + module_flags = BORG_MODULE_MEDICAL /obj/item/borg/upgrade/processor/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -547,6 +558,7 @@ icon_state = "borgrped" require_module = TRUE module_type = list(/obj/item/robot_module/engineering, /obj/item/robot_module/saboteur) + module_flags = BORG_MODULE_ENGINEERING /obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -575,6 +587,7 @@ icon_state = "pinpointer_crew" require_module = TRUE module_type = list(/obj/item/robot_module/medical, /obj/item/robot_module/syndicate_medical) + module_flags = BORG_MODULE_MEDICAL var/datum/action/crew_monitor /obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R, user = usr) @@ -633,6 +646,7 @@ icon_state = "cyborg_upgrade3" require_module = TRUE module_type = list(/obj/item/robot_module/engineering, /obj/item/robot_module/saboteur) + module_flags = BORG_MODULE_ENGINEERING /obj/item/borg/upgrade/circuit_app/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -659,6 +673,7 @@ icon_state = "cyborg_upgrade3" require_module = TRUE module_type = list(/obj/item/robot_module/medical) + module_flags = BORG_MODULE_MEDICAL /obj/item/borg/upgrade/beaker_app/action(mob/living/silicon/robot/R, user = usr) . = ..() @@ -685,6 +700,7 @@ icon_state = "cyborg_upgrade3" require_module = TRUE module_type = list(/obj/item/robot_module/janitor) + module_flags = BORG_MODULE_JANITOR /obj/item/borg/upgrade/broomer/action(mob/living/silicon/robot/R, user = usr) . = ..() diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index 96cb2830838..0462375f3dd 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -209,7 +209,7 @@ "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif', "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif', "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif', - ) + ) /datum/asset/spritesheet/simple/achievements name ="achievements" @@ -389,3 +389,13 @@ assets = list( "view_variables.css" = 'html/admin/view_variables.css' ) + +/datum/asset/spritesheet/sheetmaterials + name = "sheetmaterials" + +/datum/asset/spritesheet/sheetmaterials/register() + InsertAll("", 'icons/obj/stack_objects.dmi') + + // Special case to handle Bluespace Crystals + Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal") + ..() diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 1735a88b3a5..e75c8b20abc 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -234,6 +234,7 @@ w_class = WEIGHT_CLASS_SMALL require_module = 1 module_type = list(/obj/item/robot_module/miner) + module_flags = BORG_MODULE_MINER var/denied_type = null var/maximum_of_type = 1 var/cost = 30 diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index f98a38a4176..1b48d4d1f4f 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -39,6 +39,8 @@ other types of metals and chemistry for reagents). var/research_icon //Replaces the item icon in the research console var/research_icon_state var/icon_cache + /// Optional string that interfaces can use as part of search filters. See- item/borg/upgrade/ai and the Exosuit Fabs. + var/search_metadata /datum/design/error_design name = "ERROR" diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm index f3b4baa917e..ca940cfb722 100644 --- a/code/modules/research/designs/mecha_designs.dm +++ b/code/modules/research/designs/mecha_designs.dm @@ -288,7 +288,7 @@ departmental_flags = DEPARTMENTAL_FLAG_SECURITY /datum/design/clusterbang_launcher - name = "Exosuit Module (SOB-3 Clusterbang Launcher)" + name = "Exosuit Weapon (SOB-3 Clusterbang Launcher)" desc = "A weapon that violates the Geneva Convention at 3 rounds per minute" id = "clusterbang_launcher" build_type = MECHFAB @@ -399,7 +399,7 @@ category = list("Exosuit Equipment") /datum/design/mech_diamond_drill - name = "Exosuit Module (Diamond Mining Drill)" + name = "Exosuit Mining (Diamond Mining Drill)" desc = "An upgraded version of the standard drill." id = "mech_diamond_drill" build_type = MECHFAB @@ -419,7 +419,7 @@ category = list("Exosuit Equipment") /datum/design/mech_plasma_cutter - name = "Exosuit Module Design (217-D Heavy Plasma Cutter)" + name = "Exosuit Mining (217-D Heavy Plasma Cutter)" desc = "A device that shoots resonant plasma bursts at extreme velocity. The blasts are capable of crushing rock and demolishing solid obstacles." id = "mech_plasma_cutter" build_type = MECHFAB @@ -450,7 +450,7 @@ departmental_flags = DEPARTMENTAL_FLAG_SECURITY /datum/design/mech_sleeper - name = "Exosuit Medical Equipment (Mounted Sleeper)" + name = "Exosuit Medical (Mounted Sleeper)" desc = "Equipment for medical exosuits. A mounted sleeper that stabilizes patients and can inject reagents in the exosuit's reserves." id = "mech_sleeper" build_type = MECHFAB @@ -460,7 +460,7 @@ category = list("Exosuit Equipment") /datum/design/mech_syringe_gun - name = "Exosuit Medical Equipment (Syringe Gun)" + name = "Exosuit Medical (Syringe Gun)" desc = "Equipment for medical exosuits. A chem synthesizer with syringe gun. Reagents inside are held in stasis, so no reactions will occur." id = "mech_syringe_gun" build_type = MECHFAB @@ -470,7 +470,7 @@ category = list("Exosuit Equipment") /datum/design/mech_medical_beamgun - name = "Exosuit Medical Equipment (Medical Beamgun)" + name = "Exosuit Medical (Medical Beamgun)" desc = "Equipment for medical exosuits. A mounted medical nanite projector which will treat patients with a focused beam." id = "mech_medi_beam" build_type = MECHFAB diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index c561d9b2c3d..21e6f6da51a 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -513,7 +513,7 @@ //Exosuit Equipment /datum/design/ripleyupgrade - name = "Ripley MK-1 to MK-II conversion kit" + name = "Ripley MK-I to MK-II conversion kit" id = "ripleyupgrade" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/ripleyupgrade @@ -522,7 +522,7 @@ category = list("Exosuit Equipment") /datum/design/mech_hydraulic_clamp - name = "Exosuit Engineering Equipment (Hydraulic Clamp)" + name = "Exosuit Engineering (Hydraulic Clamp)" id = "mech_hydraulic_clamp" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp @@ -531,7 +531,7 @@ category = list("Exosuit Equipment") /datum/design/mech_drill - name = "Exosuit Engineering Equipment (Drill)" + name = "Exosuit Mining (Mining Drill)" id = "mech_drill" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/drill @@ -540,7 +540,7 @@ category = list("Exosuit Equipment") /datum/design/mech_mining_scanner - name = "Exosuit Engineering Equipment (Mining Scanner)" + name = "Exosuit Engineering (Mining Scanner)" id = "mech_mscanner" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/mining_scanner @@ -549,7 +549,7 @@ category = list("Exosuit Equipment") /datum/design/mech_extinguisher - name = "Exosuit Engineering Equipment (Extinguisher)" + name = "Exosuit Engineering (Extinguisher)" id = "mech_extinguisher" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/extinguisher @@ -558,7 +558,7 @@ category = list("Exosuit Equipment") /datum/design/mech_generator - name = "Exosuit Equipment (Plasma Generator)" + name = "Exosuit Module (Plasma Generator)" id = "mech_generator" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/generator @@ -567,7 +567,7 @@ category = list("Exosuit Equipment") /datum/design/mech_mousetrap_mortar - name = "H.O.N.K Mousetrap Mortar" + name = "H.O.N.K Weapon (Mousetrap Mortar)" id = "mech_mousetrap_mortar" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar @@ -576,7 +576,7 @@ category = list("Exosuit Equipment") /datum/design/mech_banana_mortar - name = "H.O.N.K Banana Mortar" + name = "H.O.N.K Weapon (Banana Mortar)" id = "mech_banana_mortar" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar @@ -585,7 +585,7 @@ category = list("Exosuit Equipment") /datum/design/mech_honker - name = "HoNkER BlAsT 5000" + name = "H.O.N.K Weapon (HoNkER BlAsT 5000)" id = "mech_honker" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/weapon/honker @@ -594,7 +594,7 @@ category = list("Exosuit Equipment") /datum/design/mech_punching_glove - name = "Oingo Boingo Punch-face" + name = "H.O.N.K Weapon (Oingo Boingo Punch-face)" id = "mech_punching_face" build_type = MECHFAB build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove @@ -766,7 +766,8 @@ build_path = /obj/item/borg/upgrade/ai materials = list(/datum/material/iron = 1200, /datum/material/glass = 1500, /datum/material/gold = 200) construction_time = 50 - category = list("Misc") + category = list("Control Interfaces") + search_metadata = "boris" /datum/design/borg_upgrade_rped name = "Cyborg Upgrade (RPED)" @@ -815,13 +816,13 @@ //Misc /datum/design/mecha_tracking - name = "Exosuit Tracking Beacon" + name = "Exosuit Tracker (Exosuit Tracking Beacon)" id = "mecha_tracking" build_type = MECHFAB build_path =/obj/item/mecha_parts/mecha_tracking materials = list(/datum/material/iron=500) construction_time = 50 - category = list("Misc") + category = list("Exosuit Equipment") /datum/design/mecha_tracking_ai_control name = "AI Control Beacon" @@ -830,7 +831,7 @@ build_path = /obj/item/mecha_parts/mecha_tracking/ai_control materials = list(/datum/material/iron = 1000, /datum/material/glass = 500, /datum/material/silver = 200) construction_time = 50 - category = list("Misc") + category = list("Control Interfaces") /datum/design/synthetic_flash name = "Flash" diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index e882ccba3bf..fa5e30df7ee 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -19,7 +19,7 @@ materials = list(/datum/material/iron = 1000, /datum/material/glass = 500) construction_time = 75 build_path = /obj/item/mmi - category = list("Misc","Medical Designs") + category = list("Control Interfaces", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE /datum/design/posibrain @@ -30,7 +30,7 @@ materials = list(/datum/material/iron = 1700, /datum/material/glass = 1350, /datum/material/gold = 500) //Gold, because SWAG. construction_time = 75 build_path = /obj/item/mmi/posibrain - category = list("Misc", "Medical Designs") + category = list("Control Interfaces", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE /datum/design/bluespacebeaker @@ -303,7 +303,7 @@ construction_time = 40 materials = list(/datum/material/iron = 600, /datum/material/glass = 400) build_path = /obj/item/organ/eyes/robotic/shield - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_gloweyes @@ -314,7 +314,7 @@ construction_time = 40 materials = list(/datum/material/iron = 600, /datum/material/glass = 1000) build_path = /obj/item/organ/eyes/robotic/glow - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_breather @@ -325,7 +325,7 @@ construction_time = 35 materials = list(/datum/material/iron = 600, /datum/material/glass = 250) build_path = /obj/item/organ/cyberimp/mouth/breathing_tube - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_surgical @@ -336,7 +336,7 @@ materials = list (/datum/material/iron = 2500, /datum/material/glass = 1500, /datum/material/silver = 1500) construction_time = 200 build_path = /obj/item/organ/cyberimp/arm/surgery - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_toolset @@ -347,7 +347,7 @@ materials = list (/datum/material/iron = 2500, /datum/material/glass = 1500, /datum/material/silver = 1500) construction_time = 200 build_path = /obj/item/organ/cyberimp/arm/toolset - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_medical_hud @@ -358,7 +358,7 @@ construction_time = 50 materials = list(/datum/material/iron = 600, /datum/material/glass = 600, /datum/material/silver = 500, /datum/material/gold = 500) build_path = /obj/item/organ/cyberimp/eyes/hud/medical - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_security_hud @@ -369,7 +369,7 @@ construction_time = 50 materials = list(/datum/material/iron = 600, /datum/material/glass = 600, /datum/material/silver = 750, /datum/material/gold = 750) build_path = /obj/item/organ/cyberimp/eyes/hud/security - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_diagnostic_hud @@ -380,7 +380,7 @@ construction_time = 50 materials = list(/datum/material/iron = 600, /datum/material/glass = 600, /datum/material/silver = 600, /datum/material/gold = 600) build_path = /obj/item/organ/cyberimp/eyes/hud/diagnostic - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_xray @@ -391,7 +391,7 @@ construction_time = 60 materials = list(/datum/material/iron = 600, /datum/material/glass = 600, /datum/material/silver = 600, /datum/material/gold = 600, /datum/material/plasma = 1000, /datum/material/uranium = 1000, /datum/material/diamond = 1000, /datum/material/bluespace = 1000) build_path = /obj/item/organ/eyes/robotic/xray - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_thermals @@ -402,7 +402,7 @@ construction_time = 60 materials = list(/datum/material/iron = 600, /datum/material/glass = 600, /datum/material/silver = 600, /datum/material/gold = 600, /datum/material/plasma = 1000, /datum/material/diamond = 2000) build_path = /obj/item/organ/eyes/robotic/thermals - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_antidrop @@ -413,7 +413,7 @@ construction_time = 60 materials = list(/datum/material/iron = 600, /datum/material/glass = 600, /datum/material/silver = 400, /datum/material/gold = 400) build_path = /obj/item/organ/cyberimp/brain/anti_drop - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_antistun @@ -424,7 +424,7 @@ construction_time = 60 materials = list(/datum/material/iron = 600, /datum/material/glass = 600, /datum/material/silver = 500, /datum/material/gold = 1000) build_path = /obj/item/organ/cyberimp/brain/anti_stun - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_nutriment @@ -435,7 +435,7 @@ construction_time = 40 materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/gold = 500) build_path = /obj/item/organ/cyberimp/chest/nutriment - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_nutriment_plus @@ -446,7 +446,7 @@ construction_time = 50 materials = list(/datum/material/iron = 600, /datum/material/glass = 600, /datum/material/gold = 500, /datum/material/uranium = 750) build_path = /obj/item/organ/cyberimp/chest/nutriment/plus - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_reviver @@ -457,7 +457,7 @@ construction_time = 60 materials = list(/datum/material/iron = 800, /datum/material/glass = 800, /datum/material/gold = 300, /datum/material/uranium = 500) build_path = /obj/item/organ/cyberimp/chest/reviver - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cyberimp_thrusters @@ -468,7 +468,7 @@ construction_time = 80 materials = list(/datum/material/iron = 4000, /datum/material/glass = 2000, /datum/material/silver = 1000, /datum/material/diamond = 1000) build_path = /obj/item/organ/cyberimp/chest/thrusters - category = list("Misc", "Medical Designs") + category = list("Implants", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL ///////////////////////////////////////// @@ -535,7 +535,7 @@ construction_time = 40 materials = list(/datum/material/iron = 500, /datum/material/glass = 500) build_path = /obj/item/organ/liver/cybernetic - category = list("Misc", "Medical Designs") + category = list("Cybernetics", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_liver/tier2 @@ -561,7 +561,7 @@ construction_time = 40 materials = list(/datum/material/iron = 500, /datum/material/glass = 500) build_path = /obj/item/organ/heart/cybernetic - category = list("Misc", "Medical Designs") + category = list("Cybernetics", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_heart/tier2 @@ -587,7 +587,7 @@ construction_time = 40 materials = list(/datum/material/iron = 500, /datum/material/glass = 500) build_path = /obj/item/organ/lungs/cybernetic - category = list("Misc", "Medical Designs") + category = list("Cybernetics", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_lungs/tier2 @@ -639,7 +639,7 @@ construction_time = 30 materials = list(/datum/material/iron = 250, /datum/material/glass = 400) build_path = /obj/item/organ/ears/cybernetic - category = list("Misc", "Medical Designs") + category = list("Cybernetics", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /datum/design/cybernetic_ears_u @@ -650,7 +650,7 @@ construction_time = 40 materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/silver = 500) build_path = /obj/item/organ/ears/cybernetic/upgraded - category = list("Misc", "Medical Designs") + category = list("Cybernetics", "Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL ///////////////////// diff --git a/tgstation.dme b/tgstation.dme index 2b029f2035e..919b645023f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -44,6 +44,7 @@ #include "code\__DEFINES\dye_keys.dm" #include "code\__DEFINES\economy.dm" #include "code\__DEFINES\events.dm" +#include "code\__DEFINES\exosuit_fab.dm" #include "code\__DEFINES\exports.dm" #include "code\__DEFINES\fantasy_affixes.dm" #include "code\__DEFINES\flags.dm" diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator.js b/tgui/packages/tgui/interfaces/ExosuitFabricator.js new file mode 100644 index 00000000000..a9c42d91a81 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator.js @@ -0,0 +1,796 @@ +import { classes } from 'common/react'; +import { uniqBy } from 'common/collections'; +import { useBackend, useSharedState } from '../backend'; +import { formatSiUnit, formatMoney } from '../format'; +import { Flex, Section, Tabs, Box, Button, Fragment, ProgressBar, NumberInput, Icon, Input } from '../components'; +import { Window } from '../layouts'; +import { createSearch } from 'common/string'; + +const MATERIAL_KEYS = { + "iron": "sheet-metal_3", + "glass": "sheet-glass_3", + "silver": "sheet-silver_3", + "gold": "sheet-gold_3", + "diamond": "sheet-diamond", + "plasma": "sheet-plasma_3", + "uranium": "sheet-uranium", + "bananium": "sheet-bananium", + "titanium": "sheet-titanium_3", + "bluespace crystal": "polycrystal", + "plastic": "sheet-plastic_3", +}; + +const COLOR_NONE = 0; +const COLOR_AVERAGE = 1; +const COLOR_BAD = 2; + +const COLOR_KEYS = { + [COLOR_NONE]: false, + [COLOR_AVERAGE]: "average", + [COLOR_BAD]: "bad", +}; + +const materialArrayToObj = materials => { + let materialObj = {}; + + materials.forEach(m => { + materialObj[m.name] = m.amount; }); + + return materialObj; +}; + +const partBuildColor = (cost, tally, material) => { + if (cost > material) { + return { color: COLOR_BAD, deficit: (cost - material) }; + } + + if (tally > material) { + return { color: COLOR_AVERAGE, deficit: cost }; + } + + if (cost + tally > material) { + return { color: COLOR_AVERAGE, deficit: ((cost + tally) - material) }; + } + + return { color: COLOR_NONE, deficit: 0 }; +}; + +const partCondFormat = (materials, tally, part) => { + let format = { "textColor": COLOR_NONE }; + + Object.keys(part.cost).forEach(mat => { + format[mat] = partBuildColor(part.cost[mat], tally[mat], materials[mat]); + + if (format[mat].color > format["textColor"]) { + format["textColor"] = format[mat].color; + } + }); + + return format; +}; + +const queueCondFormat = (materials, queue) => { + let materialTally = {}; + let matFormat = {}; + let missingMatTally = {}; + let textColors = {}; + + queue.forEach((part, i) => { + textColors[i] = COLOR_NONE; + Object.keys(part.cost).forEach(mat => { + materialTally[mat] = materialTally[mat] || 0; + missingMatTally[mat] = missingMatTally[mat] || 0; + + matFormat[mat] = partBuildColor( + part.cost[mat], materialTally[mat], materials[mat] + ); + + if (matFormat[mat].color !== COLOR_NONE) { + if (textColors[i] < matFormat[mat].color) { + textColors[i] = matFormat[mat].color; + } + } + else { + materialTally[mat] += part.cost[mat]; + } + + missingMatTally[mat] += matFormat[mat].deficit; + }); + }); + return { materialTally, missingMatTally, textColors, matFormat }; +}; + +const searchFilter = (search, allparts) => { + let searchResults = []; + + if (!search.length) { + return; + } + + const resultFilter = createSearch(search, part => ( + (part.name || "") + + (part.desc || "") + + (part.searchMeta || "") + )); + + Object.keys(allparts).forEach(category => { + allparts[category] + .filter(resultFilter) + .forEach(e => { searchResults.push(e); }); + }); + + searchResults = uniqBy(part => part.name)(searchResults); + + return searchResults; +}; + +export const ExosuitFabricator = (props, context) => { + const { act, data } = useBackend(context); + + const queue = data.queue || []; + const materialAsObj = materialArrayToObj(data.materials || []); + + const { + materialTally, + missingMatTally, + textColors, + } = queueCondFormat(materialAsObj, queue); + + const [ + displayMatCost, + setDisplayMatCost, + ] = useSharedState(context, "display_mats", false); + + return ( + + + + + +
+ +
+
+ +
+ setDisplayMatCost(!displayMatCost)} + checked={displayMatCost}> + Display Material Costs + +
+
+
+ + + +
act("sync_rnd")} /> + )}> + +
+
+ + + + + + + + +
+
+
+
+
+ ); +}; + +const EjectMaterial = (props, context) => { + const { act } = useBackend(context); + + const { material } = props; + + const { + name, + removable, + sheets, + ref, + } = material; + + const [ + removeMaterials, + setRemoveMaterials, + ] = useSharedState(context, "remove_mats_" + name, 1); + + if ((removeMaterials > 1) && (sheets < removeMaterials)) { + setRemoveMaterials(sheets || 1); + } + + return ( + + { + const newVal = parseInt(val, 10); + if (Number.isInteger(newVal)) { + setRemoveMaterials(newVal); + } + }} /> +