diff --git a/code/__DEFINES/dcs/signals/signals_material_container.dm b/code/__DEFINES/dcs/signals/signals_material_container.dm new file mode 100644 index 00000000000..3f9ab395175 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_material_container.dm @@ -0,0 +1,11 @@ +//Material Container Signals +/// Called from datum/component/material_container/proc/can_hold_material() : (mat) +#define COMSIG_MATCONTAINER_MAT_CHECK "matcontainer_mat_check" + #define MATCONTAINER_ALLOW_MAT (1<<0) +/// Called from datum/component/material_container/proc/user_insert() : (held_item, user) +#define COMSIG_MATCONTAINER_PRE_USER_INSERT "matcontainer_pre_user_insert" + #define MATCONTAINER_BLOCK_INSERT (1<<1) +/// Called from datum/component/material_container/proc/insert_item() : (target, last_inserted_id, material_amount, container) +#define COMSIG_MATCONTAINER_ITEM_CONSUMED "matcontainer_item_consumed" +/// Called from datum/component/material_container/proc/retrieve_sheets() : (sheets) +#define COMSIG_MATCONTAINER_SHEETS_RETRIVED "matcontainer_sheets_retrived" diff --git a/code/__DEFINES/materials.dm b/code/__DEFINES/materials.dm index f58ec028dbb..08b88324826 100644 --- a/code/__DEFINES/materials.dm +++ b/code/__DEFINES/materials.dm @@ -15,6 +15,9 @@ /// Used to make a material type able to be instantiated on demand after roundstart. #define MATERIAL_INIT_BESPOKE (1<<1) +/// Makes sure only integer values are used when consuming, removing & checking for mats +#define OPTIMAL_COST(cost)(max(1, round(cost))) + //Material Container Flags. ///If the container shows the amount of contained materials on examine. #define MATCONTAINER_EXAMINE (1<<0) diff --git a/code/__HELPERS/construction.dm b/code/__HELPERS/construction.dm index ad9f24cef3c..add76c0f9ce 100644 --- a/code/__HELPERS/construction.dm +++ b/code/__HELPERS/construction.dm @@ -8,3 +8,44 @@ ) else return defaults + +/** + * Turns material amount into the number of sheets, returning FALSE if the number is less than SHEET_MATERIAL_AMOUNT + * + * Arguments: + * - amt: amount to convert + */ +/proc/amount2sheet(amt) + if(amt >= SHEET_MATERIAL_AMOUNT) + return round(amt / SHEET_MATERIAL_AMOUNT) + return 0 + +/** + * Turns number of sheets into material amount, returning FALSE if the number is <= 0 + * + * Arguments: + * - amt: amount to convert + */ +/proc/sheet2amount(sheet_amt) + if(sheet_amt > 0) + return sheet_amt * SHEET_MATERIAL_AMOUNT + return 0 + +/** + * Splits a stack. we don't use /obj/item/stack/proc/fast_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 + * Has special internal uses for e.g. by the material container + * + * Arguments: + * - [target][obj/item]: the stack to splot + * - [amount]: amount to split by + */ +/datum/component/material_container/proc/fast_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) + diff --git a/code/datums/components/material_container.dm b/code/datums/components/material/material_container.dm similarity index 66% rename from code/datums/components/material_container.dm rename to code/datums/components/material/material_container.dm index af9b3f32903..02d73b51055 100644 --- a/code/datums/components/material_container.dm +++ b/code/datums/components/material/material_container.dm @@ -10,8 +10,6 @@ */ /datum/component/material_container - /// The total amount of materials this material container contains - var/total_amount = 0 /// The maximum amount of materials this material container can contain var/max_amount /// Map of material ref -> amount @@ -20,31 +18,22 @@ var/list/allowed_materials /// The typecache of things that this material container can accept var/list/allowed_item_typecache - /// The last main material that was inserted into this container - var/last_inserted_id /// Whether or not this material container allows specific amounts from sheets to be inserted var/precise_insertion = FALSE - /// A callback for checking wheter we can insert a material into this container - var/datum/callback/insertion_check - /// A callback invoked before materials are inserted into this container - var/datum/callback/precondition - /// A callback invoked after materials are inserted into this container - var/datum/callback/after_insert - /// A callback invoked after sheets are retrieve from this container - var/datum/callback/after_retrieve /// The material container flags. See __DEFINES/materials.dm. var/mat_container_flags + /// Signals that are registered with this contained + var/list/registered_signals /// Sets up the proper signals and fills the list of materials with the appropriate references. -/datum/component/material_container/Initialize(list/init_mats, +/datum/component/material_container/Initialize( + list/init_mats, max_amt = 0, - _mat_container_flags=NONE, - list/allowed_mats=init_mats, + _mat_container_flags = NONE, + list/allowed_mats = init_mats, list/allowed_items, - datum/callback/_insertion_check, - datum/callback/_precondition, - datum/callback/_after_insert, - datum/callback/_after_retrieve) + list/container_signals + ) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE @@ -60,11 +49,6 @@ else allowed_item_typecache = typecacheof(allowed_items) - insertion_check = _insertion_check - precondition = _precondition - after_insert = _after_insert - after_retrieve = _after_retrieve - for(var/mat in init_mats) //Make the assoc list material reference -> amount var/mat_ref = GET_MATERIAL_REF(mat) if(isnull(mat_ref)) @@ -74,6 +58,11 @@ mat_amt = 0 materials[mat_ref] += mat_amt + //all user handled signals + if(length(container_signals)) + for(var/signal in container_signals) + parent.RegisterSignal(src, signal, container_signals[signal]) + if(_mat_container_flags & MATCONTAINER_NO_INSERT) return @@ -83,19 +72,11 @@ RegisterSignal(atom_target, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) /datum/component/material_container/Destroy(force, silent) + retrieve_all() materials = null allowed_materials = null - if(insertion_check) - QDEL_NULL(insertion_check) - if(precondition) - QDEL_NULL(precondition) - if(after_insert) - QDEL_NULL(after_insert) - if(after_retrieve) - QDEL_NULL(after_retrieve) return ..() - /datum/component/material_container/RegisterWithParent() . = ..() @@ -104,6 +85,14 @@ if(mat_container_flags & MATCONTAINER_EXAMINE) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) +/datum/component/material_container/proc/on_examine(datum/source, mob/user, list/examine_texts) + SIGNAL_HANDLER + + for(var/I in materials) + var/datum/material/M = I + var/amt = materials[I] / SHEET_MATERIAL_AMOUNT + if(amt) + examine_texts += span_notice("It has [amt] sheets of [lowertext(M.name)] stored.") /datum/component/material_container/vv_edit_var(var_name, var_value) var/old_flags = mat_container_flags @@ -119,27 +108,137 @@ else if(!(old_flags & MATCONTAINER_NO_INSERT) && mat_container_flags & MATCONTAINER_NO_INSERT) UnregisterSignal(parent, COMSIG_ATOM_ATTACKBY) +/** + * 3 Types of Procs + * Material Insertion : Insert materials into the container + * Material Validation : Checks how much materials are available, Extracts materials from items if the container can hold them + * Material Removal : Removes material from the container + * + * Each Proc furthur belongs to a specific category + * LOW LEVEL: Procs that are used internally & should not be used anywhere else unless you know what your doing + * MID LEVEL: Procs that can be used by machines(like recycler, stacking machines) to bypass majority of checks + * HIGH LEVEL: Procs that can be used by anyone publically and guarentees safty checks & limits + */ -/datum/component/material_container/proc/on_examine(datum/source, mob/user, list/examine_texts) - SIGNAL_HANDLER +//================================Material Insertion procs============================== - for(var/I in materials) - var/datum/material/M = I - var/amt = materials[I] - if(amt) - examine_texts += span_notice("It has [amt] units of [lowertext(M.name)] stored.") +//======================================LOW LEVEL========================================= +/** + * Inserts the relevant materials from an item into this material container. + * This low level proc should not be used directly by anyone + * + * Arguments: + * - [source][/obj/item]: The source of the materials we are inserting. + * - multiplier: The multiplier for the materials extract from this item being inserted. + * - breakdown_flags: The breakdown bitflags that will be used to retrieve the materials from the source + */ +/datum/component/material_container/proc/insert_item_materials(obj/item/source, multiplier = 1, breakdown_flags = mat_container_flags) + var/primary_mat + var/max_mat_value = 0 -/// Proc that allows players to fill the parent with mats -/datum/component/material_container/proc/on_attackby(datum/source, obj/item/weapon, mob/living/user) - SIGNAL_HANDLER + var/list/item_materials = source.get_material_composition(breakdown_flags) + for(var/MAT in item_materials) + if(!can_hold_material(MAT)) + continue + materials[MAT] += OPTIMAL_COST(item_materials[MAT] * multiplier) + if(item_materials[MAT] > max_mat_value) + max_mat_value = item_materials[MAT] + primary_mat = MAT - user_insert(weapon, user) + return primary_mat +//=================================================================================== - return COMPONENT_NO_AFTERATTACK + +//===============================MID LEVEL=================================================== +/** + * For inserting an amount of material. Use this to add materials to the container directly + * + * Arguments: + * - amt: amount of said material to insert + * - mat: the material type to insert + */ +/datum/component/material_container/proc/insert_amount_mat(amt, datum/material/mat) + if(amt <= 0) + return 0 + amt = OPTIMAL_COST(amt) + if(!has_space(amt)) + return 0 + + var/total_amount_saved = total_amount() + if(mat) + if(!istype(mat)) + mat = GET_MATERIAL_REF(mat) + materials[mat] += amt + else + var/num_materials = length(materials) + if(!num_materials) + return 0 + + amt /= num_materials + for(var/i in materials) + materials[i] += amt + return (total_amount() - total_amount_saved) +/** + * Proc specifically for inserting items, use this when you want to insert any item into the container + * this bypasses most of the material flag checks so much be used by machines like recycler, stacking machine etc that + * does not care for such checks + * + * Arguments: + * - [weapon][obj/item]: the item you are trying to insert + * - multiplier: The multiplier for the materials being inserted + * - breakdown_flags: The breakdown bitflags that will be used to retrieve the materials from the source + */ +/datum/component/material_container/proc/insert_item(obj/item/weapon, multiplier = 1, breakdown_flags = mat_container_flags) + if(QDELETED(weapon)) + return MATERIAL_INSERT_ITEM_NO_MATS + multiplier = CEILING(multiplier, 0.01) + + var/obj/item/target = weapon + + var/material_amount = get_item_material_amount(target, breakdown_flags) * multiplier + if(!material_amount) + return MATERIAL_INSERT_ITEM_NO_MATS + var/obj/item/stack/item_stack + if(isstack(weapon) && !has_space(material_amount)) //not enough space split and feed as many sheets possible + item_stack = weapon + var/space_left = max_amount - total_amount() + if(!space_left) + return MATERIAL_INSERT_ITEM_NO_SPACE + var/material_per_sheet = material_amount / item_stack.amount + var/sheets_to_insert = round(space_left / material_per_sheet) + if(!sheets_to_insert) + return MATERIAL_INSERT_ITEM_NO_SPACE + target = fast_split_stack(item_stack, sheets_to_insert) + material_amount = get_item_material_amount(target, breakdown_flags) * multiplier + material_amount = OPTIMAL_COST(material_amount) + + //not enough space, time to bail + if(!has_space(material_amount)) + return MATERIAL_INSERT_ITEM_NO_SPACE + + //do the insert + var/last_inserted_id = insert_item_materials(target, multiplier, breakdown_flags) + if(!isnull(last_inserted_id)) + SEND_SIGNAL(src, COMSIG_MATCONTAINER_ITEM_CONSUMED, target, last_inserted_id, material_amount, src) + 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 MATERIAL_INSERT_ITEM_FAILURE +//============================================================================================ + + +//===================================HIGH LEVEL=================================================== /** * inserts an item from the players hand into the container. Loops through all the contents inside reccursively - * Arguments + * Does all explicit checking for mat flags & callbacks to check if insertion is valid + * This proc is what you should be using for almost all cases + * + * 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 @@ -160,7 +259,7 @@ if(held_item.resistance_flags & INDESTRUCTIBLE) return //user defined conditions - if(precondition && !precondition.Invoke(user)) + if(SEND_SIGNAL(src, COMSIG_MATCONTAINER_PRE_USER_INSERT, held_item, user) & MATCONTAINER_BLOCK_INSERT) return //get all contents of this item reccursively @@ -216,7 +315,7 @@ 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 + target = fast_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? @@ -235,6 +334,7 @@ var/inserted = insert_item(target, breakdown_flags = mat_container_flags) if(inserted > 0) . += inserted + inserted /= SHEET_MATERIAL_AMOUNT // display units inserted as sheets for improved readability var/message = null //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 @@ -249,21 +349,23 @@ //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) - message = "Only [inserted] amount of [item_name] was consumed by [parent]." + message = "Only [inserted] sheets of [item_name] was consumed by [parent]." //collect all messages to print later if(!message) - message = "[item_name] worth [inserted] material was consumed by [parent]." + message = "[item_name] worth [inserted] sheets of material was consumed by [parent]." if(inserts[message]) inserts[message] += 1 else inserts[message] = 1 else var/error_msg - if(inserted == -2) + if(inserted == MATERIAL_INSERT_ITEM_NO_SPACE) error_msg = "[parent] has insufficient space to accept [target]" - else + else if(inserted == MATERIAL_INSERT_ITEM_NO_MATS) error_msg = "[target] has insufficient materials to be accepted by [parent]" + else + error_msg = "[parent] refuses to accept [target]" //collect all messages to print later if(errors[error_msg]) @@ -293,79 +395,27 @@ for(var/i in 1 to count) to_chat(user, span_warning(error_msg)) +/// Proc that allows players to fill the parent with mats +/datum/component/material_container/proc/on_attackby(datum/source, obj/item/weapon, mob/living/user) + SIGNAL_HANDLER + + user_insert(weapon, user) + + return COMPONENT_NO_AFTERATTACK +//=============================================================================================== + + +//======================================Material Validation======================================= + +//=========================================LOW LEVEL=================================== /** - * 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/weapon, multiplier = 1, breakdown_flags = mat_container_flags) - if(QDELETED(weapon)) - return MATERIAL_INSERT_ITEM_NO_MATS - multiplier = CEILING(multiplier, 0.01) - - var/obj/item/target = weapon - - var/material_amount = get_item_material_amount(target, breakdown_flags) * multiplier - if(!material_amount) - return MATERIAL_INSERT_ITEM_NO_MATS - 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 MATERIAL_INSERT_ITEM_NO_SPACE - var/material_per_sheet = material_amount / item_stack.amount - var/sheets_to_insert = round(space_left / material_per_sheet) - if(!sheets_to_insert) - return MATERIAL_INSERT_ITEM_NO_SPACE - target = split_stack(item_stack, sheets_to_insert) - material_amount = get_item_material_amount(target, breakdown_flags) * multiplier - if(!has_space(material_amount)) - return MATERIAL_INSERT_ITEM_NO_SPACE - - 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, src) - 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 MATERIAL_INSERT_ITEM_FAILURE - -/** - * Inserts the relevant materials from an item into this material container. + * Proc that returns TRUE if the container has space * * Arguments: - * - [source][/obj/item]: The source of the materials we are inserting. - * - multiplier: The multiplier for the materials being inserted. - * - breakdown_flags: The breakdown bitflags that will be used to retrieve the materials from the source + * - amt: can this container hold this much amount of materials */ -/datum/component/material_container/proc/insert_item_materials(obj/item/source, multiplier = 1, breakdown_flags = mat_container_flags) - var/primary_mat - var/max_mat_value = 0 - var/list/item_materials = source.get_material_composition(breakdown_flags) - for(var/MAT in item_materials) - if(!can_hold_material(MAT)) - continue - materials[MAT] += item_materials[MAT] * multiplier - total_amount += item_materials[MAT] * multiplier - if(item_materials[MAT] > max_mat_value) - max_mat_value = item_materials[MAT] - primary_mat = MAT - - return primary_mat +/datum/component/material_container/proc/has_space(amt = 0) + return (total_amount() + amt) <= max_amount /** * The default check for whether we can add materials to this material container. @@ -379,102 +429,146 @@ if(istype(mat) && ((mat.id in allowed_materials) || (mat.type in allowed_materials))) allowed_materials += mat // This could get messy with passing lists by ref... but if you're doing that the list expansion is probably being taken care of elsewhere anyway... return TRUE - if(insertion_check?.Invoke(mat)) + if(SEND_SIGNAL(src, COMSIG_MATCONTAINER_MAT_CHECK, mat) & MATCONTAINER_ALLOW_MAT) allowed_materials += mat return TRUE return FALSE +//======================================================================================== -/// For inserting an amount of material -/datum/component/material_container/proc/insert_amount_mat(amt, datum/material/mat) - if(amt <= 0 || !has_space(amt)) - return 0 - var/total_amount_saved = total_amount - if(mat) - if(!istype(mat)) - mat = GET_MATERIAL_REF(mat) - materials[mat] += amt - else - var/num_materials = length(materials) - if(!num_materials) - return 0 - - amt /= num_materials - for(var/i in materials) - materials[i] += amt - total_amount += amt - return (total_amount - total_amount_saved) - -/// Uses an amount of a specific material, effectively removing it. -/datum/component/material_container/proc/use_amount_mat(amt, datum/material/mat) +//===================================MID LEVEL============================================= +/** + * Returns the amount of a specific material in this container. + * + * Arguments: + * -[mat][datum/material] : the material type to check for 3 cases + * a) If it's an path its ref is retrived + * b) If it's text then its an category material & there is no way to deal with it so return 0 + * c) If normal material proceeds as usual + */ +/datum/component/material_container/proc/get_material_amount(datum/material/mat) if(!istype(mat)) mat = GET_MATERIAL_REF(mat) + return materials[mat] - if(!mat) - return 0 - var/amount = materials[mat] - if(amount < amt) +/** + * Returns the amount of material relevant to this container; + * if this container does not support glass, any glass in 'I' will not be taken into account + * + * Arguments: + * - [I][obj/item]: the item whos materials must be retrived + * - breakdown_flags: how this item must be broken down to retrive its materials + */ +/datum/component/material_container/proc/get_item_material_amount(obj/item/I, breakdown_flags = mat_container_flags) + if(!istype(I) || !I.custom_materials) return 0 + var/material_amount = 0 + var/list/item_materials = I.get_material_composition(breakdown_flags) + for(var/MAT in item_materials) + if(!can_hold_material(MAT)) + continue + material_amount += item_materials[MAT] + return material_amount +//================================================================================================ - materials[mat] -= amt - total_amount -= amt - return amt -/// Proc for transfering materials to another container. -/datum/component/material_container/proc/transer_amt_to(datum/component/material_container/T, amt, datum/material/mat) - if(!istype(mat)) - mat = GET_MATERIAL_REF(mat) - if((amt == 0) || (!T) || (!mat)) +//=========================================HIGH LEVEL========================================== +/// returns the total amount of material in the container +/datum/component/material_container/proc/total_amount() + . = 0 + for(var/i in materials) + . += get_material_amount(i) + +/** + * Returns TRUE if you have enough of the specified material. + * + * Arguments: + * - [req_mat][datum/material]: the material to check for + * - amount: how much material do we need + */ +/datum/component/material_container/proc/has_enough_of_material(datum/material/req_mat, amount = 1) + return get_material_amount(req_mat) >= OPTIMAL_COST(amount) + + +/** + * Checks if its possible to afford a certain amount of materials. Takes a dictionary of materials. + * coefficient can be thought of as the machines efficiency & multiplier as the print quantity + * + * Arguments: + * - mats: list of materials(key=material, value= 1 unit of material) to check for + * - coefficient: scaling applied to 1 unit of material in the mats list + * - multiplier: how many units(after scaling) do we require + */ +/datum/component/material_container/proc/has_materials(list/mats, coefficient = 1, multiplier = 1) + if(!length(mats)) return FALSE - if(amt<0) - return T.transer_amt_to(src, -amt, mat) - var/tr = min(amt, materials[mat], T.can_insert_amount_mat(amt, mat)) - if(tr) - use_amount_mat(tr, mat) - T.insert_amount_mat(tr, mat) - return tr - return FALSE -/// Proc for checking if there is room in the component, returning the amount or else the amount lacking. -/datum/component/material_container/proc/can_insert_amount_mat(amt, datum/material/mat) - if(!amt || !mat) + for(var/x in mats) //Loop through all required materials + if(!has_enough_of_material(x, OPTIMAL_COST(mats[x] * coefficient) * multiplier))//Not a category, so just check the normal way + return FALSE + + return TRUE +//========================================================================================================== + + +//================================================Material Usage============================================ + +//==================================================LOW LEVEL======================================= +/** + * Uses an amount of a specific material, effectively removing it. + * + * Arguments: + * - amt: amount of said material to use + * - [mat][datum/material]: type of mat to use + */ +/datum/component/material_container/proc/use_amount_mat(amt, datum/material/mat) + //round amount + amt = OPTIMAL_COST(amt) + + //get ref if nessassary + if(!istype(mat)) + mat = GET_MATERIAL_REF(mat) + + //check if sufficient is available + if(materials[mat] < amt) return 0 - if((total_amount + amt) <= max_amount) - return amt - else - return (max_amount - total_amount) + //consume & return amount consumed + materials[mat] -= amt + return amt +//============================================================================================== - -/// For consuming a dictionary of materials. mats is the map of materials to use and the corresponding amounts, example: list(M/datum/material/glass =100, datum/material/iron=SMALL_MATERIAL_AMOUNT * 2) -/datum/component/material_container/proc/use_materials(list/mats, multiplier=1) +//=========================================MID LEVEL========================================== +/** + * For consuming a dictionary of materials. + * + * Arguments: + * - mats: map of materials to consume(key = material type, value = amount) + * - coefficient: how much fraction of unit material in the mats list must be consumed. This is usually your machines efficiency + * - multiplier: how many units of material in the mats list(after each unit is multiplied and rounded with coefficient) must be consumed, This is usually your print quantity + */ +/datum/component/material_container/proc/use_materials(list/mats, coefficient = 1, multiplier = 1) if(!mats || !length(mats)) return FALSE - var/list/mats_to_remove = list() //Assoc list MAT | AMOUNT + var/amount_removed = 0 + for(var/i in mats) + amount_removed += use_amount_mat(OPTIMAL_COST(mats[i] * coefficient) * multiplier, i) - for(var/x in mats) //Loop through all required materials - var/datum/material/req_mat = x - if(!istype(req_mat)) - req_mat = GET_MATERIAL_REF(req_mat) //Get the ref if necesary - if(!materials[req_mat]) //Do we have the resource? - return FALSE //Can't afford it - var/amount_required = mats[x] * multiplier - if(amount_required < 0) - return FALSE //No negative mats - if(!(materials[req_mat] >= amount_required)) // do we have enough of the resource? - return FALSE //Can't afford it - mats_to_remove[req_mat] += amount_required //Add it to the assoc list of things to remove - continue + return amount_removed +//============================================================================================ - var/total_amount_save = total_amount - for(var/i in mats_to_remove) - total_amount_save -= use_amount_mat(mats_to_remove[i], i) +//===========================================HIGH LEVEL======================================= - return total_amount_save - total_amount - -/// For spawning mineral sheets at a specific location. Used by machines to output sheets. +/** + * For spawning mineral sheets at a specific location. Used by machines to output sheets. + * + * Arguments: + * sheet_amt: number of sheets to extract + * [material][datum/material]: type of sheets present in this container to extract + * [target][atom]: drop location + */ /datum/component/material_container/proc/retrieve_sheets(sheet_amt, datum/material/material, atom/target = null) if(!material.sheet_type) return 0 //Add greyscale sheet handling here later @@ -489,108 +583,32 @@ var/count = 0 while(sheet_amt > MAX_STACK_SIZE) var/obj/item/stack/sheet/new_sheets = new material.sheet_type(target, MAX_STACK_SIZE, null, list((material) = SHEET_MATERIAL_AMOUNT)) - after_retrieve?.Invoke(new_sheets) count += MAX_STACK_SIZE use_amount_mat(sheet_amt * SHEET_MATERIAL_AMOUNT, material) sheet_amt -= MAX_STACK_SIZE + SEND_SIGNAL(src, COMSIG_MATCONTAINER_SHEETS_RETRIVED, new_sheets) if(sheet_amt >= 1) var/obj/item/stack/sheet/new_sheets = new material.sheet_type(target, sheet_amt, null, list((material) = SHEET_MATERIAL_AMOUNT)) - after_retrieve?.Invoke(new_sheets) count += sheet_amt use_amount_mat(sheet_amt * SHEET_MATERIAL_AMOUNT, material) + SEND_SIGNAL(src, COMSIG_MATCONTAINER_SHEETS_RETRIVED, new_sheets) return count -/// Proc to get all the materials and dump them as sheets +/** + * Proc to get all the materials and dump them as sheets + * + * Arguments: + * - target: drop location of the sheets + */ /datum/component/material_container/proc/retrieve_all(target = null) var/result = 0 for(var/MAT in materials) var/amount = materials[MAT] result += retrieve_sheets(amount2sheet(amount), MAT, target) return result +//============================================================================================ -/// Proc that returns TRUE if the container has space -/datum/component/material_container/proc/has_space(amt = 0) - return (total_amount + amt) <= max_amount - -/// Checks if its possible to afford a certain amount of materials. Takes a dictionary of materials. -/datum/component/material_container/proc/has_materials(list/mats, multiplier=1) - if(!mats || !mats.len) - return FALSE - - for(var/x in mats) //Loop through all required materials - var/datum/material/req_mat = x - if(!istype(req_mat)) - if(ispath(req_mat)) //Is this an actual material, or is it a category? - req_mat = GET_MATERIAL_REF(req_mat) //Get the ref - - else // Its a category. (For example MAT_CATEGORY_RIGID) - if(!has_enough_of_category(req_mat, mats[x], multiplier)) //Do we have enough of this category? - return FALSE - else - continue - - if(!has_enough_of_material(req_mat, mats[x], multiplier))//Not a category, so just check the normal way - return FALSE - - return TRUE - -/// Returns all the categories in a recipe. -/datum/component/material_container/proc/get_categories(list/mats) - var/list/categories = list() - for(var/x in mats) //Loop through all required materials - if(!istext(x)) //This means its not a category - continue - categories += x - return categories - -/// Returns TRUE if you have enough of the specified material. -/datum/component/material_container/proc/has_enough_of_material(datum/material/req_mat, amount, multiplier=1) - if(!materials[req_mat]) //Do we have the resource? - return FALSE //Can't afford it - var/amount_required = amount * multiplier - if(materials[req_mat] >= amount_required) // do we have enough of the resource? - return TRUE - return FALSE //Can't afford it - -/// Returns TRUE if you have enough of a specified material category (Which could be multiple materials) -/datum/component/material_container/proc/has_enough_of_category(category, amount, multiplier=1) - for(var/i in SSmaterials.materials_by_category[category]) - var/datum/material/mat = i - if(materials[mat] >= amount) //we have enough - return TRUE - return FALSE - -/// Turns a material amount into the amount of sheets it should output -/datum/component/material_container/proc/amount2sheet(amt) - if(amt >= SHEET_MATERIAL_AMOUNT) - return round(amt / SHEET_MATERIAL_AMOUNT) - return FALSE - -/// Turns an amount of sheets into the amount of material amount it should output -/datum/component/material_container/proc/sheet2amount(sheet_amt) - if(sheet_amt > 0) - return sheet_amt * SHEET_MATERIAL_AMOUNT - return FALSE - - -///returns the amount of material relevant to this container; if this container does not support glass, any glass in 'I' will not be taken into account -/datum/component/material_container/proc/get_item_material_amount(obj/item/I, breakdown_flags = mat_container_flags) - if(!istype(I) || !I.custom_materials) - return 0 - var/material_amount = 0 - var/list/item_materials = I.get_material_composition(breakdown_flags) - for(var/MAT in item_materials) - if(!can_hold_material(MAT)) - continue - material_amount += item_materials[MAT] - return material_amount - -/// Returns the amount of a specific material in this container. -/datum/component/material_container/proc/get_material_amount(datum/material/mat) - if(!istype(mat)) - mat = GET_MATERIAL_REF(mat) - return materials[mat] /datum/component/material_container/ui_static_data(mob/user) var/list/data = list() @@ -608,8 +626,6 @@ "name" = material.name, "ref" = REF(material), "amount" = amount, - "sheets" = round(amount / SHEET_MATERIAL_AMOUNT), - "removable" = amount >= SHEET_MATERIAL_AMOUNT, "color" = material.greyscale_colors )) diff --git a/code/datums/components/remote_materials.dm b/code/datums/components/material/remote_materials.dm similarity index 77% rename from code/datums/components/remote_materials.dm rename to code/datums/components/material/remote_materials.dm index a3c61221c6f..e20a4dbdaec 100644 --- a/code/datums/components/remote_materials.dm +++ b/code/datums/components/material/remote_materials.dm @@ -10,19 +10,24 @@ handles linking back and forth. // 1. silo exists, materials is parented to silo // 2. silo is null, materials is parented to parent // 3. silo is null, materials is null + + /// The silo machine this container is connected to var/obj/machinery/ore_silo/silo + //material container. the value is either the silo or local var/datum/component/material_container/mat_container - var/category + //should we create a local storage if we can't connect to silo var/allow_standalone + //are we trying to connect to the silo + var/connecting + //local size of container when silo = null var/local_size = INFINITY ///Flags used when converting inserted materials into their component materials. var/mat_container_flags = NONE -/datum/component/remote_materials/Initialize(category, mapload, allow_standalone = TRUE, force_connect = FALSE, mat_container_flags=NONE) +/datum/component/remote_materials/Initialize(mapload, allow_standalone = TRUE, force_connect = FALSE, mat_container_flags = NONE) if (!isatom(parent)) return COMPONENT_INCOMPATIBLE - src.category = category src.allow_standalone = allow_standalone src.mat_container_flags = mat_container_flags @@ -30,30 +35,26 @@ handles linking back and forth. RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(OnMultitool)) var/turf/T = get_turf(parent) - if (force_connect || (mapload && is_station_level(T.z))) - addtimer(CALLBACK(src, PROC_REF(LateInitialize))) - else if (allow_standalone) - _MakeLocal() + if(force_connect || (mapload && is_station_level(T.z))) + connecting = TRUE -/datum/component/remote_materials/proc/LateInitialize() - silo = GLOB.ore_silo_default - if (silo) - silo.ore_connected_machines += src - mat_container = silo.GetComponent(/datum/component/material_container) - else +/datum/component/remote_materials/RegisterWithParent() + if (connecting) + silo = GLOB.ore_silo_default + if (silo) + silo.ore_connected_machines += src + mat_container = silo.GetComponent(/datum/component/material_container) + connecting = FALSE + if (!mat_container && allow_standalone) _MakeLocal() /datum/component/remote_materials/Destroy() if (silo) silo.ore_connected_machines -= src + silo.holds -= src silo.updateUsrDialog() silo = null - mat_container = null - else if (mat_container) - // specify explicitly in case the other component is deleted first - var/atom/P = parent - mat_container.retrieve_all(P.drop_location()) - QDEL_NULL(mat_container) + mat_container = null return ..() /datum/component/remote_materials/proc/_MakeLocal() @@ -71,9 +72,15 @@ handles linking back and forth. /datum/material/titanium, /datum/material/bluespace, /datum/material/plastic, - ) + ) - mat_container = parent.AddComponent(/datum/component/material_container, allowed_mats, local_size, mat_container_flags, allowed_items=/obj/item/stack) + mat_container = parent.AddComponent( \ + /datum/component/material_container, \ + allowed_mats, \ + local_size, \ + mat_container_flags, \ + allowed_items = /obj/item/stack \ + ) /datum/component/remote_materials/proc/toggle_holding(force_hold = FALSE) if(isnull(silo)) @@ -123,9 +130,9 @@ handles linking back and forth. return COMPONENT_BLOCK_TOOL_ATTACK if (silo) silo.ore_connected_machines -= src + silo.holds -= src silo.updateUsrDialog() else if (mat_container) - mat_container.retrieve_all() qdel(mat_container) silo = M.buffer silo.ore_connected_machines += src @@ -150,7 +157,7 @@ handles linking back and forth. /datum/component/remote_materials/proc/on_hold() if(!check_z_level()) return FALSE - return silo.holds["[get_area(parent)]/[category]"] + return silo.holds[src] /datum/component/remote_materials/proc/silo_log(obj/machinery/M, action, amount, noun, list/mats) if (silo) @@ -158,7 +165,7 @@ handles linking back and forth. /datum/component/remote_materials/proc/format_amount() if (mat_container) - return "[mat_container.total_amount] / [mat_container.max_amount == INFINITY ? "Unlimited" : mat_container.max_amount] ([silo ? "remote" : "local"])" + return "[mat_container.total_amount()] / [mat_container.max_amount == INFINITY ? "Unlimited" : mat_container.max_amount] ([silo ? "remote" : "local"])" else return "0 / 0" @@ -179,10 +186,3 @@ handles linking back and forth. matlist[material_ref] = eject_amount silo_log(parent, "ejected", -count, "sheets", matlist) return count - -/// Returns `TRUE` if and only if the given material ref can be inserted/removed from this component -/datum/component/remote_materials/proc/can_hold_material(datum/material/material_ref) - if(!mat_container) - return FALSE - - return mat_container.can_hold_material(material_ref) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index d1a7de25556..6ad97655c4c 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -22,15 +22,26 @@ ///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 + /obj/machinery/autolathe/Initialize(mapload) - AddComponent(/datum/component/material_container, SSmaterials.materials_by_category[MAT_CATEGORY_ITEM_MATERIAL], 0, MATCONTAINER_EXAMINE, _after_insert = CALLBACK(src, PROC_REF(AfterMaterialInsert))) + materials = AddComponent( \ + /datum/component/material_container, \ + SSmaterials.materials_by_category[MAT_CATEGORY_ITEM_MATERIAL], \ + 0, \ + MATCONTAINER_EXAMINE, \ + container_signals = list(COMSIG_MATCONTAINER_ITEM_CONSUMED = TYPE_PROC_REF(/obj/machinery/autolathe, AfterMaterialInsert)) \ + ) . = ..() + set_wires(new /datum/wires/autolathe(src)) if(!GLOB.autounlock_techwebs[/datum/techweb/autounlocking/autolathe]) GLOB.autounlock_techwebs[/datum/techweb/autounlocking/autolathe] = new /datum/techweb/autounlocking/autolathe stored_research = GLOB.autounlock_techwebs[/datum/techweb/autounlocking/autolathe] /obj/machinery/autolathe/Destroy() + materials = null QDEL_NULL(wires) return ..() @@ -48,7 +59,7 @@ ui.open() /obj/machinery/autolathe/ui_static_data(mob/user) - var/list/data = list() + var/list/data = materials.ui_static_data() data["designs"] = handle_designs(stored_research.researched_designs) if(imported_designs.len) @@ -62,10 +73,7 @@ var/list/data = list() data["materials"] = list() - - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - - data["materialtotal"] = materials.total_amount + data["materialtotal"] = materials.total_amount() data["materialsmax"] = materials.max_amount data["active"] = busy data["materials"] = materials.ui_data() @@ -78,63 +86,38 @@ 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 - var/unbuildable = FALSE // we can't build the design currently - var/m10 = FALSE // 10x mult - var/m25 = FALSE // 25x mult - var/m50 = FALSE // 50x mult - var/m5 = FALSE // 5x mult - var/sheets = FALSE // sheets or no? + //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() + for(var/i in design.materials) + var/datum/material/mat = i - if(disabled || !can_build(design)) - unbuildable = TRUE + var/design_cost = OPTIMAL_COST(design.materials[i] * coeff) + if(istype(mat)) + cost[mat.name] = design_cost + else + cost[i] = design_cost - var/max_multiplier = unbuildable ? 0 : 1 - - if(ispath(design.build_path, /obj/item/stack)) - sheets = TRUE - - if(!unbuildable) - var/datum/component/material_container/mats = GetComponent(/datum/component/material_container) - - for(var/datum/material/mat in design.materials) - max_multiplier = min(design.maxstack, round(mats.get_material_amount(mat) / design.materials[mat])) - if (max_multiplier >= 10 && !disabled) - m10 = TRUE - if (max_multiplier >= 25 && !disabled) - m25 = TRUE - else - if(!unbuildable) - if(!disabled && can_build(design, 5)) - m5 = TRUE - if(!disabled && can_build(design, 10)) - m10 = TRUE - - var/datum/component/material_container/mats = GetComponent(/datum/component/material_container) - - for(var/datum/material/mat in design.materials) - max_multiplier = min(50, round(mats.get_material_amount(mat) / (design.materials[mat] * creation_efficiency))) + max_multiplier = min(max_multiplier, 50, round((istype(mat) ? materials.get_material_amount(i) : 0) / design_cost)) + //create & send ui data var/icon_size = spritesheet.icon_size_id(design.id) - var/list/design_data = list( "name" = design.name, "desc" = design.get_description(), - "cost" = get_design_cost(design), + "cost" = cost, "id" = design.id, "categories" = design.category, "icon" = "[icon_size == size32x32 ? "" : "[icon_size] "][design.id]", "constructionTime" = -1, - - "buildable" = unbuildable, - "mult5" = m5, - "mult10" = m10, - "mult25" = m25, - "mult50" = m50, - "sheet" = sheets, - "maxmult" = max_multiplier, + "maxmult" = max_multiplier ) output += list(design_data) @@ -153,85 +136,78 @@ return if(action == "make") + if(disabled) + say("The autolathe wires are disabled.") + return + if(busy) + say("The autolathe is busy. Please wait for completion of previous operation.") + return + var/design_id = params["id"] if(!istext(design_id)) return - if(!stored_research.researched_designs.Find(design_id) && !stored_research.hacked_designs.Find(design_id) && !imported_designs.Find(design_id)) return - var/datum/design/design = SSresearch.techweb_design_by_id(design_id) - if(!(design.build_type & AUTOLATHE) || design.id != design_id) return - if (busy) - to_chat(usr, span_alert("The autolathe is busy. Please wait for completion of previous operation.")) - return - being_built = design + var/is_stack = ispath(being_built.build_path, /obj/item/stack) + var/coeff = (is_stack ? 1 : creation_efficiency) // Stacks are unaffected by production coefficient var/multiplier = round(text2num(params["multiplier"])) - if(!multiplier || !IS_FINITE(multiplier)) return - - var/is_stack = ispath(being_built.build_path, /obj/item/stack) multiplier = clamp(multiplier, 1, 50) - var/coeff = (is_stack ? 1 : creation_efficiency) // Stacks are unaffected by production coefficient - var/total_amount = 0 - - for(var/material in being_built.materials) - total_amount += being_built.materials[material] - - var/power = max(active_power_usage, (total_amount)*multiplier/5) // Change this to use all materials - - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - + //check for materials var/list/materials_used = list() var/list/custom_materials = list() // These will apply their material effect, should usually only be one. - for(var/mat in being_built.materials) var/datum/material/used_material = mat - var/amount_needed = being_built.materials[mat] * coeff * multiplier + var/amount_needed = being_built.materials[mat] if(istext(used_material)) // This means its a category var/list/list_to_show = list() - + //list all materials in said category for(var/i in SSmaterials.materials_by_category[used_material]) if(materials.materials[i] > 0) list_to_show += i - + //ask user to pick specific material from list used_material = tgui_input_list( usr, "Choose [used_material]", "Custom Material", sort_list(list_to_show, GLOBAL_PROC_REF(cmp_typepaths_asc)) ) - if(isnull(used_material)) - // Didn't pick any material, so you can't build shit either. return - + //the item composition will be made of these materials custom_materials[used_material] += amount_needed - materials_used[used_material] = amount_needed - if(materials.has_materials(materials_used)) - busy = TRUE - to_chat(usr, span_notice("You print [multiplier] item(s) from the [src]")) - use_power(power) - icon_state = "autolathe_n" - var/time = is_stack ? 32 : (32 * coeff * multiplier) ** 0.8 - addtimer(CALLBACK(src, PROC_REF(make_item), power, materials_used, custom_materials, multiplier, coeff, is_stack, usr), time) - . = TRUE - else - to_chat(usr, span_alert("Not enough materials for this operation.")) + if(!materials.has_materials(materials_used, coeff, multiplier)) + say("Not enough materials for this operation!.") + return -/obj/machinery/autolathe/on_deconstruction() - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - materials.retrieve_all() + //use power + var/total_amount = 0 + for(var/material in being_built.materials) + total_amount += being_built.materials[material] + use_power(max(active_power_usage, (total_amount) * multiplier / 5)) + + //use materials + materials.use_materials(materials_used, coeff, multiplier) + busy = TRUE + to_chat(usr, span_notice("You print [multiplier] item(s) from the [src]")) + update_static_data_for_all_viewers() + //print item + icon_state = "autolathe_n" + var/time = is_stack ? 32 : (32 * coeff * multiplier) ** 0.8 + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/autolathe, make_item), custom_materials, multiplier, is_stack, usr), time) + + return TRUE /obj/machinery/autolathe/attackby(obj/item/attacking_item, mob/living/user, params) if(busy) @@ -303,8 +279,10 @@ return SECONDARY_ATTACK_CALL_NORMAL -/obj/machinery/autolathe/proc/AfterMaterialInsert(obj/item/item_inserted, id_inserted, amount_inserted) - if(istype(item_inserted, /obj/item/stack/ore/bluespace_crystal)) +/obj/machinery/autolathe/proc/AfterMaterialInsert(obj/machinery/machine, obj/item/item_inserted, last_inserted_id, amount_inserted, container) + SIGNAL_HANDLER + + if(ispath(item_inserted, /obj/item/stack/ore/bluespace_crystal)) use_power(SHEET_MATERIAL_AMOUNT / 10) else if(item_inserted.has_material_type(/datum/material/glass)) flick("autolathe_r", src)//plays glass insertion animation by default otherwise @@ -312,13 +290,10 @@ flick("autolathe_o", src)//plays metal insertion animation use_power(min(active_power_usage * 0.25, amount_inserted / 100)) + update_static_data_for_all_viewers() -/obj/machinery/autolathe/proc/make_item(power, list/materials_used, list/picked_materials, multiplier, coeff, is_stack, mob/user) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) +/obj/machinery/autolathe/proc/make_item(list/picked_materials, multiplier, is_stack, mob/user) var/atom/A = drop_location() - use_power(power) - - materials.use_materials(materials_used) if(is_stack) var/obj/item/stack/N = new being_built.build_path(A, multiplier, FALSE) @@ -334,7 +309,6 @@ if(!istype(M, /datum/material/glass) && !istype(M, /datum/material/iron)) user.client.give_award(/datum/award/achievement/misc/getting_an_upgrade, user) - icon_state = "autolathe" busy = FALSE @@ -343,7 +317,6 @@ var/mat_capacity = 0 for(var/datum/stock_part/matter_bin/new_matter_bin in component_parts) mat_capacity += new_matter_bin.tier * (37.5*SHEET_MATERIAL_AMOUNT) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) materials.max_amount = mat_capacity var/efficiency=1.8 @@ -353,40 +326,9 @@ /obj/machinery/autolathe/examine(mob/user) . += ..() - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) 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]%.") -/obj/machinery/autolathe/proc/can_build(datum/design/D, amount = 1) - if(D.make_reagent) - return FALSE - - var/coeff = (ispath(D.build_path, /obj/item/stack) ? 1 : creation_efficiency) - - var/list/required_materials = list() - - for(var/i in D.materials) - required_materials[i] = D.materials[i] * coeff * amount - - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - - return materials.has_materials(required_materials) - - -/obj/machinery/autolathe/proc/get_design_cost(datum/design/design) - var/coeff = (ispath(design.build_path, /obj/item/stack) ? 1 : creation_efficiency) - var/list/cost = list() - - for(var/material in design.materials) - if (istext(material)) - // Wildcard materials - cost[material] = design.materials[material] * coeff - else - var/datum/material/cast = material - cost[cast.name] = design.materials[cast] * coeff - - return cost - /obj/machinery/autolathe/proc/reset(wire) switch(wire) if(WIRE_HACK) diff --git a/code/game/machinery/droneDispenser.dm b/code/game/machinery/droneDispenser.dm index 8b4ba250a43..4b3c2a37d50 100644 --- a/code/game/machinery/droneDispenser.dm +++ b/code/game/machinery/droneDispenser.dm @@ -21,8 +21,8 @@ var/list/using_materials var/starting_amount = 0 - var/iron_cost =HALF_SHEET_MATERIAL_AMOUNT - var/glass_cost =HALF_SHEET_MATERIAL_AMOUNT + var/iron_cost = HALF_SHEET_MATERIAL_AMOUNT + var/glass_cost = HALF_SHEET_MATERIAL_AMOUNT var/power_used = 1000 var/mode = DRONE_READY @@ -48,16 +48,28 @@ var/break_message = "lets out a tinny alarm before falling dark." var/break_sound = 'sound/machines/warning-buzzer.ogg' + var/datum/component/material_container/materials + /obj/machinery/drone_dispenser/Initialize(mapload) . = ..() - var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, list(/datum/material/iron, /datum/material/glass), SHEET_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_DRONE_DISPENSER, allowed_items=/obj/item/stack) + materials = AddComponent( \ + /datum/component/material_container, \ + list(/datum/material/iron, /datum/material/glass), \ + SHEET_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, \ + MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_DRONE_DISPENSER, \ + allowed_items=/obj/item/stack \ + ) materials.insert_amount_mat(starting_amount) materials.precise_insertion = TRUE using_materials = list(/datum/material/iron = iron_cost, /datum/material/glass = glass_cost) REGISTER_REQUIRED_MAP_ITEM(1, 1) +/obj/machinery/drone_dispenser/Destroy() + materials = null + return ..() + /obj/machinery/drone_dispenser/preloaded - starting_amount = 5000 + starting_amount = SHEET_MATERIAL_AMOUNT * 2.5 /obj/machinery/drone_dispenser/syndrone //Please forgive me name = "syndrone shell dispenser" @@ -66,7 +78,7 @@ //If we're gonna be a jackass, go the full mile - 10 second recharge timer cooldownTime = 100 end_create_message = "dispenses a suspicious drone shell." - starting_amount = 25000 + starting_amount = SHEET_MATERIAL_AMOUNT * 12.5 /obj/machinery/drone_dispenser/syndrone/badass //Please forgive me name = "badass syndrone shell dispenser" @@ -81,10 +93,10 @@ dispense_type = /obj/effect/mob_spawn/ghost_role/drone/snowflake end_create_message = "dispenses a snowflake drone shell." // Those holoprojectors aren't cheap - iron_cost =SHEET_MATERIAL_AMOUNT - glass_cost =SHEET_MATERIAL_AMOUNT + iron_cost = SHEET_MATERIAL_AMOUNT + glass_cost = SHEET_MATERIAL_AMOUNT power_used = 2000 - starting_amount = 10000 + starting_amount = SHEET_MATERIAL_AMOUNT * 5 // If the derelict gets lonely, make more friends. /obj/machinery/drone_dispenser/derelict @@ -92,8 +104,8 @@ desc = "A rusty machine that, when supplied with iron and glass, will periodically create a derelict drone shell. Does not need to be manually operated." dispense_type = /obj/effect/mob_spawn/ghost_role/drone/derelict end_create_message = "dispenses a derelict drone shell." - iron_cost = 10000 - glass_cost = 5000 + iron_cost = SHEET_MATERIAL_AMOUNT * 5 + glass_cost = SHEET_MATERIAL_AMOUNT * 2.5 starting_amount = 0 cooldownTime = 600 @@ -128,11 +140,11 @@ . = ..() var/material_requirement_string = "It needs " if (iron_cost > 0) - material_requirement_string += "[iron_cost] iron " + material_requirement_string += "[iron_cost / SHEET_MATERIAL_AMOUNT] iron sheets " if (glass_cost > 0) material_requirement_string += "and " if (glass_cost > 0) - material_requirement_string += "[glass_cost] glass " + material_requirement_string += "[glass_cost / SHEET_MATERIAL_AMOUNT] glass sheets " if (iron_cost > 0 || glass_cost > 0) material_requirement_string += "to produce one drone shell." . += span_notice(material_requirement_string) @@ -144,7 +156,6 @@ if((machine_stat & (NOPOWER|BROKEN)) || !anchored) return - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) if(!materials.has_materials(using_materials)) return // We require more minerals @@ -212,7 +223,6 @@ /obj/machinery/drone_dispenser/attackby(obj/item/I, mob/living/user) if(I.tool_behaviour == TOOL_CROWBAR) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) materials.retrieve_all() I.play_tool_sound(src) to_chat(user, span_notice("You retrieve the materials from [src].")) diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 16af9a22423..415dacc9f17 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -21,7 +21,6 @@ materials = AddComponent( /datum/component/remote_materials, \ - "charger", \ mapload, \ mat_container_flags = MATCONTAINER_NO_INSERT, \ ) diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index fa75e70506c..3e78f2dfe54 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -17,6 +17,7 @@ var/crush_damage = 1000 var/eat_victim_items = TRUE var/item_recycle_sound = 'sound/items/welder.ogg' + var/datum/component/material_container/materials /obj/machinery/recycler/Initialize(mapload) var/list/allowed_materials = list( @@ -32,7 +33,7 @@ /datum/material/titanium, /datum/material/bluespace ) - AddComponent(/datum/component/material_container, allowed_materials, INFINITY, MATCONTAINER_NO_INSERT|BREAKDOWN_FLAGS_RECYCLER) + materials = AddComponent(/datum/component/material_container, allowed_materials, INFINITY, MATCONTAINER_NO_INSERT|BREAKDOWN_FLAGS_RECYCLER) AddComponent(/datum/component/butchering/recycler, \ speed = 0.1 SECONDS, \ effectiveness = amount_produced, \ @@ -50,6 +51,10 @@ ) AddElement(/datum/element/connect_loc, loc_connections) +/obj/machinery/recycler/Destroy() + materials = null + return ..() + /obj/machinery/recycler/RefreshParts() . = ..() var/amt_made = 0 @@ -183,7 +188,6 @@ new wood.plank_type(loc, 1 + seed_modifier) . = TRUE else - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) 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() diff --git a/code/game/machinery/sheetifier.dm b/code/game/machinery/sheetifier.dm index 5b01dd99018..57decf63ae4 100644 --- a/code/game/machinery/sheetifier.dm +++ b/code/game/machinery/sheetifier.dm @@ -7,11 +7,25 @@ circuit = /obj/item/circuitboard/machine/sheetifier layer = BELOW_OBJ_LAYER var/busy_processing = FALSE + var/datum/component/material_container/materials /obj/machinery/sheetifier/Initialize(mapload) . = ..() + materials = AddComponent( \ + /datum/component/material_container, \ + list(/datum/material/meat, /datum/material/hauntium), \ + SHEET_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, \ + MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_SHEETIFIER, \ + typesof(/datum/material/meat) + /datum/material/hauntium, list(/obj/item/food/meat, /obj/item/photo), \ + container_signals = list( + COMSIG_MATCONTAINER_PRE_USER_INSERT = TYPE_PROC_REF(/obj/machinery/sheetifier, CanInsertMaterials), + COMSIG_MATCONTAINER_ITEM_CONSUMED = TYPE_PROC_REF(/obj/machinery/sheetifier, AfterInsertMaterials) + ) \ + ) - AddComponent(/datum/component/material_container, list(/datum/material/meat, /datum/material/hauntium), SHEET_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_SHEETIFIER, typesof(/datum/material/meat) + /datum/material/hauntium, list(/obj/item/food/meat, /obj/item/photo), null, CALLBACK(src, PROC_REF(CanInsertMaterials)), CALLBACK(src, PROC_REF(AfterInsertMaterials))) +/obj/machinery/sheetifier/Destroy() + materials = null + return ..() /obj/machinery/sheetifier/update_overlays() . = ..() @@ -24,10 +38,12 @@ icon_state = "base_machine[busy_processing ? "_processing" : ""]" return ..() -/obj/machinery/sheetifier/proc/CanInsertMaterials() - return !busy_processing +/obj/machinery/sheetifier/proc/CanInsertMaterials(obj/machinery/machine, held_item, user) + SIGNAL_HANDLER -/obj/machinery/sheetifier/proc/AfterInsertMaterials(item_inserted, id_inserted, amount_inserted) + return busy_processing ? MATCONTAINER_BLOCK_INSERT : TRUE + +/obj/machinery/sheetifier/proc/AfterInsertMaterials(obj/machinery/machine, item_inserted, id_inserted, amount_inserted, container) busy_processing = TRUE update_appearance() var/datum/material/last_inserted_material = id_inserted @@ -39,7 +55,6 @@ /obj/machinery/sheetifier/proc/finish_processing() busy_processing = FALSE update_appearance() - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) materials.retrieve_all() //Returns all as sheets use_power(active_power_usage) diff --git a/code/game/objects/items/rcd/RHD.dm b/code/game/objects/items/rcd/RHD.dm index a296eefa973..68355267315 100644 --- a/code/game/objects/items/rcd/RHD.dm +++ b/code/game/objects/items/rcd/RHD.dm @@ -1,5 +1,7 @@ //RAPID HANDHELD DEVICE. the base for all rapid devices +#define SILO_USE_AMOUNT (SHEET_MATERIAL_AMOUNT / 4) + /obj/item/construction name = "not for ingame use" desc = "A device used to rapidly build and deconstruct. Reload with iron, plasteel, glass or compressed matter cartridges." @@ -13,7 +15,7 @@ throw_speed = 3 throw_range = 5 w_class = WEIGHT_CLASS_NORMAL - custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*50) + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 50) req_access = list(ACCESS_ENGINE_EQUIP) armor_type = /datum/armor/item_construction resistance_flags = FIRE_PROOF @@ -46,13 +48,13 @@ spark_system.set_up(5, 0, src) spark_system.attach(src) if(upgrade & RCD_UPGRADE_SILO_LINK) - silo_mats = AddComponent(/datum/component/remote_materials, "RCD", mapload, FALSE) + silo_mats = AddComponent(/datum/component/remote_materials, mapload, FALSE) update_appearance() ///used for examining the RCD and for its UI /obj/item/construction/proc/get_silo_iron() if(silo_link && silo_mats.mat_container && !silo_mats.on_hold()) - return silo_mats.mat_container.get_material_amount(/datum/material/iron)/500 + return silo_mats.mat_container.get_material_amount(/datum/material/iron) / SILO_USE_AMOUNT return FALSE ///returns local matter units available. overriden by rcd borg to return power units available @@ -99,7 +101,7 @@ return upgrade |= design_disk.upgrade if((design_disk.upgrade & RCD_UPGRADE_SILO_LINK) && !silo_mats) - silo_mats = AddComponent(/datum/component/remote_materials, "RCD", FALSE, FALSE) + silo_mats = AddComponent(/datum/component/remote_materials, FALSE, FALSE) playsound(loc, 'sound/machines/click.ogg', 50, TRUE) qdel(design_disk) @@ -171,16 +173,17 @@ balloon_alert(user, "silo on hold!") return FALSE if(!silo_mats.mat_container) - balloon_alert(user, "no silo detected!") + if(user) + balloon_alert(user, "no silo detected!") return FALSE - if(!silo_mats.mat_container.has_materials(list(/datum/material/iron = 500), amount)) + if(!silo_mats.mat_container.has_materials(list(/datum/material/iron = SILO_USE_AMOUNT), multiplier = amount)) if(user) balloon_alert(user, "not enough silo material!") return FALSE var/list/materials = list() - materials[GET_MATERIAL_REF(/datum/material/iron)] = 500 - silo_mats.mat_container.use_materials(materials, amount) + materials[GET_MATERIAL_REF(/datum/material/iron)] = SILO_USE_AMOUNT + silo_mats.mat_container.use_materials(materials, multiplier = amount) silo_mats.silo_log(src, "consume", -amount, "build", materials) return TRUE @@ -235,7 +238,7 @@ if(user) balloon_alert(user, "silo on hold!") return FALSE - . = silo_mats.mat_container.has_materials(list(/datum/material/iron = 500), amount) + . = silo_mats.mat_container.has_materials(list(/datum/material/iron = SILO_USE_AMOUNT), multiplier = amount) if(!. && user) balloon_alert(user, "low ammo!") if(has_ammobar) @@ -295,3 +298,4 @@ name = "Destruction Scan" desc = "Scans the surrounding area for destruction. Scanned structures will rebuild significantly faster." +#undef SILO_USE_AMOUNT diff --git a/code/modules/antagonists/clown_ops/clown_weapons.dm b/code/modules/antagonists/clown_ops/clown_weapons.dm index 5341a9db5ba..1c55e5416e2 100644 --- a/code/modules/antagonists/clown_ops/clown_weapons.dm +++ b/code/modules/antagonists/clown_ops/clown_weapons.dm @@ -64,13 +64,11 @@ . = ..() create_storage(storage_type = /datum/storage/pockets/shoes) - - var/datum/component/material_container/bananium = GetComponent(/datum/component/material_container) bananium.insert_amount_mat(BANANA_SHOES_MAX_CHARGE, /datum/material/bananium) + START_PROCESSING(SSobj, src) /obj/item/clothing/shoes/clown_shoes/banana_shoes/combat/process(seconds_per_tick) - var/datum/component/material_container/bananium = GetComponent(/datum/component/material_container) var/bananium_amount = bananium.get_material_amount(/datum/material/bananium) if(bananium_amount < BANANA_SHOES_MAX_CHARGE) bananium.insert_amount_mat(min(BANANA_SHOES_RECHARGE_RATE * seconds_per_tick, BANANA_SHOES_MAX_CHARGE - bananium_amount), /datum/material/bananium) diff --git a/code/modules/clothing/shoes/bananashoes.dm b/code/modules/clothing/shoes/bananashoes.dm index 46e98db0a8c..0c280eb2f3b 100644 --- a/code/modules/clothing/shoes/bananashoes.dm +++ b/code/modules/clothing/shoes/bananashoes.dm @@ -13,16 +13,22 @@ var/material_per_banana =SMALL_MATERIAL_AMOUNT /// Typepath of created banana var/banana_type = /obj/item/grown/bananapeel/specialpeel + /// Material container for bananium + var/datum/component/material_container/bananium /obj/item/clothing/shoes/clown_shoes/banana_shoes/Initialize(mapload) . = ..() AddElement(/datum/element/update_icon_updates_onmob) - AddComponent(/datum/component/material_container, list(/datum/material/bananium), 100 * SHEET_MATERIAL_AMOUNT, MATCONTAINER_EXAMINE|MATCONTAINER_ANY_INTENT|MATCONTAINER_SILENT, allowed_items=/obj/item/stack) + bananium = AddComponent(/datum/component/material_container, list(/datum/material/bananium), 100 * SHEET_MATERIAL_AMOUNT, MATCONTAINER_EXAMINE|MATCONTAINER_ANY_INTENT|MATCONTAINER_SILENT, allowed_items=/obj/item/stack) AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 75, falloff_exponent = 20) RegisterSignal(src, COMSIG_SHOES_STEP_ACTION, PROC_REF(on_step)) if(always_noslip) LAZYOR(clothing_traits, TRAIT_NO_SLIP_WATER) +/obj/item/clothing/shoes/clown_shoes/banana_shoes/Destroy() + bananium = null + return ..() + /obj/item/clothing/shoes/clown_shoes/banana_shoes/proc/toggle_clowning_action() on = !on update_appearance() @@ -38,7 +44,6 @@ SIGNAL_HANDLER var/mob/wearer = loc - var/datum/component/material_container/bananium = GetComponent(/datum/component/material_container) if(!on || !istype(wearer)) return @@ -50,7 +55,6 @@ to_chat(wearer, span_warning("You ran out of bananium!")) /obj/item/clothing/shoes/clown_shoes/banana_shoes/attack_self(mob/user) - var/datum/component/material_container/bananium = GetComponent(/datum/component/material_container) var/sheet_amount = bananium.retrieve_all() if(sheet_amount) to_chat(user, span_notice("You retrieve [sheet_amount] sheets of bananium from the prototype shoes.")) @@ -62,7 +66,6 @@ . += span_notice("The shoes are [on ? "enabled" : "disabled"].") /obj/item/clothing/shoes/clown_shoes/banana_shoes/ui_action_click(mob/user) - var/datum/component/material_container/bananium = GetComponent(/datum/component/material_container) if(bananium.get_material_amount(/datum/material/bananium) >= material_per_banana) toggle_clowning_action() to_chat(user, span_notice("You [on ? "activate" : "deactivate"] the prototype shoes.")) diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index b89083824fd..41fdf228939 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -136,6 +136,8 @@ var/datum/techweb/stored_research ///Proximity monitor associated with this atom, needed for proximity checks. var/datum/proximity_monitor/proximity_monitor + ///Material container for materials + var/datum/component/material_container/materials /obj/machinery/mineral/processing_unit/Initialize(mapload) . = ..() @@ -152,13 +154,20 @@ /datum/material/titanium, /datum/material/bluespace, ) - AddComponent(/datum/component/material_container, allowed_materials, INFINITY, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_ORE_PROCESSOR, allowed_items=/obj/item/stack) + materials = AddComponent( \ + /datum/component/material_container, \ + allowed_materials, \ + INFINITY, \ + MATCONTAINER_EXAMINE | BREAKDOWN_FLAGS_ORE_PROCESSOR, \ + allowed_items = /obj/item/stack \ + ) if(!GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter]) GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter] = new /datum/techweb/autounlocking/smelter stored_research = GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter] selected_material = GET_MATERIAL_REF(/datum/material/iron) /obj/machinery/mineral/processing_unit/Destroy() + materials = null mineral_machine = null stored_research = null return ..() @@ -166,7 +175,6 @@ /obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/ore/O) if(QDELETED(O)) return - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) var/material_amount = materials.get_item_material_amount(O, BREAKDOWN_FLAGS_ORE_PROCESSOR) if(!materials.has_space(material_amount)) unload_mineral(O) @@ -177,7 +185,6 @@ /obj/machinery/mineral/processing_unit/proc/get_machine_data() var/dat = "Smelter control console

" - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) for(var/datum/material/all_materials as anything in materials.materials) var/amount = materials.materials[all_materials] dat += "[all_materials.name]: [amount] cm³" @@ -231,7 +238,6 @@ mineral_machine.updateUsrDialog() /obj/machinery/mineral/processing_unit/proc/smelt_ore(seconds_per_tick = 2) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) var/datum/material/mat = selected_material if(!mat) return @@ -254,8 +260,7 @@ on = FALSE return - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - materials.use_materials(alloy.materials, amount) + materials.use_materials(alloy.materials, multiplier = amount) generate_mineral(alloy.build_path) @@ -265,8 +270,6 @@ var/build_amount = SMELT_AMOUNT * seconds_per_tick - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - for(var/mat_cat in D.materials) var/required_amount = D.materials[mat_cat] var/amount = materials.materials[mat_cat] @@ -279,9 +282,4 @@ var/O = new P(src) unload_mineral(O) -/obj/machinery/mineral/processing_unit/on_deconstruction() - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - materials.retrieve_all() - return ..() - #undef SMELT_AMOUNT diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index 9ed337f9d56..03ec725dc31 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -52,7 +52,11 @@ if(!GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter]) GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter] = new /datum/techweb/autounlocking/smelter stored_research = GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter] - materials = AddComponent(/datum/component/remote_materials, "orm", mapload, mat_container_flags=BREAKDOWN_FLAGS_ORM) + materials = AddComponent( + /datum/component/remote_materials, \ + mapload, \ + mat_container_flags = BREAKDOWN_FLAGS_ORM \ + ) /obj/machinery/mineral/ore_redemption/Destroy() stored_research = null @@ -375,7 +379,7 @@ var/amount = round(min(text2num(params["sheets"]), 50, can_smelt_alloy(alloy))) if(amount < 1) //no negative mats return - mat_container.use_materials(alloy.materials, amount) + mat_container.use_materials(alloy.materials, multiplier = amount) materials.silo_log(src, "released", -amount, "sheets", alloy.materials) var/output if(ispath(alloy.build_path, /obj/item/stack/sheet)) diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm index 2af363335e5..b06188fb2c6 100644 --- a/code/modules/mining/machine_silo.dm +++ b/code/modules/mining/machine_silo.dm @@ -15,6 +15,8 @@ GLOBAL_LIST_EMPTY(silo_access_logs) var/list/holds = list() /// List of all components that are sharing ores with this silo. var/list/datum/component/remote_materials/ore_connected_machines = list() + /// Material Container + var/datum/component/material_container/materials /obj/machinery/ore_silo/Initialize(mapload) . = ..() @@ -31,7 +33,13 @@ GLOBAL_LIST_EMPTY(silo_access_logs) /datum/material/bluespace, /datum/material/plastic, ) - AddComponent(/datum/component/material_container, materials_list, INFINITY, MATCONTAINER_NO_INSERT, allowed_items=/obj/item/stack) + materials = AddComponent( \ + /datum/component/material_container, \ + materials_list, \ + INFINITY, \ + MATCONTAINER_NO_INSERT, \ + allowed_items = /obj/item/stack \ + ) if (!GLOB.ore_silo_default && mapload && is_station_level(z)) GLOB.ore_silo_default = src @@ -43,15 +51,11 @@ GLOBAL_LIST_EMPTY(silo_access_logs) mats.disconnect_from(src) ore_connected_machines = null - - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - materials.retrieve_all() + materials = null return ..() /obj/machinery/ore_silo/proc/remote_attackby(obj/machinery/M, mob/living/user, obj/item/stack/I, breakdown_flags=NONE) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - // stolen from /datum/component/material_container/proc/OnAttackBy if(user.combat_mode) return if(I.item_flags & ABSTRACT) @@ -92,7 +96,6 @@ GLOBAL_LIST_EMPTY(silo_access_logs) popup.open() /obj/machinery/ore_silo/proc/generate_ui() - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) var/list/ui = list("Ore Silo

