<commit_before>/obj/machinery/mecha_part_fabricator
	icon = 'icons/obj/robotics.dmi'
	icon_state = "fab-idle"
	name = "exosuit fabricator"
	desc = "Nothing is being built."
	density = TRUE
	use_power = IDLE_POWER_USE
	idle_power_usage = 20
	active_power_usage = 5000
	req_access = list(ACCESS_ROBOTICS)
	circuit = /obj/item/circuitboard/machine/mechfab
	processing_flags = START_PROCESSING_MANUALLY

	subsystem_type = /datum/controller/subsystem/processing/fastprocess

	/// Current items in the build queue.
	var/list/queue = list()
	/// Whether or not the machine is building the entire queue automagically.
	var/process_queue = FALSE

	/// The current design datum that the machine is building.
	var/datum/design/being_built
	/// World time when the build will finish.
	var/build_finish = 0
	/// World time when the build started.
	var/build_start = 0
	/// Reference to all materials used in the creation of the item being_built.
	var/list/build_materials
	/// Part currently stored in the Exofab.
	var/obj/item/stored_part

	/// Coefficient for the speed of item building. Based on the installed parts.
	var/time_coeff = 1
	/// Coefficient for the efficiency of material usage in item building. Based on the installed parts.
	var/component_coeff = 1

	/// Reference to the techweb.
	var/datum/techweb/stored_research

	/// Whether the Exofab links to the ore silo on init. Special derelict or maintanance variants should set this to FALSE.
	var/link_on_init = TRUE

	/// Reference to a remote material inventory, such as an ore silo.
	var/datum/component/remote_materials/rmat

	/// A list of part sets used for TGUI static data. Updated on Init() and syncing with the R&D console.
	var/list/final_sets = list()

	/// A list of individual parts used for TGUI static data. Updated on Init() and syncing with the R&D console.
	var/list/buildable_parts = list()

	/// A list of categories that valid MECHFAB design datums will broadly categorise themselves under.
	var/list/part_sets = list(
								"Cyborg",
								"Ripley",
								"Odysseus",
								"Clarke",
								"Gygax",
								"Durand",
								"H.O.N.K",
								"Phazon",
								"Savannah-Ivanov",
								"Exosuit Equipment",
								"Exosuit Ammunition",
								"Cyborg Upgrade Modules",
								"Cybernetics",
								"Implants",
								"Control Interfaces",
								"MOD Construction",
								"MOD Modules",
								"Misc"
								)

/obj/machinery/mecha_part_fabricator/Initialize(mapload)
	stored_research = SSresearch.science_tech
	rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init, mat_container_flags=BREAKDOWN_FLAGS_LATHE)
	RefreshParts() //Recalculating local material sizes if the fab isn't linked
	update_menu_tech()
	return ..()

/obj/machinery/mecha_part_fabricator/RefreshParts()
	var/T = 0

	//maximum stocking amount (default 300000, 600000 at T4)
	for(var/obj/item/stock_parts/matter_bin/M in component_parts)
		T += M.rating
	rmat.set_local_size((200000 + (T*50000)))

	//resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55)
	T = 1.15
	for(var/obj/item/stock_parts/micro_laser/Ma in component_parts)
		T -= Ma.rating*0.15
	component_coeff = T

	//building time adjustment coefficient (1 -> 0.8 -> 0.6)
	T = -1
	for(var/obj/item/stock_parts/manipulator/Ml in component_parts)
		T += Ml.rating
	time_coeff = round(initial(time_coeff) - (initial(time_coeff)*(T))/5,0.01)

	// Adjust the build time of any item currently being built.
	if(being_built)
		var/last_const_time = build_finish - build_start
		var/new_const_time = get_construction_time_w_coeff(initial(being_built.construction_time))
		var/const_time_left = build_finish - world.time
		var/new_build_time = (new_const_time / last_const_time) * const_time_left
		build_finish = world.time + new_build_time

	update_static_data(usr)

