From 46b114dc3b5ed09ed04477dae2c0d52b58cde883 Mon Sep 17 00:00:00 2001 From: Hatterhat <31829017+Hatterhat@users.noreply.github.com> Date: Fri, 6 Jan 2023 19:29:49 -0600 Subject: [PATCH] RPED tier-based parts dumping (#72386) ## About The Pull Request ![image](https://user-images.githubusercontent.com/31829017/210158760-9784fc06-f49c-45a3-b020-23c54507d471.png) Dumping out an RPED (by using it inhand - clickdrag dumping unaffected) causes it to calculate and drop the lowest tier of parts. Emptying further can be done by just using it inhand more. Directly inspired by https://github.com/Citadel-Station-13/Citadel-Station-13/pull/13763. The implementation probably sucks. I know I was told to use an associated list but then I forgot how to approach that and decided to slap together the current implementation. Sorry. https://user-images.githubusercontent.com/31829017/210158742-cae83430-bd9f-407f-a0fa-f11975d15d4c.mp4 ## Why It's Good For The Game Decluttering your part exchanger is as easy as pressing Z or whatever you do to dump out a storage item inhand. ## Changelog :cl: qol: Rapid Part Exchange Devices and their bluespace variants now automatically drop their current lowest tier of parts, instead of all of their parts. /:cl: Co-authored-by: Hatterhat --- code/datums/storage/subtypes/rped.dm | 47 ++++++++++++++++++++++++++++ code/modules/research/stock_parts.dm | 9 ++---- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/code/datums/storage/subtypes/rped.dm b/code/datums/storage/subtypes/rped.dm index a8edde8a693..390cd17f976 100644 --- a/code/datums/storage/subtypes/rped.dm +++ b/code/datums/storage/subtypes/rped.dm @@ -34,6 +34,11 @@ /obj/item/stack/sheet/bluespace_crystal, ) +/datum/storage/rped/New(atom/parent, max_slots, max_specific_storage, max_total_storage, numerical_stacking, allow_quick_gather, allow_quick_empty, collection_mode, attack_hand_interact) + . = ..() + var/atom/resolve_parent = src.parent?.resolve() + RegisterSignal(resolve_parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(rped_mass_empty), TRUE) + /datum/storage/rped/can_insert(obj/item/to_insert, mob/user, messages = TRUE, force = FALSE) . = ..() @@ -77,4 +82,46 @@ return . +/// overridden mass_empty, so as to dump only the lowest tier of parts currently in the RPED +/datum/storage/rped/proc/rped_mass_empty(datum/source, atom/location, force) + SIGNAL_HANDLER + + if(!allow_quick_empty && !force) + return + + remove_lowest_tier(get_turf(location)) + +/** + * Searches through everything currently in storage, calculates the lowest tier of parts inside of it, + * and then dumps out every part that has the equal tier of parts. Likely a worse implementation of remove_all. + * + * @param atom/target where we're placing the item + */ +/datum/storage/rped/proc/remove_lowest_tier(atom/target) // look whatever happens here i'm not proud of this. at all. + var/obj/item/resolve_parent = parent?.resolve() + var/obj/item/resolve_location = real_location?.resolve() + var/list/obj/item/parts_list = list() + var/current_lowest_tier = INFINITY + if(!resolve_parent || !resolve_location) + return + + if(!target) + target = get_turf(resolve_parent) + + for(var/obj/item/thing in resolve_location) + if(thing.loc != resolve_location) + continue + parts_list.Add(thing) + if(parts_list.len > 0) + parts_list = reverse_range(sortTim(parts_list, GLOBAL_PROC_REF(cmp_rped_sort))) + current_lowest_tier = parts_list[1].get_part_rating() + resolve_parent.balloon_alert(resolve_parent.loc, "dropping lowest rated parts...") + for(var/obj/item/part in parts_list) + if(part.get_part_rating() != current_lowest_tier) + break + if(!attempt_remove(part, target, silent = TRUE)) + continue + part.pixel_x = part.base_pixel_x + rand(-8, 8) + part.pixel_y = part.base_pixel_y + rand(-8, 8) + #undef MAX_STACK_PICKUP diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 5e57fecd4e0..7fcaa015f91 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -225,14 +225,11 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good part_list = sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort)) return part_list -/proc/cmp_rped_sort(obj/item/A, obj/item/B) +/proc/cmp_rped_sort(obj/item/first_item, obj/item/second_item) /** - * stacks components like cable,glass,plasteel are not component parts hence their get_part_rating() method is undefined and would return undefined values causing errors - * so we assign them an default rating of 1 when the RPED sorts these components + * even though stacks aren't stock parts, get_part_rating() is defined on the item level (see /obj/item/proc/get_part_rating()) and defaults to returning 0. */ - var/a_rating = isstack(A) ? 1 : A.get_part_rating() - var/b_rating = isstack(B) ? 1 : B.get_part_rating() - return b_rating - a_rating + return second_item.get_part_rating() - first_item.get_part_rating() /obj/item/stock_parts name = "stock part"