diff --git a/code/game/machinery/mecha_fabricator.dm b/code/game/machinery/mecha_fabricator.dm index 676769baa6c..fc0612104a2 100644 --- a/code/game/machinery/mecha_fabricator.dm +++ b/code/game/machinery/mecha_fabricator.dm @@ -8,22 +8,6 @@ idle_power_usage = 20 active_power_usage = 5000 req_access = list(ACCESS_ROBOTICS) - - var/speed = 1 - var/mat_efficiency = 1 - var/list/materials = list(DEFAULT_WALL_MATERIAL = 0, MATERIAL_GLASS = 0, MATERIAL_GOLD = 0, MATERIAL_SILVER = 0, MATERIAL_DIAMOND = 0, MATERIAL_PHORON = 0, MATERIAL_URANIUM = 0) - 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 = "" - var/limb_manufacturer - component_types = list( /obj/item/circuitboard/mechfab, /obj/item/stock_parts/matter_bin = 2, @@ -32,6 +16,34 @@ /obj/item/stock_parts/console_screen ) + /** + * A `/list` of enqueued `/datum/design` to be printed, processed in the queue + */ + var/list/datum/design/queue = list() + + /** + * How much efficient (or inefficient) the protolathe is at manufacturing things + */ + var/mat_efficiency = 1 + + /** + * The production speed of this specific protolathe, a factor + */ + var/production_speed = 1 + + var/list/materials = list(DEFAULT_WALL_MATERIAL = 0, MATERIAL_GLASS = 0, MATERIAL_GOLD = 0, MATERIAL_SILVER = 0, MATERIAL_DIAMOND = 0, MATERIAL_PHORON = 0, MATERIAL_URANIUM = 0) + var/res_max_amount = 200000 + + var/datum/research/files + + var/list/categories = list() + var/category = null + var/sync_message = "" + var/limb_manufacturer + + ///The timer id for the build callback, if we're building something + var/build_callback_timer + /obj/machinery/mecha_part_fabricator/Initialize() . = ..() @@ -39,22 +51,10 @@ limb_manufacturer = GLOB.basic_robolimb.company update_categories() -/obj/machinery/mecha_part_fabricator/process() - ..() - if(stat) - return - if(busy) - update_use_power(POWER_USE_ACTIVE) - progress += speed - check_build() - else - update_use_power(POWER_USE_IDLE) - update_icon() - /obj/machinery/mecha_part_fabricator/update_icon() ClearOverlays() icon_state = "fab-base" - if(busy) + if(build_callback_timer) AddOverlays("fab-active") if(panel_open) AddOverlays("fab-panel") @@ -77,7 +77,7 @@ for(var/obj/item/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 + production_speed = T / 2 // 1 -> 3 /obj/machinery/mecha_part_fabricator/attack_hand(var/mob/user) if(..()) @@ -98,6 +98,7 @@ data["buildable"] = get_build_options() data["category"] = category data["categories"] = categories + if(GLOB.fabricator_robolimbs) var/list/T = list() for(var/A in GLOB.fabricator_robolimbs) @@ -105,11 +106,18 @@ T += list(list("id" = A, "company" = R.company)) data["manufacturers"] = T data["manufacturer"] = limb_manufacturer + data["materials"] = get_materials() data["maxres"] = res_max_amount data["sync"] = sync_message + + //If we have something in the queue that we're trying to build, show the time left if the build is undergoing, otherwise null + //the logic of displaying it is handled client-side if(current) - data["builtperc"] = round((progress / current.time) * 100) + if(build_callback_timer) + data["timeleft"] = round(timeleft(build_callback_timer)) + else + data["timeleft"] = null ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) @@ -148,7 +156,7 @@ return 1 /obj/machinery/mecha_part_fabricator/attackby(obj/item/attacking_item, mob/user) - if(busy) + if(build_callback_timer) to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for completion of previous operation.")) return TRUE if(default_deconstruction_screwdriver(user, attacking_item)) @@ -182,7 +190,7 @@ M.use(1) count++ to_chat(user, SPAN_NOTICE("You insert [count] [sname] into \the [src].")) - update_busy() + else to_chat(user, SPAN_NOTICE("\The [src] cannot hold more [sname].")) return TRUE @@ -250,27 +258,70 @@ if(1) visible_message("[icon2html(src, viewers(get_turf(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/path) +/** + * Adds a design to the queue + * + * * path: The path of the design to add + */ +/obj/machinery/mecha_part_fabricator/proc/add_to_queue(path) var/datum/design/D = files.known_designs[path] if(!D) return queue += D - update_busy() -/obj/machinery/mecha_part_fabricator/proc/remove_from_queue(var/index) - if(index == 1) - progress = 0 + //Wake up, we have things to do + handle_queue() + +/** + * Removes a design from the queue + * + * * index: The index of the design to remove + */ +/obj/machinery/mecha_part_fabricator/proc/remove_from_queue(index) queue.Cut(index, index + 1) - update_busy() + + //If we're removing the first thing in the queue, stop the build timer + if(index == 1) + deltimer(build_callback_timer) + build_callback_timer = null + + //Wake up, we have things to do + handle_queue() + +/** + * Handle the construction queue + */ +/obj/machinery/mecha_part_fabricator/proc/handle_queue() + + //No work to do or already busy, stop + if(!length(queue) || build_callback_timer) + //If we don't have a build in progress, revert to idle power usage + if(!build_callback_timer) + update_use_power(POWER_USE_IDLE) + + update_icon() + return + + //If there's no power, there's no building + if(stat & NOPOWER) + queue = list() + return + + //Get the first design in the queue + var/datum/design/D = queue[1] + + //If we can build it, process the request + if(can_build(D)) + update_use_power(POWER_USE_ACTIVE) + + //Add the callback timer for printing, and remove the design from the queue + build_callback_timer = addtimer(CALLBACK(src, PROC_REF(build), D), (D.time / production_speed), TIMER_UNIQUE|TIMER_STOPPABLE) + //No queue removal here because we show how long it takes to build in the UI + + else + visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] flashes: Insufficient materials to complete build: [D.name].")) + + update_icon() /obj/machinery/mecha_part_fabricator/proc/can_build(var/datum/design/D) for(var/M in D.materials) @@ -278,31 +329,34 @@ 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) +/** + * Builds the given design, assuming all the necessary conditions are met + * + * * design_to_build: The design to build + */ +/obj/machinery/mecha_part_fabricator/proc/build(datum/design/design_to_build) + //Consume the materials + for(var/M in design_to_build.materials) + materials[M] = max(0, materials[M] - design_to_build.materials[M] * mat_efficiency) intent_message(MACHINE_SOUND) - if(D.build_path) + if(design_to_build.build_path) var/loc_offset = get_step(src, dir) - var/obj/new_item = D.Fabricate(loc_offset, src) + var/obj/new_item = design_to_build.Fabricate(loc_offset, src) visible_message("\The [src] pings, indicating that \the [new_item] is complete.", "You hear a ping.", intent_message = PING_SOUND) 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 + + //We finished building, clear the timer and remove the thing from the queue + build_callback_timer = null remove_from_queue(1) + //Do the queue handling for the next item, or to stop + handle_queue() + /obj/machinery/mecha_part_fabricator/proc/get_queue_names() . = list() for(var/i = 2 to queue.len) @@ -324,7 +378,7 @@ 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") + return time2text(round(10 * D.time / production_speed), "mm:ss") /obj/machinery/mecha_part_fabricator/proc/update_categories() categories = list() @@ -358,7 +412,6 @@ materials[material] -= ejected * S.perunit if(recursive && materials[material] >= S.perunit) eject_materials(material, -1) - update_busy() /obj/machinery/mecha_part_fabricator/proc/sync() sync_message = "Error: no console found." diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index 40c286956d3..7468d0d24a4 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -1,7 +1,7 @@ GLOBAL_LIST_EMPTY(all_robolimbs) GLOBAL_LIST_EMPTY(internal_robolimbs) GLOBAL_LIST_EMPTY(chargen_robolimbs) -GLOBAL_LIST_EMPTY(fabricator_robolimbs) +GLOBAL_LIST_EMPTY_TYPED(fabricator_robolimbs, /datum/robolimb) GLOBAL_DATUM(basic_robolimb, /datum/robolimb) /proc/populate_robolimb_list() diff --git a/html/changelogs/fluffyghost-mechafabrefactor.yml b/html/changelogs/fluffyghost-mechafabrefactor.yml new file mode 100644 index 00000000000..41831842e13 --- /dev/null +++ b/html/changelogs/fluffyghost-mechafabrefactor.yml @@ -0,0 +1,60 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Refactored the mecha fabricator to use a queue system instead of processing." + - refactor: "Typed a GLOB list for robolimbs." + - bugfix: "Build time is now correct." diff --git a/nano/templates/mechfab.tmpl b/nano/templates/mechfab.tmpl index 863dbcceb09..7fe6c36c253 100644 --- a/nano/templates/mechfab.tmpl +++ b/nano/templates/mechfab.tmpl @@ -41,7 +41,11 @@ {{if data.current}}