<commit_before>/*
	This datum should be used for handling mineral contents of machines and whatever else is supposed to hold minerals and make use of them.

	Variables:
		amount - raw amount of the mineral this container is holding, calculated by the defined value MINERAL_MATERIAL_AMOUNT=2000.
		max_amount - max raw amount of mineral this container can hold.
		sheet_type - type of the mineral sheet the container handles, used for output.
		parent - object that this container is being used by, used for output.
		MAX_STACK_SIZE - size of a stack of mineral sheets. Constant.
*/

/datum/component/material_container
	var/total_amount = 0
	var/max_amount
	var/sheet_type
	var/list/materials
	var/show_on_examine
	var/list/allowed_typecache
	var/last_inserted_type
	var/last_inserted_id
	var/last_amount_inserted
	var/last_insert_success
	var/precise_insertion = FALSE
	var/datum/callback/precondition
	//MAX_STACK_SIZE = 50
	//MINERAL_MATERIAL_AMOUNT = 2000

/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _show_on_examine = FALSE, list/allowed_types, datum/callback/_precondition)
	materials = list()
	max_amount = max(0, max_amt)
	show_on_examine = _show_on_examine
	if(allowed_types)
		allowed_typecache = typecacheof(allowed_types)
	precondition = _precondition

	RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
	RegisterSignal(COMSIG_PARENT_EXAMINE, .proc/OnExamine)

	var/list/possible_mats = list()
	for(var/mat_type in subtypesof(/datum/material))
		var/datum/material/MT = mat_type
		possible_mats[initial(MT.id)] = mat_type
	for(var/id in mat_list)
		if(possible_mats[id])
			var/mat_path = possible_mats[id]
			materials[id] = new mat_path()

/datum/component/material_container/proc/OnExamine(mob/user)
	for(var/I in materials)
		var/datum/material/M = materials[I]
		var/amt = amount(M.id)
		if(amt)
			to_chat(user, "<span class='notice'>It has [amt] units of [lowertext(M.name)] stored.</span>")

/datum/component/material_container/proc/OnAttackBy(obj/item/I, mob/living/user)
	var/list/tc = allowed_typecache
	if(user.a_intent == INTENT_HARM)
		return FALSE
	if((I.flags_2 & (HOLOGRAM_2 | NO_MAT_REDEMPTION_2)) || (tc && !is_type_in_typecache(I, tc)))
		to_chat(user, "<span class='warning'>[parent] won't accept [I]!</span>")
		return FALSE
	. = TRUE
	last_insert_success = FALSE
	var/datum/callback/pc = precondition
	if(pc && !pc.Invoke())
		return
	var/material_amount = get_item_material_amount(I)
	if(!material_amount)
		to_chat(user, "<span class='warning'>[I] does not contain sufficient amounts of metal or glass to be accepted by [parent].</span>")
		return
	if(!has_space(material_amount))
		to_chat(user, "<span class='warning'>[parent] is full. Please remove metal or glass from [parent] in order to insert more.</span>")
		return
	INVOKE_ASYNC(src, .proc/user_insert, I, user)

/datum/component/material_container/proc/user_insert(obj/item/I, mob/living/user)
	var/requested_amount
	if(istype(I, /obj/item/stack) && precise_insertion)
		var/atom/current_parent = parent
		requested_amount = input(user, "How much do you want to insert?", "Inserting sheets") as num|null
		if(isnull(requested_amount) || (requested_amount <= 0))
			return
		if(QDELETED(I) || QDELETED(user) || QDELETED(src) || parent != current_parent || !user.canUseTopic(current_parent) || !user.is_holding(I) || !user.Adjacent(current_parent))
			return
	if(!user.temporarilyRemoveItemFromInventory(I))
		to_chat(user, "<span class='warning'>[I] is stuck to you and cannot be placed into [parent].</span>")
		return
	var/inserted = insert_item(I, stack_amt = requested_amount)
	if(inserted)
		last_insert_success = TRUE
		if(istype(I, /obj/item/stack))
			to_chat(user, "<span class='notice'>You insert [inserted] sheet[inserted>1 ? "s" : ""] into [parent].</span>")
			if(!QDELETED(I))
				user.put_in_active_hand(I)
		else
			to_chat(user, "<span class='notice'>You insert a material total of [inserted] into [parent].</span>")
			qdel(I)
	else
		user.put_in_active_hand(I)