/obj/machinery/mecha_part_fabricator/examine(mob/user)
	. = ..()
	if(in_range(user, src) || isobserver(user))
		. += span_notice("The status display reads: Storing up to <b>[rmat.local_size]</b> material units.<br>Material consumption at <b>[component_coeff*100]%</b>.<br>Build time reduced by <b>[100-time_coeff*100]%</b>.")
	if(panel_open)
		. += span_notice("Alt-click to rotate the output direction.")

/obj/machinery/mecha_part_fabricator/AltClick(mob/user)
	. = ..()
	if(!user.canUseTopic(src, BE_CLOSE))
		return
	if(panel_open)
		dir = turn(dir, -90)
		balloon_alert(user, "rotated to [dir2text(dir)].")
		return TRUE

/**
 * Generates an info list for a given part.
 *
 * Returns a list of part information.
 * * D - Design datum to get information on.
 * * categories - Boolean, whether or not to parse snowflake categories into the part information list.
 */
/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D, categories = FALSE)
	var/cost = list()
	for(var/c in D.materials)
		var/datum/material/M = c
		cost[M.name] = get_resource_cost_w_coeff(D, M)

	var/obj/built_item = D.build_path

	var/list/category_override = null
	var/list/sub_category = null

	if(categories)
		// Handle some special cases to build up sub-categories for the fab interface.
		// Start with checking if this design builds a cyborg module.
		if(ispath(built_item, /obj/item/borg/upgrade))
			var/obj/item/borg/upgrade/U = built_item
			var/model_types = initial(U.model_flags)
			sub_category = list()
			if(model_types)
				if(model_types & BORG_MODEL_SECURITY)
					sub_category += "Security"
				if(model_types & BORG_MODEL_MINER)
					sub_category += "Mining"
				if(model_types & BORG_MODEL_JANITOR)
					sub_category += "Janitor"
				if(model_types & BORG_MODEL_MEDICAL)
					sub_category += "Medical"
				if(model_types & BORG_MODEL_ENGINEERING)
					sub_category += "Engineering"
			else
				sub_category += "All Cyborgs"

		else if(ispath(built_item, /obj/item/mecha_parts/mecha_equipment))
			var/obj/item/mecha_parts/mecha_equipment/E = built_item
			var/mech_types = initial(E.mech_flags)
			sub_category = "Equipment"
			if(mech_types)
				category_override = list()
				if(mech_types & EXOSUIT_MODULE_RIPLEY)
					category_override += "Ripley"
				if(mech_types & EXOSUIT_MODULE_ODYSSEUS)
					category_override += "Odysseus"
				if(mech_types & EXOSUIT_MODULE_CLARKE)
					category_override += "Clarke"
				if(mech_types & EXOSUIT_MODULE_GYGAX)
					category_override += "Gygax"
				if(mech_types & EXOSUIT_MODULE_DURAND)
					category_override += "Durand"
				if(mech_types & EXOSUIT_MODULE_HONK)
					category_override += "H.O.N.K"
				if(mech_types & EXOSUIT_MODULE_PHAZON)
					category_override += "Phazon"

		else if(ispath(built_item, /obj/item/borg_restart_board))
			sub_category += "All Cyborgs" //Otherwise the restart board shows in the "parts" category, which seems dumb

		else if(istype(D, /datum/design/module))
			var/datum/design/module/module_design = D
			sub_category = list(module_design.department_type)

	var/list/part = list(
		"name" = D.name,
		"desc" = D.get_description(),
		"printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10,
		"cost" = cost,
		"id" = D.id,
		"subCategory" = sub_category,
		"categoryOverride" = category_override,
		"searchMeta" = D.search_metadata
	)

	return part

