From 7d08da9fd618997eb47fcd4dc13e296e629c4412 Mon Sep 17 00:00:00 2001 From: Roxy <75404941+TealSeer@users.noreply.github.com> Date: Sat, 24 May 2025 20:14:53 -0400 Subject: [PATCH] Refactor split_stack to two separate procs, fixes a hard delete in the process (#91306) ## About The Pull Request I was trying to fix a hard delete and it became a whole thing - Reworks `/obj/item/stack/proc/split_stack` to no longer also try to put it in the user's hands, or take a user at all. The proc now purely splits the stack and returns the new one - Creates `/obj/item/stack/proc/split_n_take` which uses `split_stack` and does the other behaviors like fingerprint adding and putting in the user's hands - Update usages of `split_stack` to either properly use it and remove the code added to get around the put in hands behavior, or change them to use `split_n_take` instead - Fix a random bug in pipe bomb building I noticed while testing ## Why It's Good For The Game Ultimately this fixes a hard delete with goldgrubs eating a piece of ore while sitting on top of another piece of ore of the same type (the put in hands behavior of split stack would cause the ore being consumed to drop to the ground briefly, merge with the ore there, and then qdel while still being moved to the goldgrub contents), but also added bonus that it makes `split_stack` just split the stack and not some other stuff too. Also a pipe bomb bug fix ## Changelog :cl: fix: fixed being able to add seemingly infinite refined bluespace crystals to pipe bombs refactor: /obj/item/stack/split_stack no longer tries to move the stack into the user's hands, use /obj/item/stack/split_n_take for that /:cl: --- code/datums/components/udder.dm | 2 +- code/datums/elements/basic_eating.dm | 2 +- .../objects/items/devices/laserpointer.dm | 5 +-- .../game/objects/items/grenades/ghettobomb.dm | 5 ++- code/game/objects/items/stacks/stack.dm | 39 ++++++++++++------- code/modules/manufactorio/machines/router.dm | 2 +- .../living/basic/bots/repairbot/repairbot.dm | 10 ++--- .../bots/repairbot/repairbot_abilities.dm | 3 +- .../living/simple_animal/bot/construction.dm | 3 +- 9 files changed, 39 insertions(+), 32 deletions(-) diff --git a/code/datums/components/udder.dm b/code/datums/components/udder.dm index a659efbc504..c296c9bd4b4 100644 --- a/code/datums/components/udder.dm +++ b/code/datums/components/udder.dm @@ -119,7 +119,7 @@ var/atom/movable/final_food = food if(isstack(food)) //if stack, only consume 1 var/obj/item/stack/food_stack = food - final_food = food_stack.split_stack(udder_mob, 1) + final_food = food_stack.split_stack(1) final_food.forceMove(src) /obj/item/udder/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index 0e292054677..a0f5a2cedef 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -102,7 +102,7 @@ return if(isstack(target)) //if stack, only consume 1 var/obj/item/stack/food_stack = target - final_target = food_stack.split_stack(eater, 1) + final_target = food_stack.split_stack(1) eater.log_message("has eaten [target], [add_to_contents ? "swallowing it" : "destroying it"]!", LOG_ATTACK) diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index ba6bc73bcb0..71509d389ce 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -142,11 +142,10 @@ crystal_stack.use_tool(src, user, amount = 1) //use only one if we were installing from a stack of crystals return //the single crystal that we actually install - var/obj/item/stack/ore/bluespace_crystal/single_crystal = crystal_stack.split_stack(null, 1) + var/obj/item/stack/ore/bluespace_crystal/single_crystal = crystal_stack.split_stack(1) if(isnull(single_crystal)) return - if(!user.transferItemToLoc(single_crystal, src)) - return + single_crystal.forceMove(src) crystal_lens = single_crystal playsound(src, 'sound/items/tools/screwdriver2.ogg', 30) balloon_alert(user, "installed \the [crystal_lens.name]") diff --git a/code/game/objects/items/grenades/ghettobomb.dm b/code/game/objects/items/grenades/ghettobomb.dm index b10c6e6e976..1a7dc6f4fff 100644 --- a/code/game/objects/items/grenades/ghettobomb.dm +++ b/code/game/objects/items/grenades/ghettobomb.dm @@ -225,8 +225,9 @@ var/atom/movable/to_put = item if(isstack(item)) var/obj/item/stack/as_stack = item - to_put = as_stack.split_stack(user = null, amount = 1) - as_stack.merge_type = null //prevent them from merging inside for contents.len + var/obj/item/stack/new_stack = as_stack.split_stack(1) + new_stack.merge_type = null //prevent them from merging inside for contents.len + to_put = new_stack to_put.forceMove(src) return diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 2b965543894..d0f4e425923 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -695,7 +695,7 @@ if(user.get_inactive_held_item() == src) if(is_zero_amount(delete_if_zero = TRUE)) return - return split_stack(user, 1) + return split_n_take(user, 1) else . = ..() @@ -712,30 +712,41 @@ var/stackmaterial = tgui_input_number(user, "How many sheets do you wish to take out of this stack?", "Stack Split", max_value = max) if(!stackmaterial || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - split_stack(user, stackmaterial) + split_n_take(user, stackmaterial) to_chat(user, span_notice("You take [stackmaterial] sheets out of the stack.")) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN -/** Splits the stack into two stacks. +/** Splits the stack into two stacks, returns the new stack. * * Arguments: - * - [user][/mob]: The mob splitting the stack. * - amount: The number of units to split from this stack. */ -/obj/item/stack/proc/split_stack(mob/user, amount) +/obj/item/stack/proc/split_stack(amount) if(!use(amount, TRUE, FALSE)) return null - var/obj/item/stack/F = new type(user? user : drop_location(), amount, FALSE, mats_per_unit) - . = F - F.copy_evidences(src) + var/obj/item/stack/new_stack = new type(null, amount, FALSE, mats_per_unit) + new_stack.copy_evidences(src) loc.atom_storage?.refresh_views() - if(user) - if(!user.put_in_hands(F, merge_stacks = FALSE)) - F.forceMove(user.drop_location()) - add_fingerprint(user) - F.add_fingerprint(user) - is_zero_amount(delete_if_zero = TRUE) + return new_stack + +/** + * Splits amount items from stack, attempts to place new stack in user's hands. + * Returns the new stack. + * Arguments: + * * [user][/mob] - Mob performing the split, non-nullable + * * amount - Number of units to split from this stack + */ +/obj/item/stack/proc/split_n_take(mob/user, amount) + if(!user) + return null + add_fingerprint(user) + var/obj/item/stack/new_stack = split_stack(amount) + if(isnull(new_stack)) + return null + new_stack.add_fingerprint(user) + user.put_in_hands(new_stack, merge_stacks = FALSE) + return new_stack /obj/item/stack/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers) if(can_merge(W, inhand = TRUE)) diff --git a/code/modules/manufactorio/machines/router.dm b/code/modules/manufactorio/machines/router.dm index fa6950ea0c7..61e73ebceee 100644 --- a/code/modules/manufactorio/machines/router.dm +++ b/code/modules/manufactorio/machines/router.dm @@ -57,4 +57,4 @@ /obj/machinery/power/manufacturing/router/proc/handle_stack(obj/item/stack/stack, direction) if(stack.amount <= 1) // last implementation was just not good so lets cheap out return stack - return stack.split_stack(amount = 1) + return stack.split_stack(1) diff --git a/code/modules/mob/living/basic/bots/repairbot/repairbot.dm b/code/modules/mob/living/basic/bots/repairbot/repairbot.dm index 932f6df6be1..29583c9fca9 100644 --- a/code/modules/mob/living/basic/bots/repairbot/repairbot.dm +++ b/code/modules/mob/living/basic/bots/repairbot/repairbot.dm @@ -113,7 +113,7 @@ if(!user.transferItemToLoc(potential_stack, src)) user.balloon_alert(user, "stuck to your hand!") return - balloon_alert(src, "inserted") + balloon_alert(user, "inserted") return if(our_sheet.amount >= our_sheet.max_amount) user?.balloon_alert(user, "full!") @@ -121,11 +121,9 @@ if(!our_sheet.can_merge(potential_stack)) user?.balloon_alert(user, "not suitable!") return - var/atom/movable/to_move = potential_stack.split_stack(user, min(our_sheet.max_amount - our_sheet.amount, potential_stack.amount)) - if(!user.transferItemToLoc(to_move, src)) - user.balloon_alert(user, "stuck to your hand!") - return - balloon_alert(src, "inserted") + var/atom/movable/to_move = potential_stack.split_stack(min(our_sheet.max_amount - our_sheet.amount, potential_stack.amount)) + to_move.forceMove(src) + balloon_alert(user, "inserted") return /mob/living/basic/bot/repairbot/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) diff --git a/code/modules/mob/living/basic/bots/repairbot/repairbot_abilities.dm b/code/modules/mob/living/basic/bots/repairbot/repairbot_abilities.dm index 4de81f0015b..4d65c62216f 100644 --- a/code/modules/mob/living/basic/bots/repairbot/repairbot_abilities.dm +++ b/code/modules/mob/living/basic/bots/repairbot/repairbot_abilities.dm @@ -36,8 +36,7 @@ playsound(turf_target, 'sound/machines/click.ogg', 50, TRUE) new /obj/structure/girder(turf_target) - var/atom/stack_to_delete = our_rods.split_stack(owner, 2) - qdel(stack_to_delete) + our_rods.use(2) StartCooldown() qdel(effect) return TRUE diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 7bcdffb6549..ea8eed7201c 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -248,8 +248,7 @@ repair.set_color(toolbox_color) to_chat(user, span_notice("You add [item] to [src]. Boop beep!")) var/obj/item/stack/crafting_stack = item - var/atom/used_belt = crafting_stack.split_stack(user, 1) - qdel(used_belt) + crafting_stack.use(1) qdel(src)