Stored Material:

") var/any = FALSE for(var/M in materials.materials) @@ -166,7 +169,6 @@ GLOBAL_LIST_EMPTY(silo_access_logs) return TRUE else if(href_list["ejectsheet"]) var/datum/material/eject_sheet = locate(href_list["ejectsheet"]) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) var/count = materials.retrieve_sheets(text2num(href_list["eject_amt"]), eject_sheet, drop_location()) var/list/matlist = list() matlist[eject_sheet] = SHEET_MATERIAL_AMOUNT * count diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index 366791c6a01..1635c5c2fa3 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -101,7 +101,12 @@ /obj/machinery/mineral/stacking_machine/Initialize(mapload) . = ..() proximity_monitor = new(src, 1) - materials = AddComponent(/datum/component/remote_materials, "stacking", mapload, FALSE, (mapload && force_connect)) + materials = AddComponent( + /datum/component/remote_materials, \ + mapload, \ + FALSE, \ + (mapload && force_connect) \ + ) /obj/machinery/mineral/stacking_machine/Destroy() if(console) diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index a97683ca59f..fab4b2a6b0f 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -726,10 +726,22 @@ COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(on_atom_initialized_on), ) var/datum/component/connect_loc_behalf/connector + var/datum/component/material_container/container /obj/item/mod/module/recycler/Initialize(mapload) . = ..() - AddComponent(/datum/component/material_container, accepted_mats, 50 * SHEET_MATERIAL_AMOUNT, MATCONTAINER_EXAMINE|MATCONTAINER_NO_INSERT, _after_retrieve=CALLBACK(src, PROC_REF(attempt_insert_storage))) + container = AddComponent( \ + /datum/component/material_container, \ + accepted_mats, 50 * SHEET_MATERIAL_AMOUNT, \ + MATCONTAINER_EXAMINE|MATCONTAINER_NO_INSERT, \ + container_signals = list( \ + COMSIG_MATCONTAINER_SHEETS_RETRIVED = TYPE_PROC_REF(/obj/item/mod/module/recycler, InsertSheets) \ + ) \ + ) + +/obj/item/mod/module/recycler/Destroy() + container = null + return ..() /obj/item/mod/module/recycler/on_activation() . = ..() @@ -747,6 +759,7 @@ /obj/item/mod/module/recycler/proc/on_wearer_moved(datum/source, atom/old_loc, dir, forced) SIGNAL_HANDLER + for(var/obj/item/item in mod.wearer.loc) if(!is_type_in_list(item, allowed_item_types)) return @@ -754,12 +767,14 @@ /obj/item/mod/module/recycler/proc/on_obj_entered(atom/new_loc, atom/movable/arrived, atom/old_loc) SIGNAL_HANDLER + if(!is_type_in_list(arrived, allowed_item_types)) return insert_trash(arrived) /obj/item/mod/module/recycler/proc/on_atom_initialized_on(atom/loc, atom/new_atom) SIGNAL_HANDLER + if(!is_type_in_list(new_atom, allowed_item_types)) return //Give the new atom the time to fully initialize and maybe live if the wearer moves away. @@ -770,7 +785,6 @@ insert_trash(new_atom) /obj/item/mod/module/recycler/proc/insert_trash(obj/item/item) - var/datum/component/material_container/container = GetComponent(/datum/component/material_container) var/retrieved = container.insert_item(item, multiplier = efficiency, breakdown_flags = BREAKDOWN_FLAGS_RECYCLER) if(retrieved == MATERIAL_INSERT_ITEM_NO_MATS) //even if it doesn't have any material to give, trash is trash. qdel(item) @@ -787,7 +801,6 @@ dispense(target) /obj/item/mod/module/recycler/proc/dispense(atom/target) - var/datum/component/material_container/container = GetComponent(/datum/component/material_container) if(container.retrieve_all(target)) balloon_alert(mod.wearer, "material dispensed") playsound(src, 'sound/machines/microwave/microwave-end.ogg', 50, TRUE) @@ -795,6 +808,11 @@ balloon_alert(mod.wearer, "not enough material") playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) +/obj/item/mod/module/recycler/proc/InsertSheets(obj/item/recycler, obj/item/stack/sheets) + SIGNAL_HANDLER + + attempt_insert_storage(sheets) + /obj/item/mod/module/recycler/proc/attempt_insert_storage(obj/item/to_drop) if(!isturf(to_drop.loc) && !to_drop.loc.atom_storage?.attempt_insert(to_drop, mod.wearer, override = TRUE)) to_drop.forceMove(to_drop.loc.drop_location()) @@ -815,7 +833,6 @@ var/required_amount = SHEET_MATERIAL_AMOUNT*12.5 /obj/item/mod/module/recycler/donk/dispense(atom/target) - var/datum/component/material_container/container = GetComponent(/datum/component/material_container) if(!container.use_amount_mat(required_amount, /datum/material/iron)) balloon_alert(mod.wearer, "not enough material") playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index 5822a354f06..55d9f3ae711 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -22,9 +22,6 @@ /// All designs in the techweb that can be fabricated by this machine, since the last update. var/list/datum/design/cached_designs - /// The department this fabricator is assigned to. - var/department_tag = "Unassigned" - /// What color is this machine's stripe? Leave null to not have a stripe. var/stripe_color = null @@ -37,7 +34,6 @@ cached_designs = list() materials = AddComponent( /datum/component/remote_materials, \ - "lathe", \ mapload, \ mat_container_flags = BREAKDOWN_FLAGS_LATHE, \ ) @@ -121,27 +117,25 @@ ui.open() /obj/machinery/rnd/production/ui_static_data(mob/user) - var/list/data - if(isnull(materials.mat_container)) - data = list() - else - data = materials.mat_container.ui_static_data() + var/list/data = materials.mat_container.ui_static_data() var/list/designs = list() var/datum/asset/spritesheet/research_designs/spritesheet = get_asset_datum(/datum/asset/spritesheet/research_designs) var/size32x32 = "[spritesheet.name]32x32" - var/max_multiplier + var/max_multiplier = INFINITY var/coefficient for(var/datum/design/design in cached_designs) var/cost = list() - coefficient = efficient_with(design.build_path) ? efficiency_coeff : 1 - for(var/datum/material/material in design.materials) - cost[material.name] = design.materials[material] * coefficient - max_multiplier = min(50, round(materials.mat_container.get_material_amount(material) / (design.materials[material] * coefficient))) - var/icon_size = spritesheet.icon_size_id(design.id) + 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( "name" = design.name, "desc" = design.get_description(), @@ -161,7 +155,7 @@ /obj/machinery/rnd/production/ui_data(mob/user) var/list/data = list() - data["materials"] = materials.mat_container?.ui_data() + data["materials"] = materials.mat_container.ui_data() data["onHold"] = materials.on_hold() data["busy"] = busy data["materialMaximum"] = materials.local_size @@ -181,7 +175,7 @@ if("remove_mat") var/datum/material/material = locate(params["ref"]) - if(!materials.can_hold_material(material)) + if(!materials.mat_container.can_hold_material(material)) // I don't know who you are or what you want, but whatever it is, // we don't have it. return @@ -223,14 +217,17 @@ return ..() -/obj/machinery/rnd/production/proc/do_print(path, amount, list/matlist) +/obj/machinery/rnd/production/proc/do_print(path, amount) for(var/i in 1 to amount) new path(get_turf(src)) SSblackbox.record_feedback("nested tally", "item_printed", amount, list("[type]", "[path]")) -/obj/machinery/rnd/production/proc/efficient_with(path) - return !ispath(path, /obj/item/stack/sheet) && !ispath(path, /obj/item/stack/ore/bluespace_crystal) +/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(design_id, print_quantity) if(!design_id) @@ -267,37 +264,29 @@ say("Mineral access is on hold, please contact the quartermaster.") return FALSE - var/power = active_power_usage - print_quantity = clamp(print_quantity, 1, 50) + var/coefficient = build_efficiency(design.build_path) - for(var/material in design.materials) - power += round(design.materials[material] * print_quantity / 35) - - power = min(active_power_usage, power) - use_power(power) - - var/coefficient = efficient_with(design.build_path) ? efficiency_coeff : 1 - var/list/efficient_mats = list() - - for(var/material in design.materials) - efficient_mats[material] = design.materials[material] * coefficient - - if(!materials.mat_container.has_materials(efficient_mats, print_quantity)) + //check if sufficient materials/reagents 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 - for(var/reagent in design.reagents_list) if(!reagents.has_reagent(reagent, design.reagents_list[reagent] * print_quantity * coefficient)) say("Not enough reagents to complete prototype[print_quantity > 1? "s" : ""].") return FALSE + //use power + var/power = active_power_usage + for(var/material in design.materials) + power += round(design.materials[material] * print_quantity / 35) + power = min(active_power_usage, power) + use_power(power) + // Charge the lathe tax at least once per ten items. var/total_cost = LATHE_TAX * max(round(print_quantity / 10), 1) - if(!charges_tax) total_cost = 0 - if(isliving(usr)) var/mob/living/user = usr var/obj/item/card/id/card = user.get_idcard(TRUE) @@ -309,34 +298,28 @@ var/datum/bank_account/our_acc = card.registered_account if(our_acc.account_job.departments_bitflags & allowed_department_flags) total_cost = 0 // We are not charging crew for printing their own supplies and equipment. - if(attempt_charge(src, usr, total_cost) & COMPONENT_OBJ_CANCEL_CHARGE) say("Insufficient funds to complete prototype. Please present a holochip or valid ID card.") return FALSE - if(iscyborg(usr)) var/mob/living/silicon/robot/borg = usr - if(!borg.cell) return FALSE - borg.cell.use(SILICON_LATHE_TAX) - materials.mat_container.use_materials(efficient_mats, print_quantity) - materials.silo_log(src, "built", -print_quantity, "[design.name]", efficient_mats) - + //consume materials + materials.mat_container.use_materials(design.materials, coefficient, print_quantity) + materials.silo_log(src, "built", -print_quantity, "[design.name]", design.materials) for(var/reagent in design.reagents_list) reagents.remove_reagent(reagent, design.reagents_list[reagent] * print_quantity * coefficient) - + //produce item busy = TRUE - if(production_animation) flick(production_animation, src) - var/time_coefficient = design.lathe_time_factor * efficiency_coeff - addtimer(CALLBACK(src, PROC_REF(reset_busy)), (30 * time_coefficient * print_quantity) ** 0.5) - addtimer(CALLBACK(src, PROC_REF(do_print), design.build_path, print_quantity, efficient_mats), (32 * time_coefficient * print_quantity) ** 0.8) + addtimer(CALLBACK(src, PROC_REF(do_print), design.build_path, print_quantity), (32 * time_coefficient * print_quantity) ** 0.8) + update_static_data_for_all_viewers() return TRUE diff --git a/code/modules/research/machinery/departmental_circuit_imprinter.dm b/code/modules/research/machinery/departmental_circuit_imprinter.dm index 7277c41d978..2f5a606d8a2 100644 --- a/code/modules/research/machinery/departmental_circuit_imprinter.dm +++ b/code/modules/research/machinery/departmental_circuit_imprinter.dm @@ -8,5 +8,4 @@ name = "department circuit imprinter (Science)" circuit = /obj/item/circuitboard/machine/circuit_imprinter/department/science allowed_department_flags = DEPARTMENT_BITFLAG_SCIENCE - department_tag = "Science" payment_department = ACCOUNT_SCI diff --git a/code/modules/research/machinery/departmental_protolathe.dm b/code/modules/research/machinery/departmental_protolathe.dm index 61c7c6f97af..dc0b882ef51 100644 --- a/code/modules/research/machinery/departmental_protolathe.dm +++ b/code/modules/research/machinery/departmental_protolathe.dm @@ -7,7 +7,6 @@ /obj/machinery/rnd/production/protolathe/department/engineering name = "department protolathe (Engineering)" allowed_department_flags = DEPARTMENT_BITFLAG_ENGINEERING - department_tag = "Engineering" circuit = /obj/item/circuitboard/machine/protolathe/department/engineering stripe_color = "#EFB341" payment_department = ACCOUNT_ENG @@ -19,7 +18,6 @@ /obj/machinery/rnd/production/protolathe/department/service name = "department protolathe (Service)" allowed_department_flags = DEPARTMENT_BITFLAG_SERVICE - department_tag = "Service" circuit = /obj/item/circuitboard/machine/protolathe/department/service stripe_color = "#83ca41" payment_department = ACCOUNT_SRV @@ -27,7 +25,6 @@ /obj/machinery/rnd/production/protolathe/department/medical name = "department protolathe (Medical)" allowed_department_flags = DEPARTMENT_BITFLAG_MEDICAL - department_tag = "Medical" circuit = /obj/item/circuitboard/machine/protolathe/department/medical stripe_color = "#52B4E9" payment_department = ACCOUNT_MED @@ -35,7 +32,6 @@ /obj/machinery/rnd/production/protolathe/department/cargo name = "department protolathe (Cargo)" allowed_department_flags = DEPARTMENT_BITFLAG_CARGO - department_tag = "Cargo" circuit = /obj/item/circuitboard/machine/protolathe/department/cargo stripe_color = "#956929" payment_department = ACCOUNT_CAR @@ -43,7 +39,6 @@ /obj/machinery/rnd/production/protolathe/department/science name = "department protolathe (Science)" allowed_department_flags = DEPARTMENT_BITFLAG_SCIENCE - department_tag = "Science" circuit = /obj/item/circuitboard/machine/protolathe/department/science stripe_color = "#D381C9" payment_department = ACCOUNT_SCI @@ -51,7 +46,6 @@ /obj/machinery/rnd/production/protolathe/department/security name = "department protolathe (Security)" allowed_department_flags = DEPARTMENT_BITFLAG_SECURITY - department_tag = "Security" circuit = /obj/item/circuitboard/machine/protolathe/department/security stripe_color = "#DE3A3A" payment_department = ACCOUNT_SEC diff --git a/code/modules/research/machinery/departmental_techfab.dm b/code/modules/research/machinery/departmental_techfab.dm index 788803e3959..3819429a8b9 100644 --- a/code/modules/research/machinery/departmental_techfab.dm +++ b/code/modules/research/machinery/departmental_techfab.dm @@ -7,7 +7,6 @@ /obj/machinery/rnd/production/techfab/department/engineering name = "department techfab (Engineering)" allowed_department_flags = DEPARTMENT_BITFLAG_ENGINEERING - department_tag = "Engineering" circuit = /obj/item/circuitboard/machine/techfab/department/engineering stripe_color = "#EFB341" payment_department = ACCOUNT_ENG @@ -15,7 +14,6 @@ /obj/machinery/rnd/production/techfab/department/service name = "department techfab (Service)" allowed_department_flags = DEPARTMENT_BITFLAG_SERVICE - department_tag = "Service" circuit = /obj/item/circuitboard/machine/techfab/department/service stripe_color = "#83ca41" payment_department = ACCOUNT_SRV @@ -23,7 +21,6 @@ /obj/machinery/rnd/production/techfab/department/medical name = "department techfab (Medical)" allowed_department_flags = DEPARTMENT_BITFLAG_MEDICAL - department_tag = "Medical" circuit = /obj/item/circuitboard/machine/techfab/department/medical stripe_color = "#52B4E9" payment_department = ACCOUNT_MED @@ -31,7 +28,6 @@ /obj/machinery/rnd/production/techfab/department/cargo name = "department techfab (Cargo)" allowed_department_flags = DEPARTMENT_BITFLAG_CARGO - department_tag = "Cargo" circuit = /obj/item/circuitboard/machine/techfab/department/cargo stripe_color = "#956929" payment_department = ACCOUNT_CAR @@ -39,7 +35,6 @@ /obj/machinery/rnd/production/techfab/department/science name = "department techfab (Science)" allowed_department_flags = DEPARTMENT_BITFLAG_SCIENCE - department_tag = "Science" circuit = /obj/item/circuitboard/machine/techfab/department/science stripe_color = "#D381C9" payment_department = ACCOUNT_SCI @@ -47,7 +42,6 @@ /obj/machinery/rnd/production/techfab/department/security name = "department techfab (Security)" allowed_department_flags = DEPARTMENT_BITFLAG_SECURITY - department_tag = "Security" circuit = /obj/item/circuitboard/machine/techfab/department/security stripe_color = "#DE3A3A" payment_department = ACCOUNT_SEC diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index d3aa604ef49..f6f54aae05d 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -55,7 +55,11 @@ /obj/machinery/mecha_part_fabricator/Initialize(mapload) if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research) connect_techweb(SSresearch.science_tech) - rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init, mat_container_flags=BREAKDOWN_FLAGS_LATHE) + rmat = AddComponent( \ + /datum/component/remote_materials, \ + mapload && link_on_init, \ + mat_container_flags = BREAKDOWN_FLAGS_LATHE \ + ) cached_designs = list() RefreshParts() //Recalculating local material sizes if the fab isn't linked if(stored_research) @@ -92,7 +96,7 @@ //maximum stocking amount (default 300000, 600000 at T4) for(var/datum/stock_part/matter_bin/matter_bin in component_parts) T += matter_bin.tier - rmat.set_local_size(((100*SHEET_MATERIAL_AMOUNT) + (T * (25*SHEET_MATERIAL_AMOUNT)))) + rmat.set_local_size(((100 * SHEET_MATERIAL_AMOUNT) + (T * (25 * SHEET_MATERIAL_AMOUNT)))) //resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55) T = 1.15 @@ -173,34 +177,6 @@ desc = initial(desc) process_queue = FALSE -/** - * Calculates resource/material costs for printing an item based on the machine's resource coefficient. - * - * Returns a list of k,v resources with their amounts. - * * D - Design datum to calculate the modified resource cost of. - */ -/obj/machinery/mecha_part_fabricator/proc/get_resources_w_coeff(datum/design/D) - var/list/resources = list() - for(var/R in D.materials) - var/datum/material/M = R - resources[M] = get_resource_cost_w_coeff(D, M) - return resources - -/** - * Checks if the Exofab has enough resources to print a given item. - * - * Returns FALSE if the design has no reagents used in its construction (?) or if there are insufficient resources. - * Returns TRUE if there are sufficient resources to print the item. - * * D - Design datum to calculate the modified resource cost of. - */ -/obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D) - if(length(D.reagents_list)) // No reagents storage - no reagent designs. - return FALSE - var/datum/component/material_container/materials = rmat.mat_container - if(materials.has_materials(get_resources_w_coeff(D))) - return TRUE - return FALSE - /** * Attempts to build the next item in the build queue. * @@ -228,7 +204,7 @@ * * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build. */ /obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D, verbose = TRUE) - if(!D) + if(!D || length(D.reagents_list)) return FALSE var/datum/component/material_container/materials = rmat.mat_container @@ -240,19 +216,16 @@ if(verbose) say("Mineral access is on hold, please contact the quartermaster.") return FALSE - if(!check_resources(D)) + if(!materials.has_materials(D.materials, component_coeff)) if(verbose) say("Not enough resources. Processing stopped.") return FALSE - build_materials = get_resources_w_coeff(D) - - materials.use_materials(build_materials) + materials.use_materials(D.materials, component_coeff) being_built = D build_finish = world.time + get_construction_time_w_coeff(initial(D.construction_time)) build_start = world.time desc = "It's building \a [D.name]." - rmat.silo_log(src, "built", -1, "[D.name]", build_materials) return TRUE @@ -339,17 +312,6 @@ queue.Cut(index,++index) return TRUE -/** - * Calculates the coefficient-modified resource cost of a single material component of a design's recipe. - * - * Returns coefficient-modified resource cost for the given material component. - * * D - Design datum to pull the resource cost from. - * * resource - Material datum reference to the resource to calculate the cost of. - * * roundto - Rounding value for round() proc - */ -/obj/machinery/mecha_part_fabricator/proc/get_resource_cost_w_coeff(datum/design/D, datum/material/resource, roundto = 1) - return round(D.materials[resource]*component_coeff, roundto) - /** * Calculates the coefficient-modified build time of a design. * @@ -373,7 +335,8 @@ ui.open() /obj/machinery/mecha_part_fabricator/ui_static_data(mob/user) - var/list/data = list() + var/list/data = rmat.mat_container.ui_static_data() + var/list/designs = list() var/datum/asset/spritesheet/research_designs/spritesheet = get_asset_datum(/datum/asset/spritesheet/research_designs) @@ -381,12 +344,11 @@ for(var/datum/design/design in cached_designs) var/cost = list() - - for(var/datum/material/material in design.materials) - cost[material.name] = get_resource_cost_w_coeff(design, material) + var/list/materials = design["materials"] + for(var/datum/material/mat in materials) + cost[mat.name] = OPTIMAL_COST(materials[mat] * component_coeff) var/icon_size = spritesheet.icon_size_id(design.id) - designs[design.id] = list( "name" = design.name, "desc" = design.get_description(), @@ -404,7 +366,7 @@ /obj/machinery/mecha_part_fabricator/ui_data(mob/user) var/list/data = list() - data["materials"] = rmat.mat_container?.ui_data() + data["materials"] = rmat.mat_container.ui_data() data["queue"] = list() data["processing"] = process_queue diff --git a/code/modules/wiremod/core/component_printer.dm b/code/modules/wiremod/core/component_printer.dm index 7925f3b76ff..b0365fa0b14 100644 --- a/code/modules/wiremod/core/component_printer.dm +++ b/code/modules/wiremod/core/component_printer.dm @@ -17,6 +17,9 @@ /// The current unlocked circuit component designs. Used by integrated circuits to print off circuit components remotely. var/list/current_unlocked_designs = list() + /// The efficiency of this machine + var/efficiency_coeff = 1 + /obj/machinery/component_printer/Initialize(mapload) . = ..() if(!CONFIG_GET(flag/no_default_techweb_link) && !techweb) @@ -24,7 +27,6 @@ materials = AddComponent( \ /datum/component/remote_materials, \ - "component_printer", \ mapload, \ mat_container_flags = BREAKDOWN_FLAGS_LATHE, \ ) @@ -74,18 +76,9 @@ get_asset_datum(/datum/asset/spritesheet/sheetmaterials) ) -/obj/machinery/component_printer/proc/calculate_efficiency() - var/rating = 0 +/obj/machinery/component_printer/RefreshParts() + . = ..() - for(var/datum/stock_part/servo/servo in component_parts) - ///we do -1 because normal manipulators rating of 1 gives us 1-1=0 i.e no decrement in cost - rating += servo.tier-1 - - ///linear interpolation between full cost i.e 1 & 1/8th the cost i.e 0.125 - ///we do it in 6 steps because maximum rating of 2 manipulators is 8 but -1 gives us 6 - var/coff = 1.0+((0.125-1.0)*(rating/6)) - - ///copied from production.dm calculate_efficiency() proc if(materials) var/total_storage = 0 @@ -94,7 +87,17 @@ materials.set_local_size(total_storage) - return coff + efficiency_coeff = 0 + + for(var/datum/stock_part/servo/servo in component_parts) + ///we do -1 because normal manipulators rating of 1 gives us 1-1=0 i.e no decrement in cost + efficiency_coeff += servo.tier-1 + + ///linear interpolation between full cost i.e 1 & 1/8th the cost i.e 0.125 + ///we do it in 6 steps because maximum rating of 2 manipulators is 8 but -1 gives us 6 + efficiency_coeff = 1.0+((0.125-1.0)*(efficiency_coeff / 6)) + + update_static_data_for_all_viewers() /obj/machinery/component_printer/proc/print_component(typepath) var/design_id = current_unlocked_designs[typepath] @@ -106,8 +109,7 @@ if (materials.on_hold()) return - var/efficiency_coeff = calculate_efficiency() - if (!materials.mat_container?.has_materials(design.materials, efficiency_coeff)) + if (!materials.mat_container.has_materials(design.materials, efficiency_coeff)) return materials.mat_container.use_materials(design.materials, efficiency_coeff) @@ -133,14 +135,12 @@ say("Mineral access is on hold, please contact the quartermaster.") return TRUE - var/efficiency_coeff = calculate_efficiency() - - if (!materials.mat_container?.has_materials(design.materials, efficiency_coeff)) + if (!materials.mat_container.has_materials(design.materials, efficiency_coeff)) say("Not enough materials.") return TRUE balloon_alert_to_viewers("printed [design.name]") - materials.mat_container?.use_materials(design.materials, efficiency_coeff) + materials.mat_container.use_materials(design.materials, efficiency_coeff) materials.silo_log(src, "printed", -1, design.name, design.materials) var/atom/printed_design = new design.build_path(drop_location()) printed_design.pixel_x = printed_design.base_pixel_x + rand(-5, 5) @@ -163,12 +163,12 @@ return data /obj/machinery/component_printer/ui_static_data(mob/user) - var/list/data = list() + var/list/data = materials.mat_container.ui_static_data() + var/list/designs = list() var/datum/asset/spritesheet/research_designs/spritesheet = get_asset_datum(/datum/asset/spritesheet/research_designs) var/size32x32 = "[spritesheet.name]32x32" - var/efficiency_coeff = calculate_efficiency() // for (var/datum/design/component/component_design_type as anything in subtypesof(/datum/design/component)) for (var/researched_design_id in techweb.researched_designs) @@ -176,12 +176,15 @@ if (!(design.build_type & COMPONENT_PRINTER)) continue - var/icon_size = spritesheet.icon_size_id(design.id) + var/list/cost = list() + for(var/datum/material/mat in design.materials) + cost[mat.name] = OPTIMAL_COST(design.materials[mat] * efficiency_coeff) + var/icon_size = spritesheet.icon_size_id(design.id) designs[researched_design_id] = list( "name" = design.name, "desc" = design.desc, - "cost" = get_material_cost_data(design.materials, efficiency_coeff), + "cost" = cost, "id" = researched_design_id, "categories" = design.category, "icon" = "[icon_size == size32x32 ? "" : "[icon_size] "][design.id]", @@ -315,12 +318,13 @@ var/cost_per_component = 1000 + var/efficiency_coeff = 1 + /obj/machinery/module_duplicator/Initialize(mapload) . = ..() materials = AddComponent( \ /datum/component/remote_materials, \ - "module_duplicator", \ mapload, \ mat_container_flags = BREAKDOWN_FLAGS_LATHE, \ ) @@ -337,8 +341,9 @@ get_asset_datum(/datum/asset/spritesheet/research_designs) ) -/obj/machinery/module_duplicator/proc/calculate_efficiency() - ///copied from production.dm calculate_efficiency() proc +/obj/machinery/module_duplicator/RefreshParts() + . = ..() + if(materials) var/total_storage = 0 @@ -347,17 +352,17 @@ materials.set_local_size(total_storage) - var/rating = 0 + efficiency_coeff = 0 for(var/datum/stock_part/servo/servo in component_parts) ///we do -1 because normal manipulators rating of 1 gives us 1-1=0 i.e no decrement in cost - rating += servo.tier - 1 + efficiency_coeff += servo.tier - 1 ///linear interpolation between full cost i.e 1 & 1/8th the cost i.e 0.125 ///we do it in 6 steps because maximum rating of 2 manipulators is 8 but -1 gives us 6 - var/coff = 1.0 + ((0.125 - 1.0) * (rating/6)) + efficiency_coeff = 1.0 + ((0.125 - 1.0) * (efficiency_coeff / 6)) - return coff + update_static_data_for_all_viewers() /obj/machinery/module_duplicator/ui_act(action, list/params) . = ..() @@ -377,14 +382,12 @@ say("Mineral access is on hold, please contact the quartermaster.") return TRUE - var/efficiency_coeff = calculate_efficiency() - - if (!materials.mat_container?.has_materials(design["materials"], efficiency_coeff)) + if (!materials.mat_container.has_materials(design["materials"], efficiency_coeff)) say("Not enough materials.") return TRUE balloon_alert_to_viewers("printed [design["name"]]") - materials.mat_container?.use_materials(design["materials"], efficiency_coeff) + materials.mat_container.use_materials(design["materials"], efficiency_coeff) materials.silo_log(src, "printed", -1, design["name"], design["materials"]) print_module(design) if ("remove_mat") @@ -481,19 +484,22 @@ return data /obj/machinery/module_duplicator/ui_static_data(mob/user) - var/list/data = list() + var/list/data = materials.mat_container.ui_static_data() var/list/designs = list() var/index = 1 - - var/efficiency_coeff = calculate_efficiency() - for (var/list/design as anything in scanned_designs) + + var/list/cost = list() + var/list/materials = design["materials"] + for(var/datum/material/mat in materials) + cost[mat.name] = OPTIMAL_COST(materials[mat] * efficiency_coeff) + designs["[index]"] = list( "name" = design["name"], "desc" = design["desc"], - "cost" = get_material_cost_data(design["materials"], efficiency_coeff), + "cost" = cost, "id" = "[index]", "icon" = "integrated_circuit", "categories" = list("/Saved Circuits"), @@ -513,11 +519,3 @@ if(..()) return TRUE return default_deconstruction_screwdriver(user, "module-fab-o", "module-fab-idle", tool) - -/obj/machinery/module_duplicator/proc/get_material_cost_data(list/materials, efficiency_coeff) - var/list/data = list() - - for (var/datum/material/material_type as anything in materials) - data[initial(material_type.name)] = materials[material_type] * efficiency_coeff - - return data diff --git a/tgstation.dme b/tgstation.dme index 85c0bb28c46..014276eadf7 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -290,6 +290,7 @@ #include "code\__DEFINES\dcs\signals\signals_ladder.dm" #include "code\__DEFINES\dcs\signals\signals_lift.dm" #include "code\__DEFINES\dcs\signals\signals_light_eater.dm" +#include "code\__DEFINES\dcs\signals\signals_material_container.dm" #include "code\__DEFINES\dcs\signals\signals_medical.dm" #include "code\__DEFINES\dcs\signals\signals_mind.dm" #include "code\__DEFINES\dcs\signals\signals_mining.dm" @@ -969,7 +970,6 @@ #include "code\datums\components\lock_on_cursor.dm" #include "code\datums\components\manual_blinking.dm" #include "code\datums\components\manual_breathing.dm" -#include "code\datums\components\material_container.dm" #include "code\datums\components\mind_linker.dm" #include "code\datums\components\mirage_border.dm" #include "code\datums\components\mirv.dm" @@ -998,7 +998,6 @@ #include "code\datums\components\redirect_attack_hand_from_turf.dm" #include "code\datums\components\regenerator.dm" #include "code\datums\components\religious_tool.dm" -#include "code\datums\components\remote_materials.dm" #include "code\datums\components\rename.dm" #include "code\datums\components\revenge_ability.dm" #include "code\datums\components\rot.dm" @@ -1095,6 +1094,8 @@ #include "code\datums\components\food\germ_sensitive.dm" #include "code\datums\components\food\golem_food.dm" #include "code\datums\components\food\ice_cream_holder.dm" +#include "code\datums\components\material\material_container.dm" +#include "code\datums\components\material\remote_materials.dm" #include "code\datums\components\pet_commands\fetch.dm" #include "code\datums\components\pet_commands\obeys_commands.dm" #include "code\datums\components\pet_commands\pet_command.dm" diff --git a/tgui/packages/tgui/interfaces/Autolathe.tsx b/tgui/packages/tgui/interfaces/Autolathe.tsx index 0f5a63879b6..1436d045256 100644 --- a/tgui/packages/tgui/interfaces/Autolathe.tsx +++ b/tgui/packages/tgui/interfaces/Autolathe.tsx @@ -8,26 +8,25 @@ import { BooleanLike, classes } from 'common/react'; import { MaterialCostSequence } from './Fabrication/MaterialCostSequence'; import { Material } from './Fabrication/Types'; -type AutolatheDesign = Design & { - buildable: BooleanLike; - mult5: BooleanLike; - mult10: BooleanLike; - mult25: BooleanLike; - mult50: BooleanLike; - sheet: BooleanLike; -}; - type AutolatheData = { materials: Material[]; materialtotal: number; materialsmax: number; - designs: AutolatheDesign[]; + SHEET_MATERIAL_AMOUNT: number; + designs: Design[]; active: BooleanLike; }; export const Autolathe = (props, context) => { - const { act, data } = useBackend(context); - const { materialtotal, materialsmax, materials, designs, active } = data; + const { data } = useBackend(context); + const { + materialtotal, + materialsmax, + materials, + designs, + active, + SHEET_MATERIAL_AMOUNT, + } = data; const filteredMaterials = materials.filter((material) => material.amount > 0); @@ -54,7 +53,10 @@ export const Autolathe = (props, context) => { 'average': [materialsmax * 0.25, materialsmax * 0.85], 'bad': [0, materialsmax * 0.25], }}> - {materialtotal + '/' + materialsmax + ' cm³'} + {materialtotal / SHEET_MATERIAL_AMOUNT + + '/' + + materialsmax / SHEET_MATERIAL_AMOUNT + + ' sheets'} @@ -74,7 +76,8 @@ export const Autolathe = (props, context) => { backgroundColor={material.color} color="black">
- {material.amount + ' cm³'} + {material.amount / SHEET_MATERIAL_AMOUNT + + ' sheets'}
@@ -98,6 +101,7 @@ export const Autolathe = (props, context) => { ) => ( )} @@ -113,11 +117,12 @@ type PrintButtonProps = { design: Design; quantity: number; availableMaterials: MaterialMap; + SHEET_MATERIAL_AMOUNT: number; }; const PrintButton = (props: PrintButtonProps, context) => { - const { act, data } = useBackend(context); - const { design, quantity, availableMaterials } = props; + const { act } = useBackend(context); + const { design, quantity, availableMaterials, SHEET_MATERIAL_AMOUNT } = props; const canPrint = !Object.entries(design.cost).some( ([material, amount]) => @@ -131,6 +136,7 @@ const PrintButton = (props: PrintButtonProps, context) => { }> @@ -148,13 +154,14 @@ const PrintButton = (props: PrintButtonProps, context) => { }; type AutolatheRecipeProps = { - design: AutolatheDesign; + design: Design; availableMaterials: MaterialMap; + SHEET_MATERIAL_AMOUNT: number; }; const AutolatheRecipe = (props: AutolatheRecipeProps, context) => { - const { act, data } = useBackend(context); - const { design, availableMaterials } = props; + const { act } = useBackend(context); + const { design, availableMaterials, SHEET_MATERIAL_AMOUNT } = props; const canPrint = !Object.entries(design.cost).some( ([material, amount]) => @@ -179,6 +186,7 @@ const AutolatheRecipe = (props: AutolatheRecipeProps, context) => { }> @@ -199,37 +207,19 @@ const AutolatheRecipe = (props: AutolatheRecipeProps, context) => {
- {!!design.mult5 && ( - - )} + - {!!design.mult10 && ( - - )} - - {!!design.mult25 && ( - - )} - - {!!design.mult50 && ( - - )} +
; materials: Material[]; + SHEET_MATERIAL_AMOUNT: number; }; export const ComponentPrinter = (props, context) => { const { act, data } = useBackend(context); - const { designs, materials } = data; + const { materials, designs, SHEET_MATERIAL_AMOUNT } = data; // Reduce the material count array to a map of actually available materials. const availableMaterials: MaterialMap = {}; - for (const material of data.materials) { + for (const material of materials) { availableMaterials[material.name] = material.amount; } @@ -37,13 +38,20 @@ export const ComponentPrinter = (props, context) => { design, availableMaterials, _onPrintDesign - ) => } + ) => ( + + )} />
act('remove_mat', { ref: material.ref, amount }) } @@ -56,9 +64,15 @@ export const ComponentPrinter = (props, context) => { ); }; -const Recipe = (props: { design: Design; available: MaterialMap }, context) => { - const { act, data } = useBackend(context); - const { design, available } = props; +type RecipeProps = { + design: Design; + available: MaterialMap; + SHEET_MATERIAL_AMOUNT: number; +}; + +const Recipe = (props: RecipeProps, context) => { + const { act } = useBackend(context); + const { design, available, SHEET_MATERIAL_AMOUNT } = props; const canPrint = !Object.entries(design.cost).some( ([material, amount]) => @@ -82,6 +96,7 @@ const Recipe = (props: { design: Design; available: MaterialMap }, context) => { }> @@ -90,7 +105,9 @@ const Recipe = (props: { design: Design; available: MaterialMap }, context) => { 'FabricatorRecipe__Title', !canPrint && 'FabricatorRecipe__Title--disabled', ])} - onClick={() => act('print', { designId: design.id, amount: 1 })}> + onClick={() => + canPrint && act('print', { designId: design.id, amount: 1 }) + }>
{ const { act, data } = useBackend(context); + const { materials, SHEET_MATERIAL_AMOUNT } = data; const availableMaterials: MaterialMap = {}; - for (const material of data.materials) { + for (const material of materials) { availableMaterials[material.name] = material.amount; } @@ -33,7 +33,11 @@ export const ExosuitFabricator = (props, context) => { designs={Object.values(data.designs)} availableMaterials={availableMaterials} buildRecipeElement={(design, availableMaterials) => ( - + )} categoryButtons={(category) => (
);