/**<commit_msg>Fix mech category overrides (#65810)<commit_after>/obj/machinery/mecha_part_fabricator
	icon = 'icons/obj/robotics.dmi'
	icon_state = "fab-idle"
	name = "exosuit fabricator"
	desc = "Nothing is being built."
	density = TRUE
	use_power = IDLE_POWER_USE
	idle_power_usage = 20
	active_power_usage = 5000
	req_access = list(ACCESS_ROBOTICS)
	circuit = /obj/item/circuitboard/machine/mechfab
	processing_flags = START_PROCESSING_MANUALLY

	subsystem_type = /datum/controller/subsystem/processing/fastprocess

	/// Current items in the build queue.
	var/list/queue = list()
	/// Whether or not the machine is building the entire queue automagically.
	var/process_queue = FALSE

	/// The current design datum that the machine is building.
	var/datum/design/being_built
	/// World time when the build will finish.
	var/build_finish = 0
	/// World time when the build started.
	var/build_start = 0
	/// Reference to all materials used in the creation of the item being_built.
	var/list/build_materials
	/// Part currently stored in the Exofab.
	var/obj/item/stored_part

	/// Coefficient for the speed of item building. Based on the installed parts.
	var/time_coeff = 1
	/// Coefficient for the efficiency of material usage in item building. Based on the installed parts.
	var/component_coeff = 1

	/// Reference to the techweb.
	var/datum/techweb/stored_research

	/// Whether the Exofab links to the ore silo on init. Special derelict or maintanance variants should set this to FALSE.
	var/link_on_init = TRUE

	/// Reference to a remote material inventory, such as an ore silo.
	var/datum/component/remote_materials/rmat

	/// A list of part sets used for TGUI static data. Updated on Init() and syncing with the R&D console.
	var/list/final_sets = list()

	/// A list of individual parts used for TGUI static data. Updated on Init() and syncing with the R&D console.
	var/list/buildable_parts = list()

	/// A list of categories that valid MECHFAB design datums will broadly categorise themselves under.
	var/list/part_sets = list(
								"Cyborg",
								"Ripley",
								"Odysseus",
								"Clarke",
								"Gygax",
								"Durand",
								"H.O.N.K",
								"Phazon",
								"Savannah-Ivanov",
								"Exosuit Equipment",
								"Exosuit Ammunition",
								"Cyborg Upgrade Modules",
								"Cybernetics",
								"Implants",
								"Control Interfaces",
								"MOD Construction",
								"MOD Modules",
								"Misc"
								)

/obj/machinery/mecha_part_fabricator/Initialize(mapload)
	stored_research = SSresearch.science_tech
	rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init, mat_container_flags=BREAKDOWN_FLAGS_LATHE)
	RefreshParts() //Recalculating local material sizes if the fab isn't linked
	update_menu_tech()
	return ..()

/obj/machinery/mecha_part_fabricator/RefreshParts()
	var/T = 0

	//maximum stocking amount (default 300000, 600000 at T4)
	for(var/obj/item/stock_parts/matter_bin/M in component_parts)
		T += M.rating
	rmat.set_local_size((200000 + (T*50000)))

	//resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55)
	T = 1.15
	for(var/obj/item/stock_parts/micro_laser/Ma in component_parts)
		T -= Ma.rating*0.15
	component_coeff = T

	//building time adjustment coefficient (1 -> 0.8 -> 0.6)
	T = -1
	for(var/obj/item/stock_parts/manipulator/Ml in component_parts)
		T += Ml.rating
	time_coeff = round(initial(time_coeff) - (initial(time_coeff)*(T))/5,0.01)

	// Adjust the build time of any item currently being built.
	if(being_built)
		var/last_const_time = build_finish - build_start
		var/new_const_time = get_construction_time_w_coeff(initial(being_built.construction_time))
		var/const_time_left = build_finish - world.time
		var/new_build_time = (new_const_time / last_const_time) * const_time_left
		build_finish = world.time + new_build_time

	update_static_data(usr)

/obj/machinery/mecha_part_fabricator/examine(mob/user)
	. = ..()
	if(in_range(user, src) || isobserver(user))
		. += span_notice("The status display reads: Storing up to <b>[rmat.local_size]</b> material units.<br>Material consumption at <b>[component_coeff*100]%</b>.<br>Build time reduced by <b>[100-time_coeff*100]%</b>.")
	if(panel_open)
		. += span_notice("Alt-click to rotate the output direction.")

/obj/machinery/mecha_part_fabricator/AltClick(mob/user)
	. = ..()
	if(!user.canUseTopic(src, BE_CLOSE))
		return
	if(panel_open)
		dir = turn(dir, -90)
		balloon_alert(user, "rotated to [dir2text(dir)].")
		return TRUE

/**
 * Generates an info list for a given part.
 *
 * Returns a list of part information.
 * * D - Design datum to get information on.
 * * categories - Boolean, whether or not to parse snowflake categories into the part information list.
 */
