[MIRROR] Refactors for material container, ammo box & recycler [MDB IGNORE] (#21519)

* Refactors for material container, ammo box & recycler

* Mirror!

* Modular!

---------

Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: Funce <funce.973@gmail.com>
This commit is contained in:
SkyratBot
2023-06-02 01:24:54 +02:00
committed by GitHub
parent 8c0af345d8
commit 24552f5f95
7 changed files with 189 additions and 125 deletions
+147 -65
View File
@@ -116,82 +116,164 @@
examine_texts += span_notice("It has [amt] units of [lowertext(M.name)] stored.")
/// Proc that allows players to fill the parent with mats
/datum/component/material_container/proc/on_attackby(datum/source, obj/item/I, mob/living/user)
/datum/component/material_container/proc/on_attackby(datum/source, obj/item/weapon, mob/living/user)
SIGNAL_HANDLER
var/list/tc = allowed_item_typecache
if(!(mat_container_flags & MATCONTAINER_ANY_INTENT) && user.combat_mode)
return
if(I.item_flags & ABSTRACT)
return
if((I.flags_1 & HOLOGRAM_1) || (I.item_flags & NO_MAT_REDEMPTION) || (tc && !is_type_in_typecache(I, tc)))
if(!(mat_container_flags & MATCONTAINER_SILENT))
to_chat(user, span_warning("[parent] won't accept [I]!"))
return
. = COMPONENT_NO_AFTERATTACK
var/datum/callback/pc = precondition
if(pc && !pc.Invoke(user))
return
var/material_amount = get_item_material_amount(I, mat_container_flags)
if(!material_amount)
to_chat(user, span_warning("[I] does not contain sufficient materials to be accepted by [parent]."))
return
if(!has_space(material_amount))
if(isstack(I))
//figure out how much space is left
var/space_left = max_amount - total_amount
//figure out the amount of sheets that can fit that space
var/obj/item/stack/stack_to_split = I
var/material_per_sheet = material_amount / stack_to_split.amount
var/sheets_to_insert = round(space_left / material_per_sheet)
if(!sheets_to_insert)
to_chat(user, span_warning("[parent] can't hold any more of [I] sheets."))
return
//split the amount we don't need off
INVOKE_ASYNC(stack_to_split, TYPE_PROC_REF(/obj/item/stack, split_stack), user, stack_to_split.amount - sheets_to_insert)
else
to_chat(user, span_warning("[I] contains more materials than [parent] has space to hold."))
return
user_insert(I, user, mat_container_flags)
user_insert(weapon, user)
/// Proc used for when player inserts materials
return COMPONENT_NO_AFTERATTACK
/**
* inserts an item from the players hand into the container. Loops through all the contents inside reccursively
* Arguments
* * held_item - the item to insert
* * user - the mob inserting this item
* * breakdown_flags - how this item and all it's contents inside are broken down during insertion. This is unique to the machine doing the insertion
*/
/datum/component/material_container/proc/user_insert(obj/item/held_item, mob/living/user, breakdown_flags = mat_container_flags)
set waitfor = FALSE
var/requested_amount
var/active_held = user.get_active_held_item() // differs from I when using TK
if(isstack(held_item) && precise_insertion)
var/atom/current_parent = parent
var/obj/item/stack/item_stack = held_item
requested_amount = tgui_input_number(user, "How much do you want to insert?", "Inserting [item_stack.singular_name]s", item_stack.amount, item_stack.amount)
if(!requested_amount || QDELETED(held_item) || QDELETED(user) || QDELETED(src))
return
if(parent != current_parent || user.get_active_held_item() != active_held)
return
if(!user.temporarilyRemoveItemFromInventory(held_item))
to_chat(user, span_warning("[held_item] is stuck to you and cannot be placed into [parent]."))
. = 0
//differs from held_item when using TK
var/active_held = user.get_active_held_item()
//don't attack the machine
if(!(mat_container_flags & MATCONTAINER_ANY_INTENT) && user.combat_mode)
return
var/inserted = insert_item(held_item, stack_amt = requested_amount, breakdown_flags= mat_container_flags)
if(inserted)
to_chat(user, span_notice("You insert a material total of [inserted] into [parent]."))
qdel(held_item)
if(after_insert)
after_insert.Invoke(held_item, last_inserted_id, inserted)
else if(held_item == active_held)
user.put_in_active_hand(held_item)
//user defined conditions
if(precondition && !precondition.Invoke(user))
return
//loop through all contents inside this atom and salvage their material as well but in reverse so we don't delete parents before processing their children
var/list/contents = held_item.get_all_contents_type(/obj/item)
for(var/i = length(contents); i >= 1 ; i--)
var/obj/item/target = contents[i]
//not a solid sub type
if(target.item_flags & ABSTRACT)
if(target == active_held) //was this the original item in the players hand? put it back because we coudn't salvage it
user.put_in_active_hand(target)
continue
//item is either not real, not allowed for redemption, not in the allowed types
if((target.flags_1 & HOLOGRAM_1) || (target.item_flags & NO_MAT_REDEMPTION) || (allowed_item_typecache && !is_type_in_typecache(target, allowed_item_typecache)))
if(!(mat_container_flags & MATCONTAINER_SILENT))
to_chat(user, span_warning("[parent] won't accept [target]!"))
if(target == active_held) //was this the original item in the players hand? put it back because we coudn't salvage it
user.put_in_active_hand(target)
continue
//if stack, check if we want to read precise amount of sheets to insert
var/obj/item/stack/item_stack = null
if(isstack(target) && precise_insertion)
var/atom/current_parent = parent
item_stack = target
var/requested_amount = tgui_input_number(user, "How much do you want to insert?", "Inserting [item_stack.singular_name]s", item_stack.amount, item_stack.amount)
if(!requested_amount || QDELETED(target) || QDELETED(user) || QDELETED(src))
continue
if(parent != current_parent || user.get_active_held_item() != active_held)
continue
if(requested_amount != item_stack.amount) //only split if its not the whole amount
target = split_stack(item_stack, requested_amount) //split off the requested amount
requested_amount = 0
//is this item a stack and was it split by the player?
var/was_stack_split = !isnull(item_stack) && item_stack != target
//if it was split then item_stack has the reference to the original stack/item
var/original_item = was_stack_split ? item_stack : target
//if this item is not the one the player is holding then don't remove it from their hand
if(original_item != active_held)
original_item = null
if(!isnull(original_item) && !user.temporarilyRemoveItemFromInventory(original_item)) //remove from hand(if split remove the original stack else the target)
to_chat(user, span_warning("[held_item] is stuck to you and cannot be placed into [parent]."))
return
//insert the item
var/inserted = insert_item(target, breakdown_flags = mat_container_flags)
if(inserted > 0)
. += inserted
//stack was either split by the container(!QDELETED(target) means the container only consumed a part of it) or by the player, put whats left back of the original stack back in players hand
if((!QDELETED(target) || was_stack_split))
//stack was split by player and that portion was not fully consumed, merge whats left back with the original stack
if(!QDELETED(target) && was_stack_split)
var/obj/item/stack/inserting_stack = target
item_stack.add(inserting_stack.amount)
qdel(inserting_stack)
//was this the original item in the players hand? put what's left back in the player's hand
if(!isnull(original_item))
user.put_in_active_hand(original_item)
to_chat(user, span_notice("You insert a material total of [inserted] into [parent]."))
else
//decode the error & print it
var/error_msg
if(inserted == -2)
error_msg = "[parent] has insufficient space to accept the [target]"
else
error_msg = "[target] has insufficient materials to be accepted by [parent]"
to_chat(user, span_warning(error_msg))
//player split the stack by the requested amount but even that split amount could not be salvaged. merge it back with the original
if(!isnull(item_stack) && was_stack_split)
var/obj/item/stack/inserting_stack = target
item_stack.add(inserting_stack.amount)
qdel(inserting_stack)
//was this the original item in the players hand? put it back because we coudn't salvage it
if(!isnull(original_item))
user.put_in_active_hand(original_item)
/**
* Splits a stack. we don't use /obj/item/stack/proc/split_stack because Byond complains that should only be called asynchronously.
* This proc is also more faster because it doesn't deal with mobs, copying evidences or refreshing atom storages
*/
/datum/component/material_container/proc/split_stack(obj/item/stack/target, amount)
if(!target.use(amount, TRUE, FALSE))
return null
. = new target.type(target.drop_location(), amount, FALSE, target.mats_per_unit)
target.loc.atom_storage?.refresh_views()
target.is_zero_amount(delete_if_zero = TRUE)
/// Proc specifically for inserting items, returns the amount of materials entered.
/datum/component/material_container/proc/insert_item(obj/item/I, multiplier = 1, stack_amt, breakdown_flags = mat_container_flags)
if(QDELETED(I))
return FALSE
/datum/component/material_container/proc/insert_item(obj/item/weapon, multiplier = 1, breakdown_flags = mat_container_flags)
if(QDELETED(weapon))
return -1
multiplier = CEILING(multiplier, 0.01)
var/material_amount = get_item_material_amount(I, breakdown_flags)
if(!material_amount || !has_space(material_amount))
return FALSE
var/obj/item/target = weapon
last_inserted_id = insert_item_materials(I, multiplier, breakdown_flags)
return material_amount
var/material_amount = get_item_material_amount(target, breakdown_flags) * multiplier
if(!material_amount)
return -1
var/obj/item/stack/item_stack
if(isstack(weapon) && !has_space(material_amount)) //not enugh space split and feed as many sheets possible
item_stack = weapon
var/space_left = max_amount - total_amount
if(!space_left)
return -2
var/material_per_sheet = material_amount / item_stack.amount
var/sheets_to_insert = round(space_left / material_per_sheet)
if(!sheets_to_insert)
return -2
target = split_stack(item_stack, sheets_to_insert)
material_amount = get_item_material_amount(target, breakdown_flags) * multiplier
if(!has_space(material_amount))
return -2
last_inserted_id = insert_item_materials(target, multiplier, breakdown_flags)
if(!isnull(last_inserted_id))
if(after_insert)
after_insert.Invoke(target, last_inserted_id, material_amount)
qdel(target) //item gone
return material_amount
else if(!isnull(item_stack) && item_stack != target) //insertion failed, merge the split stack back into the original
var/obj/item/stack/inserting_stack = target
item_stack.add(inserting_stack.amount)
qdel(inserting_stack)
return 0
/**
* Inserts the relevant materials from an item into this material container.
+28 -20
View File
@@ -150,35 +150,44 @@
if(obj_flags & EMAGGED)
for(var/CRUNCH in crunchy_nom) // Eat them and keep going because we don't care about safety.
if(isliving(CRUNCH)) // MMIs and brains will get eaten like normal items
if(!is_operational) //we ran out of power after recycling a large amount to living stuff, time to stop
break
crush_living(CRUNCH)
use_power(active_power_usage)
else // Stop processing right now without eating anything.
emergency_stop()
return
for(var/nommed in nom)
recycle_item(nommed)
use_power(active_power_usage)
if(nom.len && sound)
playsound(src, item_recycle_sound, (50 + nom.len*5), TRUE, nom.len, ignore_walls = (nom.len - 10)) // As a substitute for playing 50 sounds at once.
if(not_eaten)
playsound(src, 'sound/machines/buzz-sigh.ogg', (50 + not_eaten*5), FALSE, not_eaten, ignore_walls = (not_eaten - 10)) // Ditto.
if(!ismob(morsel))
qdel(morsel)
/obj/machinery/recycler/proc/recycle_item(obj/item/I)
var/obj/item/grown/log/L = I
if(istype(L))
/**
* we process the list in reverse so that atoms without parents/contents are deleted first & their parents are deleted next & so on.
* this is the reverse order in which get_all_contents() returns it's list
* if we delete an atom containing stuff then all its stuff are deleted with it as well so we will end recycling deleted items down the list and gain nothing from them
*/
for(var/i = length(nom); i >= 1; i--)
if(!is_operational) //we ran out of power after recycling a large amount to items, time to stop
break
use_power(active_power_usage / (recycle_item(nom[i]) ? 1 : 2)) //recycling stuff that produces no material takes just half the power
if(nom.len && sound)
playsound(src, item_recycle_sound, (50 + nom.len * 5), TRUE, nom.len, ignore_walls = (nom.len - 10)) // As a substitute for playing 50 sounds at once.
if(not_eaten)
playsound(src, 'sound/machines/buzz-sigh.ogg', (50 + not_eaten * 5), FALSE, not_eaten, ignore_walls = (not_eaten - 10)) // Ditto.
/obj/machinery/recycler/proc/recycle_item(obj/item/weapon)
. = FALSE
var/obj/item/grown/log/wood = weapon
if(istype(wood))
var/seed_modifier = 0
if(L.seed)
seed_modifier = round(L.seed.potency / 25)
new L.plank_type(loc, 1 + seed_modifier)
if(wood.seed)
seed_modifier = round(wood.seed.potency / 25)
new wood.plank_type(loc, 1 + seed_modifier)
. = TRUE
else
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/material_amount = materials.get_item_material_amount(I, BREAKDOWN_FLAGS_RECYCLER)
if(material_amount)
materials.insert_item(I, material_amount, multiplier = (amount_produced / 100), breakdown_flags=BREAKDOWN_FLAGS_RECYCLER)
var/retrived = materials.insert_item(weapon, multiplier = (amount_produced / 100), breakdown_flags=BREAKDOWN_FLAGS_RECYCLER)
if(retrived > 0) //item was salvaged i.e. deleted
materials.retrieve_all()
qdel(I)
return TRUE
qdel(weapon)
/obj/machinery/recycler/proc/emergency_stop()
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
@@ -192,7 +201,6 @@
update_appearance()
/obj/machinery/recycler/proc/crush_living(mob/living/L)
L.forceMove(loc)
if(issilicon(L))
+1 -2
View File
@@ -171,8 +171,7 @@
if(!materials.has_space(material_amount))
unload_mineral(O)
else
materials.insert_item(O, breakdown_flags=BREAKDOWN_FLAGS_ORE_PROCESSOR)
qdel(O)
materials.insert_item(O, breakdown_flags = BREAKDOWN_FLAGS_ORE_PROCESSOR)
if(mineral_machine)
mineral_machine.updateUsrDialog()
+8 -7
View File
@@ -75,9 +75,6 @@
if(gathered_ore.refined_type == null)
return
if(gathered_ore?.refined_type)
points += gathered_ore.points * point_upgrade * gathered_ore.amount
var/material_amount = mat_container.get_item_material_amount(gathered_ore, BREAKDOWN_FLAGS_ORM)
if(!material_amount)
@@ -89,10 +86,14 @@
else
var/list/stack_mats = gathered_ore.get_material_composition(BREAKDOWN_FLAGS_ORM)
var/mats = stack_mats & mat_container.materials
var/amount = gathered_ore.amount
mat_container.insert_item(gathered_ore, ore_multiplier, breakdown_flags=BREAKDOWN_FLAGS_ORM) //insert it
materials.silo_log(src, "smelted", amount, gathered_ore.name, mats)
qdel(gathered_ore)
var/ore_amount = gathered_ore.amount
var/ore_points= gathered_ore.points
var/ore_name = gathered_ore.name
var/refined_type = gathered_ore?.refined_type
if(mat_container.insert_item(gathered_ore, ore_multiplier, breakdown_flags = BREAKDOWN_FLAGS_ORM) > 0) //increase points only if insertion was successfull
if(refined_type)
points += ore_points * point_upgrade * ore_amount
materials.silo_log(src, "smelted", ore_amount, ore_name, mats)
SEND_SIGNAL(src, COMSIG_ORM_COLLECTED_ORE)
-1
View File
@@ -142,7 +142,6 @@
if (length(matlist))
var/inserted = materials.mat_container.insert_item(inp)
materials.silo_log(src, "collected", inserted, "sheets", matlist)
qdel(inp)
return
// No silo attached process to internal storage
@@ -31,10 +31,6 @@
var/multiload = TRUE
///Whether the magazine should start with nothing in it
var/start_empty = FALSE
///cost of all the bullets in the magazine/box
var/list/bullet_cost
///cost of the materials in the magazine/box itself
var/list/base_cost
/// If this and ammo_band_icon aren't null, run update_ammo_band(). Is the color of the band, such as blue on the detective's Iceblox.
var/ammo_band_color
@@ -45,9 +41,7 @@
/obj/item/ammo_box/Initialize(mapload)
. = ..()
if(!bullet_cost)
base_cost = SSmaterials.FindOrCreateMaterialCombo(custom_materials, 0.1)
bullet_cost = SSmaterials.FindOrCreateMaterialCombo(custom_materials, 0.9 / max_ammo)
custom_materials = SSmaterials.FindOrCreateMaterialCombo(custom_materials, 0.1)
if(!start_empty)
top_off(starting=TRUE)
update_icon_state()
@@ -91,7 +85,7 @@
for(var/i in max(1, stored_ammo.len) to max_ammo)
stored_ammo += new round_check() //SKYRAT EDTI CHANGE - SEC_HUAL - Moving to nullspace seems to help with lag.
update_ammo_count()
update_appearance()
///gets a round from the magazine, if keep is TRUE the round will stay in the gun
/obj/item/ammo_box/proc/get_round(keep = FALSE)
@@ -145,7 +139,7 @@
if(!did_load || !multiload)
break
if(num_loaded)
AM.update_ammo_count()
AM.update_appearance()
if(isammocasing(A))
var/obj/item/ammo_casing/AC = A
if(give_round(AC, replace_spent))
@@ -157,7 +151,7 @@
if(!silent)
to_chat(user, span_notice("You load [num_loaded] shell\s into \the [src]!"))
playsound(src, 'sound/weapons/gun/general/mag_bullet_insert.ogg', 60, TRUE)
update_ammo_count()
update_appearance()
return num_loaded
@@ -171,11 +165,6 @@
A.bounce_away(FALSE, NONE)
playsound(src, 'sound/weapons/gun/general/mag_bullet_insert.ogg', 60, TRUE)
to_chat(user, span_notice("You remove a round from [src]!"))
update_ammo_count()
/// Updates the materials and appearance of this ammo box
/obj/item/ammo_box/proc/update_ammo_count()
update_custom_materials()
update_appearance()
/obj/item/ammo_box/update_desc(updates)
@@ -206,13 +195,6 @@
ammo_band_image.appearance_flags = RESET_COLOR|KEEP_APART
overlays += ammo_band_image
/// Updates the amount of material in this ammo box according to how many bullets are left in it.
/obj/item/ammo_box/proc/update_custom_materials()
var/temp_materials = custom_materials.Copy()
for(var/material in bullet_cost)
temp_materials[material] = (bullet_cost[material] * stored_ammo.len) + base_cost[material]
set_custom_materials(temp_materials)
///Count of number of bullets in the magazine
/obj/item/ammo_box/magazine/proc/ammo_count(countempties = TRUE)
var/boolets = 0
@@ -237,7 +219,7 @@
/obj/item/ammo_box/magazine/handle_atom_del(atom/A)
stored_ammo -= A
update_ammo_count()
update_appearance()
//SKRYAT EDIT ADDITION BEGIN - SEC_HAUL
/obj/item/ammo_box/Destroy()
@@ -138,13 +138,6 @@
if(AMMO_BOX_FULL_EMPTY)
icon_state = "[initial(icon_state)]_[round_type]-[shells_left ? "full" : "empty"]"
desc = "[initial(desc)] There [(shells_left == 1) ? "is" : "are"] [shells_left] shell\s left!"
if(length(bullet_cost))
var/temp_materials = custom_materials.Copy()
for (var/material in bullet_cost)
var/material_amount = bullet_cost[material]
material_amount = (material_amount*stored_ammo.len) + base_cost[material]
temp_materials[material] = material_amount
set_custom_materials(temp_materials)
/obj/item/ammo_box/revolver
name = "speed loader"