diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index b697ba8f5ce..e46af4d1f50 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -662,7 +662,7 @@ Turf and target are seperate in case you want to teleport some distance from a t * * Arguments: * * user: The user to check for. - * * delay: The delay in ticks to wait before returning TRUE. + * * delay: The delay in deciseconds to wait before returning TRUE. * * target: The target to check for. Optional. * * do_flags: Flags that determine what the user and target can and cannot do, defined in [mobs.dm]. Defaults to DO_DEFAULT. * * incapacitation_flags: Incapacitation flags that determines if the user can be incapacitated. Defaults to INCAPACITATION_DEFAULT. diff --git a/code/modules/research/designs/designs.dm b/code/modules/research/designs/designs.dm index 2d419a34a37..9ee229e0874 100644 --- a/code/modules/research/designs/designs.dm +++ b/code/modules/research/designs/designs.dm @@ -21,15 +21,24 @@ other types of metals and chemistry for reagents). // #TODO-MERGE: Go over this file and make sure everything's fine. We might have missing vars. /datum/design //Datum for object designs, used in construction - var/name //Name of the created object. If null it will be 'guessed' from build_path if possible. - var/desc //Description of the created object. If null it will use group_desc and name where applicable. - var/item_name //An item name before it is modified by various name-modifying procs - var/list/req_tech = list() //IDs of that techs the object originated from and the minimum level requirements. - var/build_type //Flag as to what kind machine the design is built in. See defines. - var/list/materials = list() //List of materials. Format: "id" = amount. - var/list/chemicals = list() //List of chemicals. - var/build_path //The path of the object that gets created. - var/time = 10 //How many ticks it requires to build + ///Name of the created object, if null it will be 'guessed' from build_path if possible + var/name + ///Description of the created object. If null it will use group_desc and name where applicable + var/desc + ///An item name before it is modified by various name-modifying procs + var/item_name + ///IDs of that techs the object originated from and the minimum level requirements + var/list/req_tech = list() + ///Flag as to what kind machine the design is built in, see defines in `code\__DEFINES\research.dm` + var/build_type + ///List of materials, format: `"id" = amount` + var/list/materials = list() + ///List of chemicals + var/list/chemicals = list() + //The path of the object that gets created + var/build_path + ///How many deciseconds it requires to build + var/time = 10 var/p_category = "Misc" var/category //Primarily used for Mech Fabricators, but can be used for anything. diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index b7238e78a17..17bd110e869 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -4,17 +4,29 @@ icon_state = "protolathe" atom_flags = ATOM_FLAG_OPEN_CONTAINER - idle_power_usage = 30 - active_power_usage = 5000 + idle_power_usage = 30 WATTS + active_power_usage = 25 KILO WATTS var/max_material_storage = 100000 var/list/materials = list(DEFAULT_WALL_MATERIAL = 0, MATERIAL_GLASS = 0, MATERIAL_GOLD = 0, MATERIAL_SILVER = 0, MATERIAL_PHORON = 0, MATERIAL_URANIUM = 0, MATERIAL_DIAMOND = 0) + /** + * A `/list` of enqueued `/datum/design` to be printed, processed in the queue + */ var/list/datum/design/queue = list() - var/progress = 0 + /** + * How much efficient (or inefficient) the protolathe is at manufacturing things + */ var/mat_efficiency = 1 - var/speed = 1 + + /** + * The production speed of this specific protolathe, a factor + */ + var/production_speed = 1 + + ///The timer id for the build callback, if we're building something + var/build_callback_timer component_types = list( /obj/item/circuitboard/protolathe, @@ -23,33 +35,8 @@ /obj/item/reagent_containers/glass/beaker = 2 ) -/obj/machinery/r_n_d/protolathe/process() - ..() - if(stat) - update_icon() - return - if(queue.len == 0) - busy = 0 - update_icon() - return - var/datum/design/D = queue[1] - if(canBuild(D)) - busy = 1 - progress += speed - if(progress >= D.time) - build(D) - progress = 0 - removeFromQueue(1) - if(linked_console) - linked_console.updateUsrDialog() - update_icon() - else - if(busy) - visible_message("[icon2html(src, viewers(get_turf(src)))] [src] flashes: insufficient materials: [getLackingMaterials(D)].") - busy = 0 - update_icon() - -/obj/machinery/r_n_d/protolathe/proc/TotalMaterials() //returns the total of all the stored materials. Makes code neater. +///Returns the total of all the stored materials +/obj/machinery/r_n_d/protolathe/proc/TotalMaterials() var/t = 0 for(var/f in materials) t += materials[f] @@ -75,7 +62,7 @@ for(var/obj/item/stock_parts/manipulator/M in component_parts) T += M.rating mat_efficiency = 1 - (T - 2) / 8 - speed = T / 2 + production_speed = T / 2 /obj/machinery/r_n_d/protolathe/dismantle() for(var/obj/I in component_parts) @@ -92,14 +79,14 @@ /obj/machinery/r_n_d/protolathe/update_icon() if(panel_open) icon_state = "protolathe_t" - else if(busy) + else if(build_callback_timer) icon_state = "protolathe_n" else icon_state = "protolathe" /obj/machinery/r_n_d/protolathe/attackby(obj/item/attacking_item, mob/user) - if(busy) - to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") + if(build_callback_timer) + to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for completion of previous operation.")) return 1 if(default_deconstruction_screwdriver(user, attacking_item)) if(linked_console) @@ -113,98 +100,179 @@ if(attacking_item.is_open_container()) return 1 if(panel_open) - to_chat(user, "You can't load \the [src] while it's opened.") + to_chat(user, SPAN_NOTICE("You can't load \the [src] while it's opened.")) return 1 if(!linked_console) - to_chat(user, "\The [src] must be linked to an R&D console first!") + to_chat(user, SPAN_NOTICE("The [src] must be linked to an R&D console first!")) return 1 if(!istype(attacking_item, /obj/item/stack/material)) - to_chat(user, "You cannot insert this item into \the [src]!") + to_chat(user, SPAN_NOTICE("You cannot insert this item into \the [src]!")) return 1 if(stat) return 1 if(TotalMaterials() + SHEET_MATERIAL_AMOUNT > max_material_storage) - to_chat(user, "\The [src]'s material bin is full. Please remove material before adding more.") + to_chat(user, SPAN_NOTICE("The [src]'s material bin is full. Please remove material before adding more.")) return 1 var/obj/item/stack/material/stack = attacking_item if(!stack.default_type) to_chat(user, SPAN_WARNING("This stack cannot be used!")) return - var/amount = round(input("How many sheets do you want to add?") as num)//No decimals + var/amount = tgui_input_number(user, "How many sheets do you want to add?", "Add sheets", 10, + max_value = min(stack.get_amount(), round((max_material_storage - TotalMaterials()) / SHEET_MATERIAL_AMOUNT)), + min_value = 1, round_value = TRUE) if(!attacking_item) return if(!Adjacent(user)) - to_chat(user, "\The [src] is too far away for you to insert this.") + to_chat(user, SPAN_NOTICE("The [src] is too far away for you to insert this.")) return - if(amount <= 0)//No negative numbers + if(amount <= 0)//No negative numbers, no nulls return - if(amount > stack.get_amount()) - amount = stack.get_amount() - if(max_material_storage - TotalMaterials() < (amount * SHEET_MATERIAL_AMOUNT)) //Can't overfill - amount = min(stack.get_amount(), round((max_material_storage - TotalMaterials()) / SHEET_MATERIAL_AMOUNT)) AddOverlays("protolathe_[stack.default_type]") CUT_OVERLAY_IN("protolathe_[stack.default_type]", 10) - busy = 1 + //Use some power and add the materials use_power_oneoff(max(1000, (SHEET_MATERIAL_AMOUNT * amount / 10))) - if(do_after(user, 16)) + if(do_after(user, 1.6 SECONDS)) if(stack.use(amount)) - to_chat(user, "You add [amount] sheets to \the [src].") + to_chat(user, SPAN_NOTICE("You add [amount] sheets to \the [src].")) materials[stack.default_type] += amount * SHEET_MATERIAL_AMOUNT - busy = 0 + + //In case there's things queued up, we run the queue handler + handle_queue() + + //Give an update on the UIs updateUsrDialog() - return + if(linked_console) + linked_console.updateUsrDialog() -/obj/machinery/r_n_d/protolathe/proc/addToQueue(var/datum/design/D) - queue += D +/** + * Adds a design to the queue + * + * * design_to_add: The design to add + */ +/obj/machinery/r_n_d/protolathe/proc/addToQueue(datum/design/design_to_add) + queue += design_to_add + //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/r_n_d/protolathe/proc/removeFromQueue(var/index) queue.Cut(index, index + 1) -/obj/machinery/r_n_d/protolathe/proc/canBuild(var/datum/design/D) - for(var/M in D.materials) - if(materials[M] < D.materials[M]) - return 0 - for(var/C in D.chemicals) - if(!reagents.has_reagent(C, D.chemicals[C])) - return 0 - return 1 + //Wake up, we have things to do + handle_queue() + +/** + * Handle the construction queue + */ +/obj/machinery/r_n_d/protolathe/proc/handle_queue() -/obj/machinery/r_n_d/protolathe/proc/getLackingMaterials(var/datum/design/D) + //No work to do or already busy, stop + if(!length(queue) || build_callback_timer) + 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(canBuild(D)) + build_callback_timer = addtimer(CALLBACK(src, PROC_REF(build), D), (D.time / production_speed), TIMER_UNIQUE) + removeFromQueue(1) + + else + visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] flashes: Insufficient materials: [getLackingMaterials(D)].")) + + update_icon() + + +/** + * Checks if the protolathe can build the given design + * + * * design_to_check: The design to check + * + * Returns `TRUE` if the design can be built, `FALSE` otherwise + */ +/obj/machinery/r_n_d/protolathe/proc/canBuild(datum/design/design_to_check) + for(var/M in design_to_check.materials) + if(materials[M] < design_to_check.materials[M]) + return FALSE + + for(var/C in design_to_check.chemicals) + if(!reagents.has_reagent(C, design_to_check.chemicals[C])) + return FALSE + + return TRUE + +/** + * Get what materials (chemicals included) are lacking from being able to build the given design + * + * * design_to_check: The design to check + * + * Returns a string of the materials that are missing + */ +/obj/machinery/r_n_d/protolathe/proc/getLackingMaterials(var/datum/design/design_to_check) var/ret = "" - for(var/M in D.materials) - if(materials[M] < D.materials[M]) + for(var/M in design_to_check.materials) + if(materials[M] < design_to_check.materials[M]) if(ret != "") ret += ", " - ret += "[D.materials[M] - materials[M]] [M]" - for(var/C in D.chemicals) - if(!reagents.has_reagent(C, D.chemicals[C])) + ret += "[design_to_check.materials[M] - materials[M]] [M]" + for(var/C in design_to_check.chemicals) + if(!reagents.has_reagent(C, design_to_check.chemicals[C])) var/singleton/reagent/R = GET_SINGLETON(C) if(ret != "") ret += ", " ret += "[R.name]" return ret -/obj/machinery/r_n_d/protolathe/proc/build(var/datum/design/D) +/** + * Builds the given design, assuming all the necessary conditions are met + * + * * design_to_build: The design to build + */ +/obj/machinery/r_n_d/protolathe/proc/build(datum/design/design_to_build) + //Consume some power var/power = active_power_usage - for(var/M in D.materials) - power += round(D.materials[M] / 5) + for(var/M in design_to_build.materials) + power += round(design_to_build.materials[M] / 2) power = max(active_power_usage, power) use_power_oneoff(power) - for(var/M in D.materials) - materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency) - for(var/C in D.chemicals) - reagents.remove_reagent(C, D.chemicals[C] * mat_efficiency) + + //Consume the materials + for(var/M in design_to_build.materials) + materials[M] = max(0, materials[M] - design_to_build.materials[M] * mat_efficiency) + for(var/C in design_to_build.chemicals) + reagents.remove_reagent(C, design_to_build.chemicals[C] * mat_efficiency) intent_message(MACHINE_SOUND) - if(D.build_path) - var/obj/new_item = D.Fabricate(src, src) + if(design_to_build.build_path) + var/obj/new_item = design_to_build.Fabricate(src, src) new_item.forceMove(loc) if(mat_efficiency != 1) // No matter out of nowhere 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 + + if(linked_console) + linked_console.updateUsrDialog() + + //We finished building, clear the timer + build_callback_timer = null + + //Do the queue handling for the next item, or to stop + handle_queue() diff --git a/html/changelogs/fluffyghost-protolatherefresh.yml b/html/changelogs/fluffyghost-protolatherefresh.yml new file mode 100644 index 00000000000..e82e76e2369 --- /dev/null +++ b/html/changelogs/fluffyghost-protolatherefresh.yml @@ -0,0 +1,63 @@ +################################ +# 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: + - code_imp: "Various DMdocs to the protolathe code." + - balance: "Increased power draw of the protolathe." + - balance: "Made the protolathe realtime-constant." + - code_imp: "Adding materials to the protolathe now uses TGUI input." + - code_imp: "Removed a basically useless processing, uses a timer / queue handler proc now." + - code_imp: "DMDoc'd other parts of the code, including corrections between ticks and deciseconds."