/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D, categories = FALSE)
	var/cost = list()
	for(var/c in D.materials)
		var/datum/material/M = c
		cost[M.name] = get_resource_cost_w_coeff(D, M)

	var/obj/built_item = D.build_path

	var/list/category_override = null
	var/list/sub_category = null

	if(categories)
		// Handle some special cases to build up sub-categories for the fab interface.
		// Start with checking if this design builds a cyborg module.
		if(ispath(built_item, /obj/item/borg/upgrade))
			var/obj/item/borg/upgrade/U = built_item
			var/model_types = initial(U.model_flags)
			sub_category = list()
			if(model_types)
				if(model_types & BORG_MODEL_SECURITY)
					sub_category += "Security"
				if(model_types & BORG_MODEL_MINER)
					sub_category += "Mining"
				if(model_types & BORG_MODEL_JANITOR)
					sub_category += "Janitor"
				if(model_types & BORG_MODEL_MEDICAL)
					sub_category += "Medical"
				if(model_types & BORG_MODEL_ENGINEERING)
					sub_category += "Engineering"
			else
				sub_category += "All Cyborgs"

		else if(ispath(built_item, /obj/item/mecha_parts/mecha_equipment))
			var/obj/item/mecha_parts/mecha_equipment/E = built_item
			var/mech_types = initial(E.mech_flags)
			sub_category = "Equipment"
			if(mech_types)
				category_override = list()
				if(mech_types & EXOSUIT_MODULE_RIPLEY)
					category_override += "Ripley"
				if(mech_types & EXOSUIT_MODULE_ODYSSEUS)
					category_override += "Odysseus"
				if(mech_types & EXOSUIT_MODULE_CLARKE)
					category_override += "Clarke"
				if(mech_types & EXOSUIT_MODULE_GYGAX)
					category_override += "Gygax"
				if(mech_types & EXOSUIT_MODULE_DURAND)
					category_override += "Durand"
				if(mech_types & EXOSUIT_MODULE_HONK)
					category_override += "H.O.N.K"
				if(mech_types & EXOSUIT_MODULE_PHAZON)
					category_override += "Phazon"

		else if(ispath(built_item, /obj/item/borg_restart_board))
			sub_category += "All Cyborgs" //Otherwise the restart board shows in the "parts" category, which seems dumb

		else if(istype(D, /datum/design/module))
			var/datum/design/module/module_design = D
			sub_category = list(module_design.department_type)

	var/list/part = list(
		"name" = D.name,
		"desc" = D.get_description(),
		"printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10,
		"cost" = cost,
		"id" = D.id,
		"subCategory" = sub_category,
		"category_override" = category_override,
		"searchMeta" = D.search_metadata
	)

	return part

/**
{'fraction_non_alphanumeric': 0.10947237224761114, 'fraction_numerical': 0.0105941005400914, 'mean_word_length': 3.7777042672841548, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6193558', 'n_tokens_mistral': 5831, 'n_tokens_neox': 5007, 'n_words': 1176}