From 412115c9b912f144de2f43d15207622ec724ca0e Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Sun, 1 Jun 2025 02:59:56 +0200 Subject: [PATCH] Fixes bugs related to transferring items to turfs, splits doing that off from `dropItemToGround(...)` (#91326) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request Closes #91131. The author currently has other priorities, and as I need it for something else I am finishing it myself with the author's blessing. Recently, we turned `transferItemToLoc(...)` into a proc intended to be for transfers to non-turfs, with it now playing an animation to reflect that. However, this had the effect of leaving us with `dropItemToGround(...)` for mob>turf transfers, which isn't _ideal_. It sends an 'item dropped' signal, it randomizes offsets, and using it to transfer to a non-`drop_location()` loc was implemented as an afterthought. So in this pr we create a new proc, `transfer_item_to_turf(...)`, that separates off the actual transferring, setting offsets, and animating into its own proc. Then `dropItemToGround(...)`, tables, racks, easels, closets, hoops, beds, conveyor belts, pin the tail corgi posters, some other stuff, and the `floor_placeable` element call such each with their own preferred arguments. While we could leave setting offsets out of it, because setting the offsets after calling the animation works just fine, having them be set before the animation felt like a more intuitive flow. ...While I would love to refactor the easel's incredibly questionable `attackby(...)`, that is outside of the scope of this pr. ## Why It's Good For The Game Fixes #91082. Less jank 👍 ## Changelog :cl: fix: Placing an item on a table/turf via the alt-click menu actually centers it, again. fix: Certain items, like canvases or syringe guns, are no longer weirdly offset when placed on tables. fix: Placing items on racks, closets, crates, hoops, beds, conveyor belts, and pin the tail corgi posters is animated again, instead of instantly teleporting followed by the pickup animation. fix: Placing a canvas on an easels no longer applies a random offset as if dropped. fix: Tucking in someone else actually animates the bedsheet from you to them, instead of from them to them. qol: Placing a canvas on an easel is animated. /:cl: --- code/datums/elements/bed_tucking.dm | 2 +- code/datums/elements/floor_placeable.dm | 11 ++++--- code/game/machinery/slotmachine.dm | 2 +- code/game/objects/items/tail_pin.dm | 16 +++++---- code/game/objects/structures/bedsheet_bin.dm | 5 ++- .../structures/crates_lockers/closets.dm | 2 +- code/game/objects/structures/girders.dm | 2 +- code/game/objects/structures/tables_racks.dm | 14 +++++--- code/modules/art/paintings.dm | 3 +- code/modules/basketball/hoop.dm | 2 +- code/modules/mob/inventory.dm | 33 ++++++++++++++----- code/modules/recycling/conveyor.dm | 2 +- 12 files changed, 58 insertions(+), 36 deletions(-) diff --git a/code/datums/elements/bed_tucking.dm b/code/datums/elements/bed_tucking.dm index 3b49f2a608f..3eb8491b481 100644 --- a/code/datums/elements/bed_tucking.dm +++ b/code/datums/elements/bed_tucking.dm @@ -45,7 +45,7 @@ if(!istype(target_bed)) return - if(!tucker.transferItemToLoc(tucked, target_bed.drop_location())) + if(!tucker.transfer_item_to_turf(tucked, target_bed.drop_location())) return to_chat(tucker, span_notice("You lay [tucked] out on [target_bed].")) diff --git a/code/datums/elements/floor_placeable.dm b/code/datums/elements/floor_placeable.dm index e7c3978de6c..25b6957a7b0 100644 --- a/code/datums/elements/floor_placeable.dm +++ b/code/datums/elements/floor_placeable.dm @@ -30,12 +30,15 @@ return NONE if(source.item_flags & ABSTRACT) return NONE - if(!user.dropItemToGround(to_drop = source, silent = FALSE, newloc = interacting_with)) - return ITEM_INTERACT_BLOCKING + var/x_offset = 0 + var/y_offset = 0 // Items are centered by default, but we move them if click ICON_X and ICON_Y are available if(LAZYACCESS(modifiers, ICON_X) && LAZYACCESS(modifiers, ICON_Y)) // Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the turf) - source.pixel_x = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(ICON_SIZE_X*0.5), ICON_SIZE_X*0.5) - source.pixel_y = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(ICON_SIZE_Y*0.5), ICON_SIZE_Y*0.5) + x_offset = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(ICON_SIZE_X*0.5), ICON_SIZE_X*0.5) + y_offset = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(ICON_SIZE_Y*0.5), ICON_SIZE_Y*0.5) + + if(!user.transfer_item_to_turf(source, interacting_with, x_offset, y_offset, silent = FALSE)) + return ITEM_INTERACT_BLOCKING return ITEM_INTERACT_SUCCESS diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm index d3266df16f8..90fe826136b 100644 --- a/code/game/machinery/slotmachine.dm +++ b/code/game/machinery/slotmachine.dm @@ -99,7 +99,7 @@ var/obj/item/coin/inserted_coin = inserted if(paymode == COIN) if(prob(2)) - if(!user.transferItemToLoc(inserted_coin, drop_location(), silent = FALSE)) + if(!user.transfer_item_to_turf(inserted_coin, drop_location(), silent = FALSE)) return ITEM_INTERACT_BLOCKING inserted_coin.throw_at(user, 3, 10) if(prob(10)) diff --git a/code/game/objects/items/tail_pin.dm b/code/game/objects/items/tail_pin.dm index 99998b53635..8b6aa245b3c 100644 --- a/code/game/objects/items/tail_pin.dm +++ b/code/game/objects/items/tail_pin.dm @@ -35,14 +35,16 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/party_game, 32) -/obj/structure/sign/poster/party_game/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers) +/obj/structure/sign/poster/party_game/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers) . = ..() - if(!istype(I,/obj/item/tail_pin))//We're using the same trick that tables use for placing objects x and y onto the click location. + if(!istype(attacking_item, /obj/item/tail_pin))//We're using the same trick that tables use for placing objects x and y onto the click location. return - if(!user.transferItemToLoc(I, drop_location(), silent = FALSE)) + + var/x_offset = 0 + var/y_offset = 0 + if(LAZYACCESS(modifiers, ICON_X) && LAZYACCESS(modifiers, ICON_Y)) + x_offset = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(ICON_SIZE_X/2), ICON_SIZE_X/2) + y_offset = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(ICON_SIZE_Y/2), ICON_SIZE_Y/2) + if(!user.transfer_item_to_turf(attacking_item, drop_location(), x_offset, y_offset, silent = FALSE)) return - if(!LAZYACCESS(modifiers, ICON_X) || !LAZYACCESS(modifiers, ICON_Y)) - return - I.pixel_x = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(ICON_SIZE_X/2), ICON_SIZE_X/2) - I.pixel_y = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(ICON_SIZE_Y/2), ICON_SIZE_Y/2) return TRUE diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 1d456148e88..01536a2518a 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -65,10 +65,9 @@ LINEN BINS var/mob/living/to_cover = interacting_with if(to_cover.body_position != LYING_DOWN) return ITEM_INTERACT_BLOCKING - if(!user.dropItemToGround(src)) + if(!user.transfer_item_to_turf(src, get_turf(to_cover))) return ITEM_INTERACT_BLOCKING - forceMove(get_turf(to_cover)) balloon_alert(user, "covered") coverup(to_cover) add_fingerprint(user) @@ -97,7 +96,7 @@ LINEN BINS return if(user.body_position != LYING_DOWN) return - if(!user.dropItemToGround(src)) + if(!user.transfer_item_to_turf(src, get_turf(src))) return coverup(user) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 31a3b4c3211..827da840f2d 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -884,7 +884,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) return if (user.combat_mode) return - if(user.transferItemToLoc(weapon, drop_location())) // so we put in unlit welder too + if(user.transfer_item_to_turf(weapon, drop_location())) // so we put in unlit welder too return else if(weapon.tool_behaviour == TOOL_WELDER && can_weld_shut) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 0051178ce29..e235b4ec3e2 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -293,7 +293,7 @@ else if(istype(W, /obj/item/pipe)) var/obj/item/pipe/P = W if (P.pipe_type in list(0, 1, 5)) //simple pipes, simple bends, and simple manifolds. - if(!user.transferItemToLoc(P, drop_location())) + if(!user.transfer_item_to_turf(P, drop_location())) return balloon_alert(user, "inserted pipe") else diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 31394ca97e0..a8eff530ffe 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -495,13 +495,17 @@ /obj/structure/table/proc/table_place_act(mob/living/user, obj/item/tool, list/modifiers) if(tool.item_flags & ABSTRACT) return NONE - if(!user.dropItemToGround(to_drop = tool, silent = FALSE, newloc = get_turf(src))) - return ITEM_INTERACT_BLOCKING + + var/x_offset = 0 + var/y_offset = 0 // Items are centered by default, but we move them if click ICON_X and ICON_Y are available if(LAZYACCESS(modifiers, ICON_X) && LAZYACCESS(modifiers, ICON_Y)) // Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf) - tool.pixel_x = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(ICON_SIZE_X*0.5), ICON_SIZE_X*0.5) - tool.pixel_y = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(ICON_SIZE_Y*0.5), ICON_SIZE_Y*0.5) + x_offset = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(ICON_SIZE_X*0.5), ICON_SIZE_X*0.5) + y_offset = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(ICON_SIZE_Y*0.5), ICON_SIZE_Y*0.5) + + if(!user.transfer_item_to_turf(tool, get_turf(src), x_offset, y_offset, silent = FALSE)) + return ITEM_INTERACT_BLOCKING AfterPutItemOnTable(tool, user) return ITEM_INTERACT_SUCCESS @@ -1171,7 +1175,7 @@ return . if((tool.item_flags & ABSTRACT) || (user.combat_mode && !(tool.item_flags & NOBLUDGEON))) return NONE - if(user.transferItemToLoc(tool, drop_location(), silent = FALSE)) + if(user.transfer_item_to_turf(tool, get_turf(src), silent = FALSE)) return ITEM_INTERACT_SUCCESS return ITEM_INTERACT_BLOCKING diff --git a/code/modules/art/paintings.dm b/code/modules/art/paintings.dm index 441c7b226ec..340d4ca7723 100644 --- a/code/modules/art/paintings.dm +++ b/code/modules/art/paintings.dm @@ -18,9 +18,8 @@ /obj/structure/easel/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers) if(istype(I, /obj/item/canvas)) var/obj/item/canvas/canvas = I - user.dropItemToGround(canvas) + user.transfer_item_to_turf(canvas, get_turf(src), silent = FALSE) painting = canvas - canvas.forceMove(get_turf(src)) canvas.layer = layer+0.1 user.visible_message(span_notice("[user] puts \the [canvas] on \the [src]."),span_notice("You place \the [canvas] on \the [src].")) else diff --git a/code/modules/basketball/hoop.dm b/code/modules/basketball/hoop.dm index 830bde426f7..588e6b1bf4a 100644 --- a/code/modules/basketball/hoop.dm +++ b/code/modules/basketball/hoop.dm @@ -93,7 +93,7 @@ if(!baller.can_perform_action(src, NEED_HANDS|FORBID_TELEKINESIS_REACH)) return // TK users aren't allowed to dunk - if(!baller.transferItemToLoc(ball, drop_location())) + if(!baller.transfer_item_to_turf(ball, drop_location())) return var/dunk_dir = get_dir(baller, src) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index ba28deacd8c..e9b78bb1f35 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -334,22 +334,37 @@ * * If it was, returns the item. * If the item can be dropped, it will be forceMove()'d to the ground and the turf's Entered() will be called. */ -/mob/proc/dropItemToGround(obj/item/to_drop, force = FALSE, silent = FALSE, invdrop = TRUE, turf/newloc = null) +/mob/proc/dropItemToGround(obj/item/to_drop, force = FALSE, silent = FALSE, invdrop = TRUE) if(isnull(to_drop)) return + var/x_offset = rand(-6, 6) + var/y_offset = rand(-6, 6) SEND_SIGNAL(src, COMSIG_MOB_DROPPING_ITEM) - var/try_uneqip = doUnEquip(to_drop, force, newloc ? newloc : drop_location(), FALSE, invdrop = invdrop, silent = silent) - - if(!try_uneqip || !to_drop) //ensure the item exists and that it was dropped properly. + if(!transfer_item_to_turf(to_drop, drop_location(), x_offset, y_offset, force, silent, invdrop)) return - if(!(to_drop.item_flags & NO_PIXEL_RANDOM_DROP)) - to_drop.pixel_x = to_drop.base_pixel_x + rand(-6, 6) - to_drop.pixel_y = to_drop.base_pixel_y + rand(-6, 6) - to_drop.do_drop_animation(src) return to_drop +/// Unequips and transfers an item to a given turf, if possible. +/mob/proc/transfer_item_to_turf( + obj/item/to_transfer, + turf/new_loc, + x_offset = 0, + y_offset = 0, + force = FALSE, + silent = FALSE, + drop_item_inventory = TRUE, +) + if(!doUnEquip(to_transfer, force, new_loc, no_move = FALSE, invdrop = drop_item_inventory, silent = silent)) + return FALSE + if(QDELETED(to_transfer)) // Some items may get deleted upon getting unequipped. + return FALSE + to_transfer.pixel_x = to_transfer.base_pixel_x + x_offset + to_transfer.pixel_y = to_transfer.base_pixel_y + y_offset + to_transfer.do_drop_animation(src) + return TRUE + //for when the item will be immediately placed in a loc other than the ground /mob/proc/transferItemToLoc(obj/item/I, newloc = null, force = FALSE, silent = TRUE, animated = null) . = doUnEquip(I, force, newloc, FALSE, silent = silent) @@ -368,7 +383,7 @@ return doUnEquip(I, force, newloc, TRUE, idrop, silent = TRUE) //DO NOT CALL THIS PROC -//use one of the above 3 helper procs +//use one of the above 4 helper procs //you may override it, but do not modify the args /mob/proc/doUnEquip(obj/item/I, force, atom/newloc, no_move, invdrop = TRUE, silent = FALSE) //Force overrides TRAIT_NODROP for things like wizarditis and admin undress. //Use no_move if the item is just gonna be immediately moved afterward diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm index c6c413837fa..751bf1585b0 100644 --- a/code/modules/recycling/conveyor.dm +++ b/code/modules/recycling/conveyor.dm @@ -340,7 +340,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) new /obj/machinery/conveyor(target_turf, forwards, id) else if(!user.combat_mode || (attacking_item.item_flags & NOBLUDGEON)) - user.transferItemToLoc(attacking_item, drop_location()) + user.transfer_item_to_turf(attacking_item, drop_location()) else return ..()