diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm index 5c9336c5c5c..6f86429720a 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm @@ -88,7 +88,7 @@ /turf/open/floor/iron, /area/ruin/planetengi) "aA" = ( -/obj/machinery/rnd/production/protolathe/department/engineering/no_tax, +/obj/machinery/rnd/production/protolathe/department/engineering, /obj/effect/turf_decal/trimline/yellow/filled/warning{ dir = 9 }, diff --git a/_maps/RandomRuins/SpaceRuins/nova/cargodiselost.dmm b/_maps/RandomRuins/SpaceRuins/nova/cargodiselost.dmm index 801a11da4fe..3592016d918 100644 --- a/_maps/RandomRuins/SpaceRuins/nova/cargodiselost.dmm +++ b/_maps/RandomRuins/SpaceRuins/nova/cargodiselost.dmm @@ -1162,7 +1162,7 @@ /obj/item/stack/sheet/glass/fifty, /obj/item/circuitboard/machine/protolathe/offstation, /obj/effect/spawner/random/engineering/toolbox, -/obj/item/circuitboard/machine/circuit_imprinter/department/no_tax, +/obj/item/circuitboard/machine/circuit_imprinter/department, /obj/item/circuitboard/machine/rtg/advanced, /obj/item/circuitboard/machine/rtg/advanced, /obj/item/circuitboard/machine/rtg/advanced, diff --git a/code/datums/components/material/remote_materials.dm b/code/datums/components/material/remote_materials.dm index 97c6b4e6282..e418d4276be 100644 --- a/code/datums/components/material/remote_materials.dm +++ b/code/datums/components/material/remote_materials.dm @@ -118,6 +118,12 @@ handles linking back and forth. else silo.holds -= src +/** + * Sets the storage size for local materials when not linked with silo + * Arguments + * + * * size - the new size for local storage. measured in SHEET_MATERIAL_SIZE units + */ /datum/component/remote_materials/proc/set_local_size(size) local_size = size if (!silo && mat_container) @@ -209,7 +215,7 @@ handles linking back and forth. return check_z_level() ? silo.holds[src] : FALSE /** - * Internal proc to check if this connection can use any materials from the silo + * Check if this connection can use any materials from the silo * Returns true only if * - The parent is of type movable atom * - A mat container is actually present @@ -217,9 +223,7 @@ handles linking back and forth. * Arguments * * check_hold - should we check if the silo is on hold */ -/datum/component/remote_materials/proc/_can_use_resource(check_hold = TRUE) - PRIVATE_PROC(TRUE) - +/datum/component/remote_materials/proc/can_use_resource(check_hold = TRUE) var/atom/movable/movable_parent = parent if (!istype(movable_parent)) return FALSE @@ -243,7 +247,7 @@ handles linking back and forth. * name- For logging only. the design you are trying to build e.g. matter bin, etc. */ /datum/component/remote_materials/proc/use_materials(list/mats, coefficient = 1, multiplier = 1, action = "build", name = "design") - if(!_can_use_resource()) + if(!can_use_resource()) return 0 var/amount_consumed = mat_container.use_materials(mats, coefficient, multiplier) @@ -265,7 +269,7 @@ handles linking back and forth. * [drop_target][atom]- optional where to drop the sheets. null means it is dropped at this components parent location */ /datum/component/remote_materials/proc/eject_sheets(datum/material/material_ref, eject_amount, atom/drop_target = null) - if(!_can_use_resource()) + if(!can_use_resource()) return 0 var/atom/movable/movable_parent = parent @@ -282,7 +286,7 @@ handles linking back and forth. * * multiplier - the multiplier applied on the materials consumed */ /datum/component/remote_materials/proc/insert_item(obj/item/weapon, multiplier = 1) - if(!_can_use_resource(FALSE)) + if(!can_use_resource(FALSE)) return MATERIAL_INSERT_ITEM_FAILURE return mat_container.insert_item(weapon, multiplier, parent) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 03473ed5d39..f6600942cde 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -7,24 +7,24 @@ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.5 circuit = /obj/item/circuitboard/machine/autolathe layer = BELOW_OBJ_LAYER + processing_flags = NONE + ///Is the autolathe hacked via wiring var/hacked = FALSE + ///Is the autolathe disabled via wiring var/disabled = FALSE + ///Did we recently shock a mob who medled with the wiring var/shocked = FALSE + ///Are we currently printing something var/busy = FALSE - - /// Coefficient applied to consumed materials. Lower values result in lower material consumption. + ///Coefficient applied to consumed materials. Lower values result in lower material consumption. var/creation_efficiency = 1.6 - - var/datum/design/being_built + ///Designs related to the autolathe var/datum/techweb/autounlocking/stored_research - ///Designs imported from technology disks that we can print. var/list/imported_designs = list() - ///The container to hold materials var/datum/component/material_container/materials - ///direction we output onto (if 0, on top of us) var/drop_direction = 0 @@ -43,17 +43,69 @@ GLOB.autounlock_techwebs[/datum/techweb/autounlocking/autolathe] = new /datum/techweb/autounlocking/autolathe stored_research = GLOB.autounlock_techwebs[/datum/techweb/autounlocking/autolathe] + register_context() + /obj/machinery/autolathe/Destroy() materials = null QDEL_NULL(wires) return ..() +/obj/machinery/autolathe/examine(mob/user) + . = ..() + if(!in_range(user, src) && !isobserver(user)) + return + + . += span_notice("Material usage cost at [creation_efficiency * 100]%") + if(drop_direction) + . += span_notice("Currently configured to drop printed objects [dir2text(drop_direction)].") + . += span_notice("[EXAMINE_HINT("Alt-click")] to reset.") + else + . += span_notice("[EXAMINE_HINT("Drag")] towards a direction (while next to it) to change drop direction.") + + . += span_notice("Its maintainence panel can be [EXAMINE_HINT("screwed")] [panel_open ? "closed" : "open"].") + if(panel_open) + . += span_notice("The machine can be [EXAMINE_HINT("pried")] apart.") + +/obj/machinery/autolathe/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(drop_direction) + context[SCREENTIP_CONTEXT_ALT_LMB] = "Reset Drop" + return CONTEXTUAL_SCREENTIP_SET + + if(isnull(held_item)) + return NONE + + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_RMB] = "[panel_open ? "Close" : "Open"] Panel" + return CONTEXTUAL_SCREENTIP_SET + + if(panel_open && held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/autolathe/crowbar_act(mob/living/user, obj/item/tool) + . = ITEM_INTERACT_BLOCKING + if(default_deconstruction_crowbar(tool)) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/autolathe/screwdriver_act_secondary(mob/living/user, obj/item/tool) + . = ITEM_INTERACT_BLOCKING + if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", tool)) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/autolathe/proc/AfterMaterialInsert(container, obj/item/item_inserted, last_inserted_id, mats_consumed, amount_inserted, atom/context) + SIGNAL_HANDLER + + flick("autolathe_[item_inserted.has_material_type(/datum/material/glass) ? "r" : "o"]", src) + + directly_use_power(round((amount_inserted / SHEET_MATERIAL_AMOUNT) * active_power_usage * 0.0025)) + /obj/machinery/autolathe/ui_interact(mob/user, datum/tgui/ui) if(!is_operational) return if(shocked && !(machine_stat & NOPOWER)) shock(user, 50) + return ui = SStgui.try_update_ui(user, src, ui) @@ -61,66 +113,40 @@ ui = new(user, src, "Autolathe") ui.open() -/obj/machinery/autolathe/ui_static_data(mob/user) - var/list/data = materials.ui_static_data() - - var/max_available = materials.total_amount() - for(var/datum/material/container_mat as anything in materials.materials) - var/available = materials.materials[container_mat] - if(available) - max_available = max(max_available, available) - - data["designs"] = handle_designs(stored_research.researched_designs, max_available) - if(imported_designs.len) - data["designs"] += handle_designs(imported_designs, max_available) - if(hacked) - data["designs"] += handle_designs(stored_research.hacked_designs, max_available) - - return data - -/obj/machinery/autolathe/ui_data(mob/user) - var/list/data = list() - - data["materials"] = list() - data["materialtotal"] = materials.total_amount() - data["materialsmax"] = materials.max_amount - data["active"] = busy - data["materials"] = materials.ui_data() - return data +/** + * Converts all the designs supported by this autolathe into UI data + * Arguments + * + * * list/designs - the list of techweb designs we are trying to send to the UI + */ +/obj/machinery/autolathe/proc/handle_designs(list/designs) + PRIVATE_PROC(TRUE) -/obj/machinery/autolathe/proc/handle_designs(list/designs, max_available) var/list/output = list() var/datum/asset/spritesheet/research_designs/spritesheet = get_asset_datum(/datum/asset/spritesheet/research_designs) var/size32x32 = "[spritesheet.name]32x32" - var/max_multiplier = INFINITY for(var/design_id in designs) var/datum/design/design = SSresearch.techweb_design_by_id(design_id) if(design.make_reagent) continue //compute cost & maximum number of printable items - max_multiplier = INFINITY var/coeff = (ispath(design.build_path, /obj/item/stack) ? 1 : creation_efficiency) var/list/cost = list() + var/customMaterials = FALSE for(var/i in design.materials) var/datum/material/mat = i var/design_cost = OPTIMAL_COST(design.materials[i] * coeff) if(istype(mat)) cost[mat.name] = design_cost + customMaterials = FALSE else cost[i] = design_cost - - var/mat_available - if(istype(mat)) //regular mat - mat_available = materials.get_material_amount(mat) - else //category mat means we can make it from any mat, use largest available mat - mat_available = max_available - - max_multiplier = min(max_multiplier, 50, round(mat_available / design_cost)) + customMaterials = TRUE //create & send ui data var/icon_size = spritesheet.icon_size_id(design.id) @@ -131,65 +157,87 @@ "id" = design.id, "categories" = design.category, "icon" = "[icon_size == size32x32 ? "" : "[icon_size] "][design.id]", - "constructionTime" = -1, - "maxmult" = max_multiplier + "customMaterials" = customMaterials ) output += list(design_data) return output +/obj/machinery/autolathe/ui_static_data(mob/user) + var/list/data = materials.ui_static_data() + + data["designs"] = handle_designs(stored_research.researched_designs) + if(imported_designs.len) + data["designs"] += handle_designs(imported_designs) + if(hacked) + data["designs"] += handle_designs(stored_research.hacked_designs) + + return data + + /obj/machinery/autolathe/ui_assets(mob/user) return list( get_asset_datum(/datum/asset/spritesheet/sheetmaterials), get_asset_datum(/datum/asset/spritesheet/research_designs), ) +/obj/machinery/autolathe/ui_data(mob/user) + var/list/data = list() + + data["materials"] = list() + data["materialtotal"] = materials.total_amount() + data["materialsmax"] = materials.max_amount + data["active"] = busy + data["materials"] = materials.ui_data() + + return data + /obj/machinery/autolathe/ui_act(action, list/params, datum/tgui/ui) . = ..() if(.) return + //sanity checks to start printing if(action != "make") stack_trace("unknown autolathe ui_act: [action]") return - if(disabled) say("Unable to print, voltage mismatch in internal wiring.") return - if(busy) - balloon_alert(ui.user, "busy!") - return - - var/turf/target_location = get_step(src, drop_direction) - if(isclosedturf(target_location)) - say("Output path is obstructed by a large object.") + say("currently printing.") return + //validate design var/design_id = params["id"] - + if(!design_id) + return var/valid_design = stored_research.researched_designs[design_id] valid_design ||= stored_research.hacked_designs[design_id] valid_design ||= imported_designs[design_id] if(!valid_design) return - var/datum/design/design = SSresearch.techweb_design_by_id(design_id) if(isnull(design)) stack_trace("got passed an invalid design id: [design_id] and somehow made it past all checks") return - if(!(design.build_type & AUTOLATHE)) + say("This fabricator does not have the necessary keys to decrypt this design.") return - var/build_count = text2num(params["multiplier"]) - if(!build_count) + //validate print quantity + var/build_count = params["multiplier"] + if(isnull(build_count)) + return + build_count = text2num(build_count) + if(isnull(build_count)) return build_count = clamp(build_count, 1, 50) + //check for materials required. For custom material items decode their required materials var/list/materials_needed = list() - for(var/datum/material/material as anything in design.materials) + for(var/material in design.materials) var/amount_needed = design.materials[material] if(istext(material)) // category var/list/choices = list() @@ -215,64 +263,70 @@ return materials_needed[material] = amount_needed + //checks for available materials var/material_cost_coefficient = ispath(design.build_path, /obj/item/stack) ? 1 : creation_efficiency if(!materials.has_materials(materials_needed, material_cost_coefficient, build_count)) say("Not enough materials to begin production.") return - //use power - var/total_charge = 0 + //compute power & time to print 1 item + var/charge_per_item = 0 for(var/material in design.materials) - total_charge += round(design.materials[material] * material_cost_coefficient * build_count) - var/charge_per_item = total_charge / build_count - - var/total_time = (design.construction_time * design.lathe_time_factor * build_count) ** 0.8 - var/time_per_item = total_time / build_count - start_making(design, build_count, time_per_item, material_cost_coefficient, charge_per_item) - return TRUE - -/// Begins the act of making the given design the given number of items -/// Does not check or use materials/power/etc -/obj/machinery/autolathe/proc/start_making(datum/design/design, build_count, build_time_per_item, material_cost_coefficient, charge_per_item) - PROTECTED_PROC(TRUE) + charge_per_item += design.materials[material] + charge_per_item = min(active_power_usage, round(charge_per_item * material_cost_coefficient)) + var/build_time_per_item = (design.construction_time * design.lathe_time_factor) ** 0.8 + //do the printing sequentially busy = TRUE icon_state = "autolathe_n" - update_static_data_for_all_viewers() + SStgui.update_uis(src) + var/turf/target_location + if(drop_direction) + target_location = get_step(src, drop_direction) + if(isclosedturf(target_location)) + target_location = get_turf(src) + else + target_location = get_turf(src) + addtimer(CALLBACK(src, PROC_REF(do_make_item), design, build_count, build_time_per_item, material_cost_coefficient, charge_per_item, materials_needed, target_location), build_time_per_item) - addtimer(CALLBACK(src, PROC_REF(do_make_item), design, material_cost_coefficient, build_time_per_item, charge_per_item, build_count), build_time_per_item) + return TRUE -/// Callback for start_making, actually makes the item -/// Called using timers started by start_making -/obj/machinery/autolathe/proc/do_make_item(datum/design/design, material_cost_coefficient, time_per_item, charge_per_item, items_remaining) +/** + * Callback for start_making, actually makes the item + * Arguments + * + * * datum/design/design - the design we are trying to print + * * items_remaining - the number of designs left out to print + * * build_time_per_item - the time taken to print 1 item + * * material_cost_coefficient - the cost efficiency to print 1 design + * * charge_per_item - the amount of power to print 1 item + * * list/materials_needed - the list of materials to print 1 item + * * turf/target - the location to drop the printed item on +*/ +/obj/machinery/autolathe/proc/do_make_item(datum/design/design, items_remaining, build_time_per_item, material_cost_coefficient, charge_per_item, list/materials_needed, turf/target) PROTECTED_PROC(TRUE) - if(!items_remaining) // how + if(items_remaining <= 0) // how finalize_build() return - if(!directly_use_power(charge_per_item)) + if(!is_operational || !directly_use_power(charge_per_item)) say("Unable to continue production, power failure.") finalize_build() return - var/list/design_materials = design.materials var/is_stack = ispath(design.build_path, /obj/item/stack) - if(!materials.has_materials(design_materials, material_cost_coefficient, is_stack ? items_remaining : 1)) + if(!materials.has_materials(materials_needed, material_cost_coefficient, is_stack ? items_remaining : 1)) say("Unable to continue production, missing materials.") return - materials.use_materials(design_materials, material_cost_coefficient, is_stack ? items_remaining : 1) - - var/turf/target = get_step(src, drop_direction) - if(isclosedturf(target)) - target = get_turf(src) + materials.use_materials(materials_needed, material_cost_coefficient, is_stack ? items_remaining : 1) var/atom/movable/created if(is_stack) created = new design.build_path(target, items_remaining) else created = new design.build_path(target) - split_materials_uniformly(design_materials, material_cost_coefficient, created) + split_materials_uniformly(materials_needed, material_cost_coefficient, created) created.pixel_x = created.base_pixel_x + rand(-6, 6) created.pixel_y = created.base_pixel_y + rand(-6, 6) @@ -283,26 +337,44 @@ else items_remaining -= 1 - if(!items_remaining) + if(items_remaining <= 0) finalize_build() return - addtimer(CALLBACK(src, PROC_REF(do_make_item), design, material_cost_coefficient, time_per_item, items_remaining), time_per_item) + addtimer(CALLBACK(src, PROC_REF(do_make_item), design, items_remaining, build_time_per_item, material_cost_coefficient, charge_per_item, materials_needed, target), build_time_per_item) -/// Resets the icon state and busy flag -/// Called at the end of do_make_item's timer loop +/** + * Resets the icon state and busy flag + * Called at the end of do_make_item's timer loop +*/ /obj/machinery/autolathe/proc/finalize_build() PROTECTED_PROC(TRUE) + icon_state = initial(icon_state) busy = FALSE - update_static_data_for_all_viewers() + SStgui.update_uis(src) -/obj/machinery/autolathe/crowbar_act(mob/living/user, obj/item/tool) - if(default_deconstruction_crowbar(tool)) - return ITEM_INTERACT_SUCCESS +/obj/machinery/autolathe/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) + . = ..() + if((!issilicon(usr) && !isAdminGhostAI(usr)) && !Adjacent(usr)) + return + if(busy) + balloon_alert(usr, "printing started!") + return + var/direction = get_dir(src, over_location) + if(!direction) + return + drop_direction = direction + balloon_alert(usr, "dropping [dir2text(drop_direction)]") -/obj/machinery/autolathe/screwdriver_act_secondary(mob/living/user, obj/item/tool) - if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", tool)) - return ITEM_INTERACT_SUCCESS +/obj/machinery/autolathe/AltClick(mob/user) + . = ..() + if(!drop_direction || !can_interact(user)) + return + if(busy) + balloon_alert(user, "busy printing!") + return + balloon_alert(user, "drop direction reset") + drop_direction = 0 /obj/machinery/autolathe/attackby(obj/item/attacking_item, mob/living/user, params) if(user.combat_mode) //so we can hit the machine @@ -346,25 +418,6 @@ return ..() -/obj/machinery/autolathe/proc/AfterMaterialInsert(container, obj/item/item_inserted, last_inserted_id, mats_consumed, amount_inserted, atom/context) - SIGNAL_HANDLER - - flick("autolathe_[item_inserted.has_material_type(/datum/material/glass) ? "r" : "o"]", src) - - use_power(min(active_power_usage * 0.25, amount_inserted / SHEET_MATERIAL_AMOUNT)) - - update_static_data_for_all_viewers() - -/obj/machinery/autolathe/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) - . = ..() - if((!issilicon(usr) && !isAdminGhostAI(usr)) && !Adjacent(usr)) - return - var/direction = get_dir(src, over_location) - if(!direction) - return - drop_direction = direction - balloon_alert(usr, "dropping [dir2text(drop_direction)]") - /obj/machinery/autolathe/RefreshParts() . = ..() var/mat_capacity = 0 @@ -377,24 +430,12 @@ efficiency -= new_servo.tier * 0.2 creation_efficiency = max(1,efficiency) // creation_efficiency goes 1.6 -> 1.4 -> 1.2 -> 1 per level of servo efficiency -/obj/machinery/autolathe/examine(mob/user) - . += ..() - if(in_range(user, src) || isobserver(user)) - . += span_notice("The status display reads: Storing up to [materials.max_amount] material units.
Material consumption at [creation_efficiency*100]%.") - if(drop_direction) - . += span_notice("Currently configured to drop printed objects [dir2text(drop_direction)].") - . += span_notice("Alt-click to reset.") - else - . += span_notice("Drag towards a direction (while next to it) to change drop direction.") - -/obj/machinery/autolathe/AltClick(mob/user) - . = ..() - if(!can_interact(user)) - return - if(drop_direction) - balloon_alert(user, "drop direction reset") - drop_direction = 0 - +/** + * Cut a wire in the autolathe + * Arguments + * + * * wire - the wire we are trying to cut + */ /obj/machinery/autolathe/proc/reset(wire) switch(wire) if(WIRE_HACK) @@ -407,6 +448,13 @@ if(!wires.is_cut(wire)) disabled = FALSE +/** + * Shock a mob who is trying to interact with the autolathe + * Arguments + * + * * mob/user - the mob we are trying to shock + * * prb - the probability of getting shocked + */ /obj/machinery/autolathe/proc/shock(mob/user, prb) if(machine_stat & (BROKEN|NOPOWER)) // unpowered, no shock return FALSE @@ -417,6 +465,12 @@ s.start() return electrocute_mob(user, get_area(src), src, 0.7, TRUE) +/** + * Is the autolathe hacked. Allowing us to acess hidden designs + * Arguments + * + * state - TRUE/FALSE for is the autolathe hacked + */ /obj/machinery/autolathe/proc/adjust_hacked(state) hacked = state update_static_data_for_all_viewers() diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 24dd69e2297..851e08beb15 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -309,9 +309,6 @@ greyscale_colors = CIRCUIT_COLOR_ENGINEERING build_path = /obj/machinery/rnd/production/protolathe/department/engineering -/obj/item/circuitboard/machine/protolathe/department/engineering/no_tax - build_path = /obj/machinery/rnd/production/protolathe/department/engineering/no_tax - /obj/item/circuitboard/machine/rtg name = "RTG" greyscale_colors = CIRCUIT_COLOR_ENGINEERING diff --git a/code/modules/mapfluff/ruins/spaceruin_code/oldstation/oldstation_rnd.dm b/code/modules/mapfluff/ruins/spaceruin_code/oldstation/oldstation_rnd.dm index 58d14e0d041..5f0935bb8bd 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/oldstation/oldstation_rnd.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/oldstation/oldstation_rnd.dm @@ -4,15 +4,24 @@ req_access = list(ACCESS_AWAY_SCIENCE) /obj/machinery/rnd/server/oldstation/Initialize(mapload) - register_context() var/datum/techweb/oldstation_web = locate(/datum/techweb/oldstation) in SSresearch.techwebs stored_research = oldstation_web return ..() /obj/machinery/rnd/server/oldstation/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(held_item && istype(held_item, /obj/item/research_notes)) context[SCREENTIP_CONTEXT_LMB] = "Generate research points" - return CONTEXTUAL_SCREENTIP_SET + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/rnd/server/oldstation/examine(mob/user) + . = ..() + + if(!in_range(user, src) && !isobserver(user)) + return + + . += span_notice("Insert [EXAMINE_HINT("Research Notes")] to generate points.") /obj/machinery/rnd/server/oldstation/attackby(obj/item/attacking_item, mob/user, params) if(istype(attacking_item, /obj/item/research_notes) && stored_research) diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm index 72fd12ced70..e9e34bfd806 100644 --- a/code/modules/research/destructive_analyzer.dm +++ b/code/modules/research/destructive_analyzer.dm @@ -14,16 +14,29 @@ base_icon_state = "d_analyzer" circuit = /obj/item/circuitboard/machine/destructive_analyzer -/obj/machinery/rnd/destructive_analyzer/Initialize(mapload) +/obj/machinery/rnd/destructive_analyzer/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) . = ..() - register_context() -/obj/machinery/rnd/destructive_analyzer/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + var/screentip_set = FALSE if(loaded_item) context[SCREENTIP_CONTEXT_ALT_LMB] = "Remove Item" + screentip_set = TRUE else if(!isnull(held_item)) context[SCREENTIP_CONTEXT_LMB] = "Insert Item" - return CONTEXTUAL_SCREENTIP_SET + screentip_set = TRUE + + if(screentip_set) + . = CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/rnd/destructive_analyzer/examine(mob/user) + . = ..() + if(!in_range(user, src) && !isobserver(user)) + return + + if(loaded_item) + . += span_notice("[EXAMINE_HINT("Left-Click")] to remove loaded item inside.") + else + . += span_notice("An item can be loaded inside via [EXAMINE_HINT("Left-Click")].") /obj/machinery/rnd/destructive_analyzer/attackby(obj/item/weapon, mob/living/user, params) if(user.combat_mode) diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index dd282040ab0..0ae8df4d8a4 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -1,38 +1,37 @@ /obj/machinery/rnd/production name = "technology fabricator" desc = "Makes researched and prototype items with materials and energy." - layer = BELOW_OBJ_LAYER /// The efficiency coefficient. Material costs and print times are multiplied by this number; - /// better parts result in a higher efficiency (and lower value). var/efficiency_coeff = 1 - /// The material storage used by this fabricator. var/datum/component/remote_materials/materials - /// Which departments are allowed to process this design var/allowed_department_flags = ALL - - /// What's flick()'d on print. + /// Icon state when production has started var/production_animation - /// The types of designs this fabricator can print. var/allowed_buildtypes = NONE - /// All designs in the techweb that can be fabricated by this machine, since the last update. var/list/datum/design/cached_designs - /// What color is this machine's stripe? Leave null to not have a stripe. var/stripe_color = null - - /// Does this charge the user's ID on fabrication? - var/charges_tax = TRUE + ///direction we output onto (if 0, on top of us) + var/drop_direction = 0 /obj/machinery/rnd/production/Initialize(mapload) . = ..() cached_designs = list() - materials = AddComponent(/datum/component/remote_materials, mapload) + materials = AddComponent( + /datum/component/remote_materials, \ + mapload, \ + mat_container_signals = list( \ + COMSIG_MATCONTAINER_ITEM_CONSUMED = TYPE_PROC_REF(/obj/machinery/rnd, local_material_insert) + ) \ + ) + + RegisterSignal(src, COMSIG_SILO_ITEM_CONSUMED, TYPE_PROC_REF(/obj/machinery/rnd/production, silo_material_insert)) AddComponent( /datum/component/payment, \ @@ -42,9 +41,49 @@ TRUE, \ ) - RefreshParts() update_icon(UPDATE_OVERLAYS) +/obj/machinery/rnd/production/Destroy() + materials = null + cached_designs = null + return ..() + + +// Stuff for the stripe on the department machines +/obj/machinery/rnd/production/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + . = ..() + + update_icon(UPDATE_OVERLAYS) + +/obj/machinery/rnd/production/update_overlays() + . = ..() + + if(!stripe_color) + return + + var/mutable_appearance/stripe = mutable_appearance('icons/obj/machines/research.dmi', "protolathe_stripe[panel_open ? "_t" : ""]") + stripe.color = stripe_color + . += stripe + + +/obj/machinery/rnd/production/examine(mob/user) + . = ..() + if(!in_range(user, src) && !isobserver(user)) + return + + . += span_notice("Material usage cost at [efficiency_coeff * 100]%") + if(drop_direction) + . += span_notice("Currently configured to drop printed objects [dir2text(drop_direction)].") + . += span_notice("[EXAMINE_HINT("Alt-click")] to reset.") + else + . += span_notice("[EXAMINE_HINT("Drag")] towards a direction (while next to it) to change drop direction.") + +/obj/machinery/rnd/production/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(drop_direction) + context[SCREENTIP_CONTEXT_ALT_LMB] = "Reset Drop" + return CONTEXTUAL_SCREENTIP_SET + /obj/machinery/rnd/production/connect_techweb(datum/techweb/new_techweb) if(stored_research) UnregisterSignal(stored_research, list(COMSIG_TECHWEB_ADD_DESIGN, COMSIG_TECHWEB_REMOVE_DESIGN)) @@ -55,24 +94,14 @@ RegisterSignals( stored_research, list(COMSIG_TECHWEB_ADD_DESIGN, COMSIG_TECHWEB_REMOVE_DESIGN), - PROC_REF(on_techweb_update) + TYPE_PROC_REF(/obj/machinery/rnd/production, on_techweb_update) ) update_designs() -/obj/machinery/rnd/production/Destroy() - materials = null - cached_designs = null - return ..() - -/obj/machinery/rnd/production/proc/on_techweb_update() - SIGNAL_HANDLER - - // We're probably going to get more than one update (design) at a time, so batch - // them together. - addtimer(CALLBACK(src, PROC_REF(update_designs)), 2 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) - /// Updates the list of designs this fabricator can print. /obj/machinery/rnd/production/proc/update_designs() + PROTECTED_PROC(TRUE) + var/previous_design_count = cached_designs.len cached_designs.Cut() @@ -91,12 +120,98 @@ update_static_data_for_all_viewers() +/obj/machinery/rnd/production/proc/on_techweb_update() + SIGNAL_HANDLER + + // We're probably going to get more than one update (design) at a time, so batch + // them together. + addtimer(CALLBACK(src, PROC_REF(update_designs)), 2 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) + +///When materials are instered via silo link +/obj/machinery/rnd/proc/silo_material_insert(obj/machinery/rnd/machine, container, obj/item/item_inserted, last_inserted_id, list/mats_consumed, amount_inserted) + SIGNAL_HANDLER + + process_item(item_inserted, mats_consumed, amount_inserted) + +/** + * Consumes power for the item inserted either into silo or local storage. + * Arguments + * + * * obj/item/item_inserted - the item to process + * * list/mats_consumed - list of mats consumed + * * amount_inserted - amount of material actually processed + */ +/obj/machinery/rnd/proc/process_item(obj/item/item_inserted, list/mats_consumed, amount_inserted) + PRIVATE_PROC(TRUE) + + if(directly_use_power(round((amount_inserted / SHEET_MATERIAL_AMOUNT) * active_power_usage * 0.00025))) + var/mat_name = "iron" + + var/highest_mat = 0 + for(var/datum/material/mat as anything in mats_consumed) + var/present_mat = mats_consumed[mat] + if(present_mat > highest_mat) + mat_name = initial(mat.name) + if(mat_name == "silver" || mat_name == "titanium" || mat_name == "plastic") //these materials have similar appearances so use an common overlay for them + mat_name = "shiny" + highest_mat = present_mat + + flick_animation(mat_name) +/** + * Plays an visual animation when materials are inserted + * Arguments + * + * * mat_name - the name of the material we are trying to animate on the machine + */ +/obj/machinery/rnd/proc/flick_animation(mat_name) + PROTECTED_PROC(TRUE) + SHOULD_CALL_PARENT(FALSE) + + flick_overlay_view(mutable_appearance('icons/obj/machines/research.dmi', "protolathe_[mat_name]"), 1 SECONDS) + +///When materials are instered into local storage +/obj/machinery/rnd/proc/local_material_insert(container, obj/item/item_inserted, last_inserted_id, list/mats_consumed, amount_inserted, atom/context) + SIGNAL_HANDLER + + process_item(item_inserted, mats_consumed, amount_inserted) + /obj/machinery/rnd/production/RefreshParts() . = ..() - calculate_efficiency() + if(materials) + var/total_storage = 0 + for(var/datum/stock_part/matter_bin/bin in component_parts) + total_storage += bin.tier * 37.5 * SHEET_MATERIAL_AMOUNT + materials.set_local_size(total_storage) + + efficiency_coeff = compute_efficiency() + update_static_data_for_all_viewers() +///Computes this machines cost efficiency based on the available parts +/obj/machinery/rnd/production/proc/compute_efficiency() + PROTECTED_PROC(TRUE) + + var/efficiency = 1.2 + for(var/datum/stock_part/servo/servo in component_parts) + efficiency -= servo.tier * 0.1 + + return efficiency + +/** + * The cost efficiency for an particular design + * Arguments + * + * * path - the design path to check for + */ +/obj/machinery/rnd/production/proc/build_efficiency(path) + PROTECTED_PROC(TRUE) // NOVA EDIT CHANGE - ORIGINAL: PRIVATE_PROC(TRUE) + + if(ispath(path, /obj/item/stack/sheet) || ispath(path, /obj/item/stack/ore/bluespace_crystal)) + return 1 + else + return efficiency_coeff + /obj/machinery/rnd/production/ui_assets(mob/user) return list( get_asset_datum(/datum/asset/spritesheet/sheetmaterials), @@ -117,16 +232,13 @@ var/datum/asset/spritesheet/research_designs/spritesheet = get_asset_datum(/datum/asset/spritesheet/research_designs) var/size32x32 = "[spritesheet.name]32x32" - var/max_multiplier = INFINITY var/coefficient for(var/datum/design/design in cached_designs) var/cost = list() - max_multiplier = INFINITY coefficient = build_efficiency(design.build_path) for(var/datum/material/mat in design.materials) cost[mat.name] = OPTIMAL_COST(design.materials[mat] * coefficient) - max_multiplier = min(max_multiplier, 50, round(materials.mat_container.get_material_amount(mat) / cost[mat.name])) var/icon_size = spritesheet.icon_size_id(design.id) designs[design.id] = list( @@ -135,9 +247,7 @@ "cost" = cost, "id" = design.id, "categories" = design.category, - "icon" = "[icon_size == size32x32 ? "" : "[icon_size] "][design.id]", - "constructionTime" = 0, - "maxmult" = max_multiplier + "icon" = "[icon_size == size32x32 ? "" : "[icon_size] "][design.id]" ) data["designs"] = designs @@ -158,141 +268,127 @@ /obj/machinery/rnd/production/ui_act(action, list/params, datum/tgui/ui) . = ..() - if(.) return - . = TRUE - switch (action) if("remove_mat") var/datum/material/material = locate(params["ref"]) - var/amount = text2num(params["amount"]) - // SAFETY: eject_sheets checks for valid mats - materials.eject_sheets(material, amount) - - if("build") - user_try_print_id(ui.user, params["ref"], params["amount"]) - -/// Updates the fabricator's efficiency coefficient based on the installed parts. -/obj/machinery/rnd/production/proc/calculate_efficiency() - efficiency_coeff = 1 - - if(materials) - var/total_storage = 0 - - for(var/datum/stock_part/matter_bin/bin in component_parts) - total_storage += bin.tier * (37.5*SHEET_MATERIAL_AMOUNT) - - materials.set_local_size(total_storage) - - var/total_rating = 1.2 - - for(var/datum/stock_part/servo/servo in component_parts) - total_rating -= servo.tier * 0.1 - - efficiency_coeff = max(total_rating, 0) - -/obj/machinery/rnd/production/proc/build_efficiency(path) - if(ispath(path, /obj/item/stack/sheet) || ispath(path, /obj/item/stack/ore/bluespace_crystal)) - return 1 - else - return efficiency_coeff - -/obj/machinery/rnd/production/proc/user_try_print_id(mob/user, design_id, print_quantity) - if(!design_id) - return FALSE - - if(istext(print_quantity)) - print_quantity = text2num(print_quantity) - - if(isnull(print_quantity)) - print_quantity = 1 - - var/datum/design/design = stored_research.researched_designs[design_id] ? SSresearch.techweb_design_by_id(design_id) : null - - if(!istype(design)) - return FALSE - - if(busy) - say("Warning: fabricator is busy!") - return FALSE - - if(!(isnull(allowed_department_flags) || (design.departmental_flags & allowed_department_flags))) - say("This fabricator does not have the necessary keys to decrypt this design.") - return FALSE - - if(design.build_type && !(design.build_type & allowed_buildtypes)) - say("This fabricator does not have the necessary manipulation systems for this design.") - return FALSE + if(!istype(material)) + return - if(!materials.mat_container) - say("No connection to material storage, please contact the quartermaster.") - return FALSE + var/amount = params["amount"] + if(isnull(amount)) + return - if(materials.on_hold()) - say("Mineral access is on hold, please contact the quartermaster.") - return FALSE + amount = text2num(amount) + if(isnull(amount)) + return - print_quantity = clamp(print_quantity, 1, 50) - var/coefficient = build_efficiency(design.build_path) - - // check if sufficient materials are available. - if(!materials.mat_container.has_materials(design.materials, coefficient, print_quantity)) - say("Not enough materials to complete prototype[print_quantity > 1 ? "s" : ""].") - return FALSE - - //use power - var/total_charge = 0 - for(var/material in design.materials) - total_charge += round(design.materials[material] * coefficient * print_quantity / 35) - var/charge_per_item = total_charge / print_quantity - - if(production_animation) - flick(production_animation, src) - - var/total_time = (design.construction_time * design.lathe_time_factor * print_quantity) ** 0.8 - var/time_per_item = total_time / print_quantity - start_making(design, print_quantity, time_per_item, coefficient, charge_per_item) - - return TRUE - -/// Begins the act of making the given design the given number of items -/// Does not check or use materials/power/etc -/obj/machinery/rnd/production/proc/start_making(datum/design/design, build_count, build_time_per_item, build_efficiency, charge_per_item) - PROTECTED_PROC(TRUE) - - busy = TRUE - update_static_data_for_all_viewers() - addtimer(CALLBACK(src, PROC_REF(do_make_item), design, build_efficiency, build_time_per_item, charge_per_item, build_count), build_time_per_item) + materials.eject_sheets(material, amount) + return TRUE -/// Callback for start_making, actually makes the item -/// Called using timers started by start_making -/obj/machinery/rnd/production/proc/do_make_item(datum/design/design, build_efficiency, time_per_item, charge_per_item, items_remaining) + if("build") + if(busy) + say("Warning: fabricator is busy!") + return + + //validate design + var/design_id = params["ref"] + if(!design_id) + return + var/datum/design/design = stored_research.researched_designs[design_id] ? SSresearch.techweb_design_by_id(design_id) : null + if(!istype(design)) + return FALSE + if(!(isnull(allowed_department_flags) || (design.departmental_flags & allowed_department_flags))) + say("This fabricator does not have the necessary keys to decrypt this design.") + return FALSE + if(design.build_type && !(design.build_type & allowed_buildtypes)) + say("This fabricator does not have the necessary manipulation systems for this design.") + return FALSE + + //validate print quantity + var/print_quantity = params["amount"] + if(isnull(print_quantity)) + return + print_quantity = text2num(print_quantity) + if(isnull(print_quantity)) + return + print_quantity = clamp(print_quantity, 1, 50) + + //efficiency for this design, stacks use exact materials + var/coefficient = build_efficiency(design.build_path) + + //check for materials + if(!materials.can_use_resource()) + return + if(!materials.mat_container.has_materials(design.materials, coefficient, print_quantity)) + say("Not enough materials to complete prototype[print_quantity > 1 ? "s" : ""].") + return FALSE + + //compute power & time to print 1 item + var/charge_per_item = 0 + for(var/material in design.materials) + charge_per_item += design.materials[material] + charge_per_item = min(active_power_usage, round(charge_per_item * coefficient)) + var/build_time_per_item = (design.construction_time * design.lathe_time_factor) ** 0.8 + + //start production + busy = TRUE + SStgui.update_uis(src) + if(production_animation) + icon_state = production_animation + start_printing_visuals() // NOVA EDIT ADDITION - COLONY FABRICATOR STUFF + var/turf/target_location + if(drop_direction) + target_location = get_step(src, drop_direction) + if(isclosedturf(target_location)) + target_location = get_turf(src) + else + target_location = get_turf(src) + addtimer(CALLBACK(src, PROC_REF(do_make_item), design, print_quantity, build_time_per_item, coefficient, charge_per_item, target_location), build_time_per_item) + + return TRUE + +/** + * Callback for start_making, actually makes the item + * Arguments + * + * * datum/design/design - the design we are trying to print + * * items_remaining - the number of designs left out to print + * * build_time_per_item - the time taken to print 1 item + * * material_cost_coefficient - the cost efficiency to print 1 design + * * charge_per_item - the amount of power to print 1 item + * * turf/target - the location to drop the printed item on +*/ +/obj/machinery/rnd/production/proc/do_make_item(datum/design/design, items_remaining, build_time_per_item, material_cost_coefficient, charge_per_item, turf/target) PROTECTED_PROC(TRUE) if(!items_remaining) // how finalize_build() return - if(!directly_use_power(charge_per_item)) + if(!is_operational || !directly_use_power(charge_per_item)) say("Unable to continue production, power failure.") finalize_build() return + if(!materials.can_use_resource()) + finalize_build() + return var/is_stack = ispath(design.build_path, /obj/item/stack) var/list/design_materials = design.materials - if(!materials.mat_container.has_materials(design_materials, build_efficiency, is_stack ? items_remaining : 1)) + if(!materials.mat_container.has_materials(design_materials, material_cost_coefficient, is_stack ? items_remaining : 1)) say("Unable to continue production, missing materials.") return - materials.use_materials(design_materials, build_efficiency, is_stack ? items_remaining : 1, "built", "[design.name]") + materials.use_materials(design_materials, material_cost_coefficient, is_stack ? items_remaining : 1, "built", "[design.name]") var/atom/movable/created if(is_stack) - created = new design.build_path(get_turf(src), items_remaining) + created = new design.build_path(target, items_remaining) else - created = new design.build_path(get_turf(src)) - split_materials_uniformly(design_materials, build_efficiency, created) + created = new design.build_path(target) + split_materials_uniformly(design_materials, material_cost_coefficient, created) created.pixel_x = created.base_pixel_x + rand(-6, 6) created.pixel_y = created.base_pixel_y + rand(-6, 6) @@ -305,40 +401,36 @@ if(!items_remaining) finalize_build() return - addtimer(CALLBACK(src, PROC_REF(do_make_item), design, build_efficiency, time_per_item, items_remaining), time_per_item) + addtimer(CALLBACK(src, PROC_REF(do_make_item), design, items_remaining, build_time_per_item, material_cost_coefficient, charge_per_item, target), build_time_per_item) /// Resets the busy flag /// Called at the end of do_make_item's timer loop /obj/machinery/rnd/production/proc/finalize_build() PROTECTED_PROC(TRUE) - busy = FALSE - update_static_data_for_all_viewers() -// Stuff for the stripe on the department machines -/obj/machinery/rnd/production/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) - . = ..() - - update_icon(UPDATE_OVERLAYS) + busy = FALSE + SStgui.update_uis(src) + icon_state = initial(icon_state) -/obj/machinery/rnd/production/update_overlays() +/obj/machinery/rnd/production/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) . = ..() - - if(!stripe_color) + if((!issilicon(usr) && !isAdminGhostAI(usr)) && !Adjacent(usr)) return + if(busy) + balloon_alert(usr, "busy printing!") + return + var/direction = get_dir(src, over_location) + if(!direction) + return + drop_direction = direction + balloon_alert(usr, "dropping [dir2text(drop_direction)]") - var/mutable_appearance/stripe = mutable_appearance('icons/obj/machines/research.dmi', "protolate_stripe") - - if(!panel_open) - stripe.icon_state = "protolathe_stripe" - else - stripe.icon_state = "protolathe_stripe_t" - - stripe.color = stripe_color - - . += stripe - -/obj/machinery/rnd/production/examine(mob/user) +/obj/machinery/rnd/production/AltClick(mob/user) . = ..() - - if(in_range(user, src) || isobserver(user)) - . += span_notice("The status display reads: Storing up to [materials.local_size] material units.
Material consumption at [efficiency_coeff * 100]%.
Build time reduced by [100 - efficiency_coeff * 100]%.") + if(!drop_direction || !can_interact(user)) + return + if(busy) + balloon_alert(user, "busy printing!") + return + balloon_alert(user, "drop direction reset") + drop_direction = 0 diff --git a/code/modules/research/machinery/circuit_imprinter.dm b/code/modules/research/machinery/circuit_imprinter.dm index 8127bc45d0a..2dcbde23663 100644 --- a/code/modules/research/machinery/circuit_imprinter.dm +++ b/code/modules/research/machinery/circuit_imprinter.dm @@ -2,23 +2,22 @@ name = "circuit imprinter" desc = "Manufactures circuit boards for the construction of machines." icon_state = "circuit_imprinter" - circuit = /obj/item/circuitboard/machine/circuit_imprinter production_animation = "circuit_imprinter_ani" + circuit = /obj/item/circuitboard/machine/circuit_imprinter allowed_buildtypes = IMPRINTER -/obj/machinery/rnd/production/circuit_imprinter/calculate_efficiency() - . = ..() - +/obj/machinery/rnd/production/circuit_imprinter/compute_efficiency() var/rating = 0 - for(var/datum/stock_part/servo/servo in component_parts) - rating += servo.tier // There is only one. + rating += servo.tier + + return 0.5 ** max(rating - 1, 0) // One sheet, half sheet, quarter sheet, eighth sheet. - efficiency_coeff = 0.5 ** max(rating - 1, 0) // One sheet, half sheet, quarter sheet, eighth sheet. +/obj/machinery/rnd/production/circuit_imprinter/flick_animation(mat_name) + return //we presently have no animation /obj/machinery/rnd/production/circuit_imprinter/offstation name = "ancient circuit imprinter" desc = "Manufactures circuit boards for the construction of machines. Its ancient construction may limit its ability to print all known technology." allowed_buildtypes = AWAY_IMPRINTER circuit = /obj/item/circuitboard/machine/circuit_imprinter/offstation - charges_tax = FALSE diff --git a/code/modules/research/machinery/departmental_protolathe.dm b/code/modules/research/machinery/departmental_protolathe.dm index a4874876ba2..70e3959f5f7 100644 --- a/code/modules/research/machinery/departmental_protolathe.dm +++ b/code/modules/research/machinery/departmental_protolathe.dm @@ -11,10 +11,6 @@ stripe_color = "#EFB341" payment_department = ACCOUNT_ENG -/obj/machinery/rnd/production/protolathe/department/engineering/no_tax - circuit = /obj/item/circuitboard/machine/protolathe/department/engineering/no_tax - charges_tax = FALSE - /obj/machinery/rnd/production/protolathe/department/service name = "department protolathe (Service)" allowed_department_flags = DEPARTMENT_BITFLAG_SERVICE diff --git a/code/modules/research/machinery/protolathe.dm b/code/modules/research/machinery/protolathe.dm index b48f64ca9d7..fb912bba67c 100644 --- a/code/modules/research/machinery/protolathe.dm +++ b/code/modules/research/machinery/protolathe.dm @@ -23,4 +23,3 @@ desc = "Converts raw materials into useful objects. Its ancient construction may limit its ability to print all known technology." circuit = /obj/item/circuitboard/machine/protolathe/offstation allowed_buildtypes = AWAY_LATHE - charges_tax = FALSE diff --git a/code/modules/research/machinery/techfab.dm b/code/modules/research/machinery/techfab.dm index 38df3fc038d..7f1428882e7 100644 --- a/code/modules/research/machinery/techfab.dm +++ b/code/modules/research/machinery/techfab.dm @@ -3,6 +3,5 @@ desc = "Produces researched prototypes with raw materials and energy." icon_state = "protolathe" circuit = /obj/item/circuitboard/machine/techfab - console_link = FALSE production_animation = "protolathe_n" allowed_buildtypes = PROTOLATHE | IMPRINTER diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm index 4ab9d73dca7..a8fa3e36d47 100644 --- a/code/modules/research/rdmachines.dm +++ b/code/modules/research/rdmachines.dm @@ -7,21 +7,22 @@ icon = 'icons/obj/machines/research.dmi' density = TRUE use_power = IDLE_POWER_USE + + ///Are we currently printing a machine var/busy = FALSE + ///Is this machne hacked via wires var/hacked = FALSE - var/console_link = TRUE //allow console link. + ///Is this machine disabled via wires var/disabled = FALSE - /// Ref to global science techweb. + ///Ref to global science techweb. var/datum/techweb/stored_research ///The item loaded inside the machine, used by experimentors and destructive analyzers only. var/obj/item/loaded_item -/obj/machinery/rnd/proc/reset_busy() - busy = FALSE - /obj/machinery/rnd/Initialize(mapload) . = ..() set_wires(new /datum/wires/rnd(src)) + register_context() /obj/machinery/rnd/LateInitialize() . = ..() @@ -37,6 +38,46 @@ QDEL_NULL(wires) return ..() +/obj/machinery/rnd/examine(mob/user) + . = ..() + if(!in_range(user, src) && !isobserver(user)) + return + + . += span_notice("A [EXAMINE_HINT("multitool")] with techweb designs can be uploaded here.") + . += span_notice("Its maintainence panel can be [EXAMINE_HINT("screwed")] [panel_open ? "closed" : "open"].") + if(panel_open) + . += span_notice("Use a [EXAMINE_HINT("multitool")] or [EXAMINE_HINT("wirecutters")] to interact with wires.") + . += span_notice("The machine can be [EXAMINE_HINT("pried")] apart.") + +/obj/machinery/rnd/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + if(isnull(held_item)) + return + + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] Panel" + context[SCREENTIP_CONTEXT_RMB] = "[panel_open ? "Close" : "Open"] Panel" + return CONTEXTUAL_SCREENTIP_SET + + if(panel_open) + var/msg + if(held_item.tool_behaviour == TOOL_CROWBAR) + msg = "Deconstruct" + else if(is_wire_tool(held_item)) + msg = "Open Wires" + + if(msg) + context[SCREENTIP_CONTEXT_LMB] = msg + context[SCREENTIP_CONTEXT_RMB] = msg + return CONTEXTUAL_SCREENTIP_SET + else + if(held_item.tool_behaviour == TOOL_MULTITOOL) + var/obj/item/multitool/tool = held_item + if(!QDELETED(tool.buffer) && istype(tool.buffer, /datum/techweb)) + context[SCREENTIP_CONTEXT_LMB] = "Upload Techweb" + context[SCREENTIP_CONTEXT_RMB] = "Upload Techweb" + return CONTEXTUAL_SCREENTIP_SET + ///Called when attempting to connect the machine to a techweb, forgetting the old. /obj/machinery/rnd/proc/connect_techweb(datum/techweb/new_techweb) if(stored_research) @@ -49,52 +90,42 @@ /obj/machinery/rnd/proc/on_connected_techweb() SHOULD_CALL_PARENT(FALSE) -/obj/machinery/rnd/proc/shock(mob/user, prb) - if(machine_stat & (BROKEN|NOPOWER)) // unpowered, no shock - return FALSE - if(!prob(prb)) - return FALSE - do_sparks(5, TRUE, src) - if (electrocute_mob(user, get_area(src), src, 0.7, TRUE)) - return TRUE - else - return FALSE +///Reset the state of this machine +/obj/machinery/rnd/proc/reset_busy() + busy = FALSE /obj/machinery/rnd/crowbar_act(mob/living/user, obj/item/tool) return default_deconstruction_crowbar(tool) /obj/machinery/rnd/crowbar_act_secondary(mob/living/user, obj/item/tool) - return default_deconstruction_crowbar(tool) + return crowbar_act(user, tool) /obj/machinery/rnd/screwdriver_act(mob/living/user, obj/item/tool) return default_deconstruction_screwdriver(user, "[initial(icon_state)]_t", initial(icon_state), tool) /obj/machinery/rnd/screwdriver_act_secondary(mob/living/user, obj/item/tool) - return default_deconstruction_screwdriver(user, "[initial(icon_state)]_t", initial(icon_state), tool) + return screwdriver_act(user, tool) /obj/machinery/rnd/multitool_act(mob/living/user, obj/item/multitool/tool) + . = ITEM_INTERACT_BLOCKING if(panel_open) wires.interact(user) - return TRUE + return ITEM_INTERACT_SUCCESS if(!QDELETED(tool.buffer) && istype(tool.buffer, /datum/techweb)) connect_techweb(tool.buffer) - return TRUE - return FALSE + return ITEM_INTERACT_SUCCESS /obj/machinery/rnd/multitool_act_secondary(mob/living/user, obj/item/tool) - if(panel_open) - wires.interact(user) - return TRUE + return multitool_act(user, tool) /obj/machinery/rnd/wirecutter_act(mob/living/user, obj/item/tool) + . = ITEM_INTERACT_BLOCKING if(panel_open) wires.interact(user) - return TRUE + return ITEM_INTERACT_SUCCESS /obj/machinery/rnd/wirecutter_act_secondary(mob/living/user, obj/item/tool) - if(panel_open) - wires.interact(user) - return TRUE + return wirecutter_act(user, tool) //whether the machine can have an item inserted in its current state. /obj/machinery/rnd/proc/is_insertion_ready(mob/user) @@ -123,15 +154,3 @@ if(loaded_item) loaded_item.forceMove(drop_location()) ..() - -/obj/machinery/rnd/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted) - var/stack_name - if(istype(item_inserted, /obj/item/stack/ore/bluespace_crystal)) - stack_name = "bluespace" - use_power(SHEET_MATERIAL_AMOUNT / 10) - else - var/obj/item/stack/S = item_inserted - stack_name = S.name - use_power(min(active_power_usage, (amount_inserted / 100))) - add_overlay("protolathe_[stack_name]") - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, cut_overlay), "protolathe_[stack_name]"), 10) diff --git a/code/modules/wiremod/core/component_printer.dm b/code/modules/wiremod/core/component_printer.dm index 3fb736540ec..7c691e3a4c4 100644 --- a/code/modules/wiremod/core/component_printer.dm +++ b/code/modules/wiremod/core/component_printer.dm @@ -184,8 +184,7 @@ "cost" = cost, "id" = researched_design_id, "categories" = design.category, - "icon" = "[icon_size == size32x32 ? "" : "[icon_size] "][design.id]", - "constructionTime" = -1 + "icon" = "[icon_size == size32x32 ? "" : "[icon_size] "][design.id]" ) data["designs"] = designs diff --git a/icons/obj/machines/research.dmi b/icons/obj/machines/research.dmi index 02d848eb4e9..544054279e9 100644 Binary files a/icons/obj/machines/research.dmi and b/icons/obj/machines/research.dmi differ diff --git a/modular_nova/master_files/code/modules/research/machinery/departmental_circuit_imprinter.dm b/modular_nova/master_files/code/modules/research/machinery/departmental_circuit_imprinter.dm deleted file mode 100644 index dc66184c345..00000000000 --- a/modular_nova/master_files/code/modules/research/machinery/departmental_circuit_imprinter.dm +++ /dev/null @@ -1,5 +0,0 @@ -/obj/item/circuitboard/machine/circuit_imprinter/department/no_tax - build_path = /obj/machinery/rnd/production/circuit_imprinter/department/no_tax - -/obj/machinery/rnd/production/circuit_imprinter/department/no_tax - charges_tax = FALSE diff --git a/modular_nova/modules/colony_fabricator/code/colony_fabricator.dm b/modular_nova/modules/colony_fabricator/code/colony_fabricator.dm index 93aa68efc3e..f74cf23dda5 100644 --- a/modular_nova/modules/colony_fabricator/code/colony_fabricator.dm +++ b/modular_nova/modules/colony_fabricator/code/colony_fabricator.dm @@ -12,7 +12,6 @@ obj_flags = CAN_BE_HIT | NO_DECONSTRUCTION light_color = LIGHT_COLOR_BRIGHT_YELLOW light_power = 5 - charges_tax = FALSE allowed_buildtypes = COLONY_FABRICATOR /// The item we turn into when repacked var/repacked_type = /obj/item/flatpacked_machine @@ -33,12 +32,11 @@ QDEL_NULL(soundloop) return ..() -/obj/machinery/rnd/production/colony_lathe/user_try_print_id(design_id, print_quantity) - . = ..() - - if(!.) - return +/// Proc for starting extra printing visuals, because upstream removed any nice way to do this +/obj/machinery/rnd/production/proc/start_printing_visuals() + return +/obj/machinery/rnd/production/colony_lathe/start_printing_visuals() soundloop.start() set_light(l_range = 1.5) icon_state = "colony_lathe_working" @@ -52,8 +50,8 @@ update_appearance() flick("colony_lathe_finish_print", src) -/obj/machinery/rnd/production/colony_lathe/calculate_efficiency() - efficiency_coeff = 1 +/obj/machinery/rnd/production/colony_lathe/build_efficiency() + return 1 // We take from all nodes even unresearched ones /obj/machinery/rnd/production/colony_lathe/update_designs() diff --git a/modular_nova/modules/tarkon/code/misc_fluff/research.dm b/modular_nova/modules/tarkon/code/misc_fluff/research.dm index 1301c970a7a..4a4290b62c7 100644 --- a/modular_nova/modules/tarkon/code/misc_fluff/research.dm +++ b/modular_nova/modules/tarkon/code/misc_fluff/research.dm @@ -85,15 +85,13 @@ req_access = list(ACCESS_AWAY_SCIENCE) /obj/machinery/rnd/server/tarkon/Initialize(mapload) - register_context() var/datum/techweb/tarkon_techweb = locate(/datum/techweb/tarkon) in SSresearch.techwebs stored_research = tarkon_techweb return ..() -/obj/machinery/rnd/server/tarkon/add_context(atom/source, list/context, obj/item/held_item, mob/user) - if(held_item && istype(held_item, /obj/item/research_notes)) - context[SCREENTIP_CONTEXT_LMB] = "Generate research points" - return CONTEXTUAL_SCREENTIP_SET +/obj/machinery/rnd/server/tarkon/examine(mob/user) + . = ..() + . += span_notice("You can use research notes on this to generate research points.") /obj/machinery/rnd/server/tarkon/attackby(obj/item/attacking_item, mob/user, params) if(istype(attacking_item, /obj/item/research_notes) && stored_research) @@ -109,7 +107,6 @@ desc = "Converts raw materials into useful objects. Refurbished and updated from its previous, limited capabilities." circuit = /obj/item/circuitboard/machine/protolathe/tarkon stripe_color = "#350f04" - charges_tax = FALSE /obj/item/circuitboard/machine/protolathe/tarkon name = "Tarkon Industries Protolathe" diff --git a/tgstation.dme b/tgstation.dme index da0e385e0e9..2dd8544cb36 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6528,7 +6528,6 @@ #include "modular_nova\master_files\code\modules\research\designs\medical_designs.dm" #include "modular_nova\master_files\code\modules\research\designs\misc_designs.dm" #include "modular_nova\master_files\code\modules\research\designs\tool_designs.dm" -#include "modular_nova\master_files\code\modules\research\machinery\departmental_circuit_imprinter.dm" #include "modular_nova\master_files\code\modules\research\techweb\all_nodes.dm" #include "modular_nova\master_files\code\modules\shuttle\shuttle.dm" #include "modular_nova\master_files\code\modules\shuttle\shuttle_events\meteors.dm" diff --git a/tgui/packages/tgui/interfaces/Autolathe.tsx b/tgui/packages/tgui/interfaces/Autolathe.tsx index 45d7051e437..8d5d5bafa16 100644 --- a/tgui/packages/tgui/interfaces/Autolathe.tsx +++ b/tgui/packages/tgui/interfaces/Autolathe.tsx @@ -19,12 +19,16 @@ import { MaterialCostSequence } from './Fabrication/MaterialCostSequence'; import { Design, MaterialMap } from './Fabrication/Types'; import { Material } from './Fabrication/Types'; +type AutolatheDesign = Design & { + customMaterials: BooleanLike; +}; + type AutolatheData = { materials: Material[]; materialtotal: number; materialsmax: number; SHEET_MATERIAL_AMOUNT: number; - designs: Design[]; + designs: AutolatheDesign[]; active: BooleanLike; }; @@ -174,7 +178,7 @@ const PrintButton = (props: PrintButtonProps) => { }; type AutolatheRecipeProps = { - design: Design; + design: AutolatheDesign; availableMaterials: MaterialMap; SHEET_MATERIAL_AMOUNT: number; }; @@ -183,7 +187,38 @@ const AutolatheRecipe = (props: AutolatheRecipeProps) => { const { act } = useBackend(); const { design, availableMaterials, SHEET_MATERIAL_AMOUNT } = props; - const maxmult = design.maxmult; + let maxmult = 0; + if (design.customMaterials) { + const smallest_mat = + Object.entries(availableMaterials).reduce( + (accumulator: number, [material, amount]) => { + return Math.min(accumulator, amount); + }, + Infinity, + ) || 0; + + if (smallest_mat > 0) { + maxmult = Object.entries(design.cost).reduce( + (accumulator: number, [material, required]) => { + return Math.min(accumulator, smallest_mat / required); + }, + Infinity, + ); + } else { + maxmult = 0; + } + } else { + maxmult = Object.entries(design.cost).reduce( + (accumulator: number, [material, required]) => { + return Math.min( + accumulator, + (availableMaterials[material] || 0) / required, + ); + }, + Infinity, + ); + } + maxmult = Math.min(Math.floor(maxmult), 50); const canPrint = maxmult > 0; return ( diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator.tsx b/tgui/packages/tgui/interfaces/ExosuitFabricator.tsx index 07c0daabe32..e78aae9591b 100644 --- a/tgui/packages/tgui/interfaces/ExosuitFabricator.tsx +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator.tsx @@ -9,8 +9,13 @@ import { MaterialAccessBar } from './Fabrication/MaterialAccessBar'; import { MaterialCostSequence } from './Fabrication/MaterialCostSequence'; import { Design, FabricatorData, MaterialMap } from './Fabrication/Types'; +type ExosuitDesign = Design & { + constructionTime: number; +}; + type ExosuitFabricatorData = FabricatorData & { processing: BooleanLike; + designs: Record; }; export const ExosuitFabricator = (props) => { diff --git a/tgui/packages/tgui/interfaces/Fabrication/Types.ts b/tgui/packages/tgui/interfaces/Fabrication/Types.ts index e05b977dd7e..f214252ef70 100644 --- a/tgui/packages/tgui/interfaces/Fabrication/Types.ts +++ b/tgui/packages/tgui/interfaces/Fabrication/Types.ts @@ -68,16 +68,6 @@ export type Design = { * 32x32.** */ icon: string; - - /** - * The amount of time, in seconds, that this design takes to print. - */ - constructionTime: number; - - /** - * The maximum number of items than can be printed - */ - maxmult: number; }; /** diff --git a/tgui/packages/tgui/interfaces/Fabricator.tsx b/tgui/packages/tgui/interfaces/Fabricator.tsx index 1b02e9f8639..05119076180 100644 --- a/tgui/packages/tgui/interfaces/Fabricator.tsx +++ b/tgui/packages/tgui/interfaces/Fabricator.tsx @@ -116,10 +116,14 @@ type CustomPrintProps = { const CustomPrint = (props: CustomPrintProps) => { const { act } = useBackend(); const { design, available } = props; - const canPrint = !Object.entries(design.cost).some( - ([material, amount]) => - !available[material] || amount > (available[material] ?? 0), + let maxMult = Object.entries(design.cost).reduce( + (accumulator: number, [material, required]) => { + return Math.min(accumulator, (available[material] || 0) / required); + }, + Infinity, ); + maxMult = Math.min(Math.floor(maxMult), 50); + const canPrint = maxMult > 0; return (
{ }) } > - [Max: {design.maxmult}] + [Max: {maxMult}]
);