//For inserting an amount of material
/datum/component/material_container/proc/insert_amount(amt, id = null)
	if(amt > 0 && has_space(amt))
		var/total_amount_saved = total_amount
		if(id)
			var/datum/material/M = materials[id]
			if(M)
				M.amount += amt
				total_amount += amt
		else
			for(var/i in materials)
				var/datum/material/M = materials[i]
				M.amount += amt
				total_amount += amt
		return (total_amount - total_amount_saved)
	return FALSE

/datum/component/material_container/proc/insert_stack(obj/item/stack/S, amt = 0)
	if(isnull(amt))
		amt = S.amount

	if(amt <= 0)
		return FALSE

	if(amt > S.amount)
		amt = S.amount

	var/material_amt = get_item_material_amount(S)
	if(!material_amt)
		return FALSE

	amt = min(amt, round(((max_amount - total_amount) / material_amt)))
	if(!amt)
		return FALSE

	last_inserted_id = insert_materials(S,amt)
	last_inserted_type = S.type
	S.use(amt)
	last_amount_inserted = amt
	return amt

/datum/component/material_container/proc/insert_item(obj/item/I, multiplier = 1, stack_amt)
	if(!I)
		return FALSE
	if(istype(I, /obj/item/stack))
		return insert_stack(I, stack_amt)

	var/material_amount = get_item_material_amount(I)
	if(!material_amount || !has_space(material_amount))<commit_msg>Update material_container.dm (#31555)<commit_after>/*
	This datum should be used for handling mineral contents of machines and whatever else is supposed to hold minerals and make use of them.

	Variables:
		amount - raw amount of the mineral this container is holding, calculated by the defined value MINERAL_MATERIAL_AMOUNT=2000.
		max_amount - max raw amount of mineral this container can hold.
		sheet_type - type of the mineral sheet the container handles, used for output.
		parent - object that this container is being used by, used for output.
		MAX_STACK_SIZE - size of a stack of mineral sheets. Constant.
*/

/datum/component/material_container
	var/total_amount = 0
	var/max_amount
	var/sheet_type
	var/list/materials
	var/show_on_examine
	var/list/allowed_typecache
	var/last_inserted_type
	var/last_inserted_id
	var/last_amount_inserted
	var/last_insert_success
	var/precise_insertion = FALSE
	var/datum/callback/precondition
	//MAX_STACK_SIZE = 50
	//MINERAL_MATERIAL_AMOUNT = 2000

/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _show_on_examine = FALSE, list/allowed_types, datum/callback/_precondition)
	materials = list()
	max_amount = max(0, max_amt)
	show_on_examine = _show_on_examine
	if(allowed_types)
		allowed_typecache = typecacheof(allowed_types)
	precondition = _precondition

	RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
	RegisterSignal(COMSIG_PARENT_EXAMINE, .proc/OnExamine)

	var/list/possible_mats = list()
	for(var/mat_type in subtypesof(/datum/material))
		var/datum/material/MT = mat_type
		possible_mats[initial(MT.id)] = mat_type
	for(var/id in mat_list)
		if(possible_mats[id])
			var/mat_path = possible_mats[id]
			materials[id] = new mat_path()

/datum/component/material_container/proc/OnExamine(mob/user)
	for(var/I in materials)
		var/datum/material/M = materials[I]
		var/amt = amount(M.id)
		if(amt)
			to_chat(user, "<span class='notice'>It has [amt] units of [lowertext(M.name)] stored.</span>")

