Files
FenodyreeAvandGitHub 038abdc905 Integrated circuits can be recycled and charged in rechargers (#23004)
Also generalizes autolathe recycling so that other containers can alt
click it to be recycled. Currently its still only circuits and the part
exchanger.

changes:
- qol: "Integrated circuit assemblies can now be recycled in autolathes.
They can't be recycled in the printer, because clicking the printer with
the circuit is required to scan it for cloning."
  - qol: "Integrated circuits can now be charged in rechargers."



https://github.com/user-attachments/assets/1b8325a8-aca0-4df0-a2a3-763eb8cec989
2026-08-13 16:25:05 +00:00

329 lines
11 KiB
Plaintext

ABSTRACT_TYPE(/obj/structure/machinery/fabricator)
density = TRUE
anchored = TRUE
use_power = POWER_USE_IDLE
idle_power_usage = 10
active_power_usage = 2000
clicksound = SFX_KEYBOARD
clickvol = 30
manufacturer = "hephaestus"
/// What location to print to. Only used for mounted autolathes
var/atom/print_loc
/// Class of fabricator. Determines recipes loaded. See entries in [__fabricator_defines.dm]
var/fabricator_class = FABRICATOR_CLASS_GENERAL
/// List of stored materials.
var/list/stored_material = list()
/// List of material capacities. Should not be modified directly, use [var/list/base_storage_capacity] instead.
var/list/storage_capacity = list()
/// Base storage capacity, which is modified by default by the amount and tier of matter bins.
var/list/base_storage_capacity = list(
MATERIAL_STEEL = 25000,
MATERIAL_ALUMINIUM = 25000,
MATERIAL_GLASS = 12500,
MATERIAL_PLASTIC = 12500,
MATERIAL_PHORON = 12500
)
/// Current category to show for this fabricator
var/show_category = "All"
/// Status bitflags for the fabricator
var/fab_status_flags = 0
/// Current queue for this fabricator
var/list/print_queue = list()
/// What is currently printing in this fabricator
var/datum/fabricator_build_order/currently_printing
/// Global list of the substances currently stored in the fabricator
var/static/list/stored_substances_to_names = list()
/// How efficiently this fabricator uses materials. Modified by default by the amount and tier of micro lasers
var/mat_efficiency = 1
/// What to multiply build times by. Modified by default by the amount and tier of manipulators
var/build_time_multiplier = 1
/// Snowflake for mounted autolathes
var/does_flick = TRUE
/// The fabricator's wires
var/datum/wires/fabricator/wires
component_types = list(
/obj/item/circuitboard/autolathe,
/obj/item/stock_parts/matter_bin = 3,
/obj/item/stock_parts/micro_laser,
/obj/item/stock_parts/manipulator,
/obj/item/stock_parts/console_screen
)
///The sound this fabricator will emit while running
var/fabricating_sound_loop = /datum/looping_sound/fabricator
///The looping sound used while the fabricator is running
VAR_PRIVATE/datum/looping_sound/fabricator_looping_sound
/obj/structure/machinery/fabricator/upgrade_hints(mob/user, distance, is_adjacent)
. += ..()
. += "- Upgraded <b>matter bins</b> will increase material storage capacity."
. += SPAN_NOTICE(" - The current storage limit per material type is <b>[SSmaterials.get_material_amount(storage_capacity, MATERIAL_STEEL) / 2000]</b> sheets")
. += "- Upgraded <b>micro lasers</b> will improve material use efficiency."
. += SPAN_NOTICE(" - The current material cost reduction is <b>[round((1 - mat_efficiency) * 100)]%</b>")
. += "- Upgraded <b>manipulators</b> will increase the fabrication speed."
. += SPAN_NOTICE(" - The current build speed increase is <b>[round(build_time_multiplier * 100)]%</b>")
/obj/structure/machinery/fabricator/Initialize(mapload)
wires = new(src)
print_loc = src
base_storage_capacity = base_storage_capacity.Copy()
SSmaterials.normalize_material_amounts(base_storage_capacity)
stored_material = list()
for(var/mat in base_storage_capacity)
stored_material[mat] = 0
// Update global type to string cache.
if(!stored_substances_to_names[mat])
if(ispath(mat, /singleton/material))
var/singleton/material/mat_instance = mat
mat_instance = GET_SINGLETON(mat_instance)
if(istype(mat_instance))
stored_substances_to_names[mat] = mat_instance.display_name
else if(ispath(mat, /singleton/reagent))
var/singleton/reagent/reg = mat
stored_substances_to_names[mat] = initial(reg.name)
update_icon()
. = ..()
/obj/structure/machinery/fabricator/proc/normalize_material_storage()
SSmaterials.normalize_material_amounts(stored_material)
SSmaterials.normalize_material_amounts(storage_capacity)
/obj/structure/machinery/fabricator/Destroy()
print_loc = null
QDEL_NULL(currently_printing)
QDEL_NULL(wires)
QDEL_LIST(print_queue)
QDEL_NULL(fabricator_looping_sound)
return ..()
/obj/structure/machinery/fabricator/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Autolathe", capitalize_first_letters(name))
ui.open()
/obj/structure/machinery/fabricator/ui_data(mob/user)
. = ..()
normalize_material_storage()
var/list/data = list()
data["manufacturer"] = manufacturer
data["disabled"] = (fab_status_flags & FAB_DISABLED)
data["material_efficiency"] = mat_efficiency
data["materials"] = list()
data["categories"] = SSfabrication.get_categories(fabricator_class)|"All"
data["build_time"] = currently_printing?.remaining_time
data["show_category"] = show_category
for(var/material in stored_material)
data["materials"] += list(list("material" = SSmaterials.material_display_name(material), "stored" = stored_material[material], "max_capacity" = storage_capacity[material]))
data["recipes"] = list()
for(var/recipe in SSfabrication.get_recipes(fabricator_class))
var/singleton/fabricator_recipe/R = recipe
if(R.hack_only && !(fab_status_flags & FAB_HACKED))
continue
var/list/recipe_data = list()
recipe_data["name"] = R.name
recipe_data["recipe"] = R.type
recipe_data["security_level"] = R.security_level ? capitalize(num2seclevel(R.security_level)) : "None"
recipe_data["hack_only"] = R.hack_only
recipe_data["enabled"] = can_print_item(R)
var/list/resources = list()
recipe_data["sheets"] = null
recipe_data["can_make"] = FALSE
for(var/resource in R.resources)
var/resource_cost = round(R.resources[resource] * mat_efficiency)
var/material = SSmaterials.material_to_path(resource, FALSE)
resources += "[resource_cost] [SSmaterials.material_display_name(resource)]"
if(!material || isnull(stored_material[material]) || stored_material[material] < resource_cost)
recipe_data["can_make"] = TRUE
if(resource_cost > 0 && material && !isnull(stored_material[material]))
var/craftable = stored_material[material] / resource_cost
recipe_data["sheets"] = isnull(recipe_data["sheets"]) ? craftable : min(recipe_data["sheets"], craftable)
recipe_data["category"] = R.category
recipe_data["resources"] = english_list(resources)
recipe_data["build_time"] = (R.build_time / 10)
recipe_data["max_sheets"] = null
if(R.is_stack)
var/obj/item/stack/R_stack = R.path
recipe_data["max_sheets"] = initial(R_stack.max_amount)
data["recipes"] += list(recipe_data)
data["currently_printing"] = null
if(currently_printing)
data["currently_printing"] = REF("[currently_printing]")
data["queue"] = list()
for(var/datum/fabricator_build_order/AR in print_queue)
data["queue"] += list(
list(
"ref" = REF(AR),
"order" = AR.target_recipe.name,
"path" = AR.target_recipe.type,
"multiplier" = AR.multiplier,
"build_time" = AR.target_recipe.build_time,
"progress" = AR.target_recipe.build_time - AR.remaining_time,
"remaining_time" = AR.remaining_time
)
)
return data
/obj/structure/machinery/fabricator/attackby(obj/item/attacking_item, mob/user)
if(fab_status_flags & FAB_BUSY)
to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for the completion of previous operation."))
return TRUE
if(default_deconstruction_screwdriver(user, attacking_item))
SStgui.update_uis(src)
return TRUE
if(default_deconstruction_crowbar(user, attacking_item))
return TRUE
if(default_part_replacement(user, attacking_item))
return TRUE
if(stat)
return TRUE
if(panel_open)
//Don't eat multitools or wirecutters used on an open lathe.
if(attacking_item.tool_behaviour == TOOL_MULTITOOL || attacking_item.tool_behaviour == TOOL_WIRECUTTER )
if(panel_open)
wires.interact(user)
else
to_chat(user, SPAN_WARNING("\The [src]'s wires aren't exposed."))
return TRUE
if(attacking_item.loc != user && !istype(attacking_item, /obj/item/stack))
return FALSE
if(is_robot_module(attacking_item))
return FALSE
load_lathe(attacking_item, user)
return TRUE
/obj/structure/machinery/fabricator/autolathe/proc/recycle_item_contents(obj/item/R, mob/user)
var/recycled = 0
var/recyclable = 0
var/rejected = 0
for(var/obj/item/item in R.contents.Copy())
if(!item.matter || !item.recyclable)
continue
recyclable++
if(load_lathe(item, user, FALSE))
recycled++
else
rejected++
if(recycled)
to_chat(user, SPAN_NOTICE("You recycle [recycled] item\s from \the [R] into \the [src]."))
else if(!recyclable)
to_chat(user, SPAN_WARNING("\The [R] contains no recyclable materials for \the [src]."))
else
to_chat(user, SPAN_WARNING("\The [src] could not accept any recyclable contents from \the [R]."))
if(rejected)
to_chat(user, SPAN_WARNING("Some contents could not be accepted and remain in \the [R]."))
/obj/structure/machinery/fabricator/attack_hand(mob/user)
user.set_machine(src)
ui_interact(user)
/obj/structure/machinery/fabricator/proc/is_functioning()
. = use_power != POWER_USE_OFF && !(fab_status_flags & FAB_DISABLED)
/obj/structure/machinery/fabricator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
usr.set_machine(src)
add_fingerprint(usr)
playsound(src, SFX_KEYBOARD, 50)
if(action == "make")
START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF)
var/multiplier = text2num(params["multiplier"])
var/singleton/fabricator_recipe/R = GET_SINGLETON(text2path(params["recipe"]))
if(!istype(R))
CRASH("Unknown recipe given! [R], param is [params["recipe"]].")
intent_message(MACHINE_SOUND)
try_queue_build(R, multiplier)
. = TRUE
if(action == "remove")
var/datum/fabricator_build_order/order = locate(params["ref"])
try_cancel_build(order)
. = TRUE
/obj/structure/machinery/fabricator/process(seconds_per_tick)
..()
if(use_power == POWER_USE_ACTIVE && (fab_status_flags & FAB_BUSY))
update_current_build(seconds_per_tick)
/obj/structure/machinery/fabricator/update_icon()
if(!does_flick)
return
ClearOverlays()
if(panel_open)
AddOverlays("[icon_state]_panel")
if(currently_printing)
AddOverlays(emissive_appearance(icon, "[icon_state]_lights_working"))
AddOverlays("[icon_state]_lights_working")
AddOverlays("[icon_state]_process")
else if(powered())
AddOverlays(emissive_appearance(icon, "[icon_state]_lights"))
AddOverlays("[icon_state]_lights")
/obj/structure/machinery/fabricator/proc/remove_mat_overlay(mat_overlay)
CutOverlays(mat_overlay)
update_icon()
/obj/structure/machinery/fabricator/RefreshParts()
..()
var/mb_rating = 0
var/man_rating = 0
var/las_rating = 0
for(var/obj/item/stock_parts/matter_bin/MB in component_parts)
mb_rating += MB.rating
for(var/obj/item/stock_parts/manipulator/M in component_parts)
man_rating += M.rating
for(var/obj/item/stock_parts/micro_laser/L in component_parts)
las_rating += L.rating
SSmaterials.normalize_material_amounts(base_storage_capacity)
storage_capacity = list()
for(var/mat in base_storage_capacity)
storage_capacity[mat] = mb_rating * base_storage_capacity[mat]
mat_efficiency = 1.1 - (las_rating * 0.1) // Normally, price is 1.25 the amount of material, so this shouldn't go higher than 0.8. Maximum rating of parts is 3
build_time_multiplier = initial(build_time_multiplier) * man_rating
/obj/structure/machinery/fabricator/dismantle()
normalize_material_storage()
for(var/mat in stored_material)
var/stack_type = SSmaterials.material_stack_type(mat)
if(!stack_type)
continue
var/obj/item/stack/material/S = new stack_type(get_turf(src))
if(stored_material[mat] > S.perunit)
S.amount = round(stored_material[mat] / S.perunit)
else
qdel(S)
..()
return TRUE