/datum/component/material_container/proc/OnAttackBy(obj/item/I, mob/living/user)
	var/list/tc = allowed_typecache
	if(user.a_intent == INTENT_HARM)
		return FALSE
	if((I.flags_2 & (HOLOGRAM_2 | NO_MAT_REDEMPTION_2)) || (tc && !is_type_in_typecache(I, tc)))
		to_chat(user, "<span class='warning'>[parent] won't accept [I]!</span>")
		return FALSE
	. = TRUE
	last_insert_success = FALSE
	var/datum/callback/pc = precondition
	if(pc && !pc.Invoke())
		return
	var/material_amount = get_item_material_amount(I)
	if(!material_amount)
		to_chat(user, "<span class='warning'>[I] does not contain sufficient amounts of metal or glass to be accepted by [parent].</span>")
		return
	if(!has_space(material_amount))
		to_chat(user, "<span class='warning'>[parent] is full. Please remove metal or glass from [parent] in order to insert more.</span>")
		return
	INVOKE_ASYNC(src, .proc/user_insert, I, user)

/datum/component/material_container/proc/user_insert(obj/item/I, mob/living/user)
	var/requested_amount
	if(istype(I, /obj/item/stack) && precise_insertion)
		var/atom/current_parent = parent
		requested_amount = input(user, "How much do you want to insert?", "Inserting sheets") as num|null
		if(isnull(requested_amount) || (requested_amount <= 0))
			return
		if(QDELETED(I) || QDELETED(user) || QDELETED(src) || parent != current_parent || !user.canUseTopic(current_parent) || !user.is_holding(I) || !user.Adjacent(current_parent))
			return
	if(!user.temporarilyRemoveItemFromInventory(I))
		to_chat(user, "<span class='warning'>[I] is stuck to you and cannot be placed into [parent].</span>")
		return
	var/inserted = insert_item(I, stack_amt = requested_amount)
	if(inserted)
		last_insert_success = TRUE
		if(istype(I, /obj/item/stack))
			to_chat(user, "<span class='notice'>You insert [inserted] sheet[inserted>1 ? "s" : ""] into [parent].</span>")
			if(!QDELETED(I))
				user.put_in_active_hand(I)
		else
			to_chat(user, "<span class='notice'>You insert a material total of [inserted] into [parent].</span>")
			qdel(I)
	else
		user.put_in_active_hand(I)

//For inserting an amount of material
/datum/component/material_container/proc/insert_amount(amt, id = null)
	if(amt > 0 && has_space(amt))
		var/total_amount_saved = total_amount
		if(id)
			var/datum/material/M = materials[id]
			if(M)
				M.amount += amt
				total_amount += amt
		else
			for(var/i in materials)
				var/datum/material/M = materials[i]
				M.amount += amt
				total_amount += amt
		return (total_amount - total_amount_saved)
	return FALSE

/datum/component/material_container/proc/insert_stack(obj/item/stack/S, amt)
	if(isnull(amt))
		amt = S.amount

	if(amt <= 0)
		return FALSE

	if(amt > S.amount)
		amt = S.amount

	var/material_amt = get_item_material_amount(S)
	if(!material_amt)
		return FALSE

	amt = min(amt, round(((max_amount - total_amount) / material_amt)))
	if(!amt)
		return FALSE

	last_inserted_id = insert_materials(S,amt)
	last_inserted_type = S.type
	S.use(amt)
	last_amount_inserted = amt
	return amt

/datum/component/material_container/proc/insert_item(obj/item/I, multiplier = 1, stack_amt)
	if(!I)
		return FALSE
	if(istype(I, /obj/item/stack))
		return insert_stack(I, stack_amt)

	var/material_amount = get_item_material_amount(I)
	if(!material_amount || !has_space(material_amount))
{'fraction_non_alphanumeric': 0.12032998293191731, 'fraction_numerical': 0.0045514887161008915, 'mean_word_length': 4.931946006749157, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 37, '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': '1680639', 'n_tokens_mistral': 4009, 'n_tokens_neox': 3810, 'n_words': 822}