From da10322dc1022e5dfe5c631db8a11fae60eee0cb Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sat, 11 Oct 2025 17:17:23 -0500 Subject: [PATCH] Fix modsuits and defibs (#93373) ## About The Pull Request Fixes #93359 Caused by #93165 Inventory screen elements were no longer considered reachable, which broke mousedrop handing on objects that check "is dragging into inventory slot" I don't know the best way to fix this yet but I figured the next best thing would be to make all of these use the `drag_pickup` element, which skips this reach-ability check Thus I refactored it slightly to accommodate for items which should contextually not be drag-pick-up-abble and bam, works like a charm ## Changelog :cl: Melbert fix: Dragging defibs and modsuits off your back works again /:cl: --------- Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com> Co-authored-by: Xander3359 <66163761+Xander3359@users.noreply.github.com> --- code/datums/elements/drag_pickup.dm | 29 ++++++++++--------- code/datums/storage/storage.dm | 18 +++++++----- code/game/objects/items.dm | 6 ++-- code/game/objects/items/defib.dm | 9 +----- code/game/objects/items/tanks/watertank.dm | 7 +---- code/modules/clothing/clothing.dm | 11 ------- code/modules/clothing/shoes/sneakers.dm | 10 +++---- .../living/carbon/alien/special/facehugger.dm | 11 ++++--- code/modules/mod/mod_control.dm | 22 ++------------ .../computers/item/laptop.dm | 11 +------ code/modules/paperwork/paper_cutter.dm | 10 +------ .../projectiles/guns/energy/laser_gatling.dm | 10 +------ .../machinery/portable_chem_mixer.dm | 9 +----- .../xenobiology/crossbreeding/_clothing.dm | 20 +++---------- code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/unequip_defib.dm | 19 ++++++++++++ 16 files changed, 73 insertions(+), 130 deletions(-) create mode 100644 code/modules/unit_tests/unequip_defib.dm diff --git a/code/datums/elements/drag_pickup.dm b/code/datums/elements/drag_pickup.dm index 8eb73bbb438..f93288303bd 100644 --- a/code/datums/elements/drag_pickup.dm +++ b/code/datums/elements/drag_pickup.dm @@ -1,7 +1,8 @@ /** - * drag_pickup element; for allowing things to be picked up by dragging. + * drag_pickup element * - * Used for paper bins. + * Allowing things to be picked up or unequipped by mouse-dragging. + * Useful for objects which have an interaction on click */ /datum/element/drag_pickup @@ -15,20 +16,22 @@ UnregisterSignal(source, COMSIG_MOUSEDROP_ONTO) return ..() -/datum/element/drag_pickup/proc/pick_up(atom/source, atom/over, mob/user) +/datum/element/drag_pickup/proc/pick_up(atom/movable/source, atom/over, mob/user) SIGNAL_HANDLER - var/mob/living/picker = user - if(!istype(picker) || !user.can_perform_action(source, FORBID_TELEKINESIS_REACH)) - return - var/obj/pickup_object = source - if (pickup_object) - if (pickup_object.anchored) + if(!user.can_perform_action(source, FORBID_TELEKINESIS_REACH)) + return NONE + if(source.anchored) + return NONE + if(source.loc == user && isitem(source)) + var/obj/item/item_source = source + if(!item_source.can_mob_unequip(user)) return COMPONENT_CANCEL_MOUSEDROP_ONTO - if(over == picker) - INVOKE_ASYNC(picker, TYPE_PROC_REF(/mob/, put_in_hands), source) + if(over == user) + INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, put_in_hands), source) else if(istype(over, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/Selected_hand = over - picker.putItemFromInventoryInHandIfPossible(source, Selected_hand.held_index) + var/atom/movable/screen/inventory/hand/selected_hand = over + user.putItemFromInventoryInHandIfPossible(source, selected_hand.held_index) + source.add_fingerprint(user) return COMPONENT_CANCEL_MOUSEDROP_ONTO diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 4c5d6b8efbe..17338ba53b6 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -775,11 +775,15 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) SIGNAL_HANDLER if(ismecha(user.loc) || user.incapacitated || !user.canUseStorage()) - return + return NONE if(istype(over_object, /atom/movable/screen/inventory/hand)) if(real_location.loc != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) - return + return NONE + if(isitem(parent)) + var/obj/item/item_parent = parent + if(!item_parent.can_mob_unequip(user)) + return COMPONENT_CANCEL_MOUSEDROP_ONTO var/atom/movable/screen/inventory/hand/hand = over_object user.putItemFromInventoryInHandIfPossible(parent, hand.held_index) @@ -788,27 +792,27 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) if(ismob(over_object)) if(over_object != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) - return + return NONE parent.add_fingerprint(user) INVOKE_ASYNC(src, PROC_REF(open_storage), user) return COMPONENT_CANCEL_MOUSEDROP_ONTO if(istype(over_object, /atom/movable/screen)) - return + return NONE if(!user.can_perform_action(over_object, FORBID_TELEKINESIS_REACH)) - return + return NONE parent.add_fingerprint(user) var/atom/dump_loc = over_object.get_dumping_location() if(isnull(dump_loc)) - return + return NONE /// Don't dump *onto* objects in the same storage as ourselves if (over_object.loc == parent.loc && !isnull(parent.loc.atom_storage) && isnull(over_object.atom_storage)) - return + return NONE INVOKE_ASYNC(src, PROC_REF(dump_content_at), over_object, dump_loc, user) return COMPONENT_CANCEL_MOUSEDROP_ONTO diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 46a13eafafa..431da812e0f 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -611,7 +611,7 @@ if(throwing) throwing.finalize(FALSE) if(loc == user && outside_storage) - if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(src)) + if(!can_mob_unequip(user) || !user.temporarilyRemoveItemFromInventory(src)) return . = FALSE @@ -621,7 +621,9 @@ user.dropItemToGround(src) return TRUE -/obj/item/proc/allow_attack_hand_drop(mob/user) +/// Called when a mob is manually attempting to unequip the item +/// Returning FALSE will prevent the unequip from happening +/obj/item/proc/can_mob_unequip(mob/user) return TRUE /obj/item/attack_paw(mob/user, list/modifiers) diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 205a47e9cb6..73684e56eab 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -56,6 +56,7 @@ paddles = new paddle_type(src) update_power() RegisterSignal(paddles, COMSIG_DEFIBRILLATOR_SUCCESS, PROC_REF(on_defib_success)) + AddElement(/datum/element/drag_pickup) /obj/item/defibrillator/loaded/Initialize(mapload) //starts with hicap . = ..() @@ -136,14 +137,6 @@ ui_action_click() //checks for this are handled in defibrillator.mount.dm return ..() -/obj/item/defibrillator/mouse_drop_dragged(atom/over_object, mob/user, src_location, over_location, params) - if(!ismob(loc)) - return - var/mob/living_mob = loc - if(!living_mob.incapacitated && istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/hand = over_object - living_mob.putItemFromInventoryInHandIfPossible(src, hand.held_index) - /obj/item/defibrillator/screwdriver_act(mob/living/user, obj/item/tool) if(!cell || !cell_removable) return FALSE diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index a704d49a7f3..3891f34bd09 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -28,6 +28,7 @@ create_reagents(volume, OPENCONTAINER) noz = make_noz() RegisterSignal(noz, COMSIG_MOVABLE_MOVED, PROC_REF(noz_move)) + AddElement(/datum/element/drag_pickup) /obj/item/watertank/Destroy() QDEL_NULL(noz) @@ -90,12 +91,6 @@ else return ..() -/obj/item/watertank/mouse_drop_dragged(atom/over_object) - var/mob/M = loc - if(istype(M) && istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/H = over_object - M.putItemFromInventoryInHandIfPossible(src, H.held_index) - /obj/item/watertank/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers) if(attacking_item == noz) remove_noz() diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 198cb6b27a9..7cccab27ea2 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -72,17 +72,6 @@ if(!icon_state) item_flags |= ABSTRACT -/obj/item/clothing/mouse_drop_dragged(atom/over_object, mob/user, src_location, over_location, params) - var/mob/M = user - - if(ismecha(M.loc)) // stops inventory actions in a mech - return - - if(loc == M && istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/H = over_object - if(M.putItemFromInventoryInHandIfPossible(src, H.held_index)) - add_fingerprint(user) - /obj/item/food/clothing name = "temporary moth clothing snack item" desc = "If you're reading this it means I messed up. This is related to moths eating clothes and I didn't know a better way to do it than making a new food object. <--- stinky idiot wrote this" diff --git a/code/modules/clothing/shoes/sneakers.dm b/code/modules/clothing/shoes/sneakers.dm index 5a1826d55e7..f073336f429 100644 --- a/code/modules/clothing/shoes/sneakers.dm +++ b/code/modules/clothing/shoes/sneakers.dm @@ -166,12 +166,10 @@ return ..() attacking_item.forceMove(src) -/obj/item/clothing/shoes/sneakers/orange/allow_attack_hand_drop(mob/user) - if(ishuman(user)) - var/mob/living/carbon/human/C = user - if(C.shoes == src && attached_cuffs) - to_chat(user, span_warning("You need help taking these off!")) - return FALSE +/obj/item/clothing/shoes/sneakers/orange/can_mob_unequip(mob/user) + if(user.get_item_by_slot(slot_flags) == src && attached_cuffs) + to_chat(user, span_warning("You need help taking these off!")) + return FALSE return ..() /obj/item/clothing/shoes/sneakers/orange/mouse_drop_dragged(atom/over_object, mob/user) diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index a028679c996..246dc481aa0 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -257,13 +257,12 @@ // chest maybe because getting slammed in the chest would knock it off your face while dead AddComponent(/datum/component/knockoff, knockoff_chance = 40, target_zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST), slots_knockoffable = slot_flags) -/obj/item/clothing/mask/facehugger/allow_attack_hand_drop(mob/living/carbon/human/user) - if(!real || sterile || user.get_organ_by_type(/obj/item/organ/body_egg/alien_embryo)) +/obj/item/clothing/mask/facehugger/can_mob_unequip(mob/user) + if(!real || sterile || stat == DEAD || user.get_organ_by_type(/obj/item/organ/body_egg/alien_embryo)) return ..() - if(istype(user) && ishuman(loc) && stat != DEAD) - if(user == loc && user.get_item_by_slot(slot_flags) == src) - to_chat(user, span_userdanger("[src] is latched on too tight! Get help or wait for it to let go!")) - return FALSE + if(user.get_item_by_slot(slot_flags) == src) + to_chat(user, span_userdanger("[src] is latched on too tight! Get help or wait for it to let go!")) + return FALSE return ..() /obj/item/clothing/mask/facehugger/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params) diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index cb4689e81d0..fcc27c3e2e6 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -106,6 +106,7 @@ module = new module(src) install(module) START_PROCESSING(SSobj, src) + AddElement(/datum/element/drag_pickup) /obj/item/mod/control/Destroy() STOP_PROCESSING(SSobj, src) @@ -212,14 +213,14 @@ return clean_up() -/obj/item/mod/control/allow_attack_hand_drop(mob/user) +/obj/item/mod/control/can_mob_unequip(mob/user) if(user != wearer) return ..() if(active) balloon_alert(wearer, "unit active!") playsound(src, 'sound/machines/scanner/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) - return + return FALSE for(var/obj/item/part as anything in get_parts()) if(part.loc != src) @@ -229,23 +230,6 @@ return ..() -/obj/item/mod/control/mouse_drop_dragged(atom/over_object, mob/user) - if(user != wearer || !istype(over_object, /atom/movable/screen/inventory/hand)) - return - if(active) - balloon_alert(wearer, "unit active!") - playsound(src, 'sound/machines/scanner/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) - return - for(var/obj/item/part as anything in get_parts()) - if(part.loc != src) - balloon_alert(wearer, "parts extended!") - playsound(src, 'sound/machines/scanner/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) - return - if(!wearer.incapacitated) - var/atom/movable/screen/inventory/hand/ui_hand = over_object - if(wearer.putItemFromInventoryInHandIfPossible(src, ui_hand.held_index)) - add_fingerprint(user) - /obj/item/mod/control/wrench_act(mob/living/user, obj/item/wrench) if(seconds_electrified && get_charge() && shock(user)) return ITEM_INTERACT_BLOCKING diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm index a33ae21f9fd..2ae9e794b57 100644 --- a/code/modules/modular_computers/computers/item/laptop.dm +++ b/code/modules/modular_computers/computers/item/laptop.dm @@ -29,6 +29,7 @@ if(start_open && !screen_on) toggle_open() RegisterSignal(src, COMSIG_SPEED_POTION_APPLIED, PROC_REF(on_speed_potioned)) + AddElement(/datum/element/drag_pickup) /obj/item/modular_computer/laptop/examine(mob/user) . = ..() @@ -76,16 +77,6 @@ try_toggle_open(usr) -/obj/item/modular_computer/laptop/mouse_drop_dragged(atom/over_object, mob/user, src_location, over_location, params) - if(over_object == user || over_object == src) - try_toggle_open(user) - return - if(istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/H = over_object - if(!isturf(loc)) - return - user.put_in_hand(src, H.held_index) - /obj/item/modular_computer/laptop/proc/try_toggle_open(mob/living/user) if(issilicon(user)) return diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 71471f4bf1f..27301f09448 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -26,6 +26,7 @@ stored_blade = new /obj/item/hatchet/cutterblade(src) register_context() update_appearance() + AddElement(/datum/element/drag_pickup) /obj/item/papercutter/Destroy(force) if(!isnull(stored_paper)) @@ -180,15 +181,6 @@ new /obj/item/paper/paperslip(get_turf(src)) update_appearance() -/obj/item/papercutter/mouse_drop_dragged(atom/over_object, mob/user) - if(over_object == user) - user.put_in_hands(src) - - else if(istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/target_hand = over_object - user.putItemFromInventoryInHandIfPossible(src, target_hand.held_index) - add_fingerprint(user) - /obj/item/paper/paperslip name = "paper slip" desc = "A little slip of paper left over after a larger piece was cut. Whoa." diff --git a/code/modules/projectiles/guns/energy/laser_gatling.dm b/code/modules/projectiles/guns/energy/laser_gatling.dm index 670f0b0c370..c9b4455919a 100644 --- a/code/modules/projectiles/guns/energy/laser_gatling.dm +++ b/code/modules/projectiles/guns/energy/laser_gatling.dm @@ -24,6 +24,7 @@ gun = new(src) battery = new(src) START_PROCESSING(SSobj, src) + AddElement(/datum/element/drag_pickup) /obj/item/minigunpack/Destroy() if(!QDELETED(gun)) @@ -64,15 +65,6 @@ if(armed) user.dropItemToGround(gun, TRUE) -/obj/item/minigunpack/mouse_drop_dragged(atom/over_object, mob/user) - if(armed) - return - - if(iscarbon(user)) - if(istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/H = over_object - user.putItemFromInventoryInHandIfPossible(src, H.held_index) - /obj/item/minigunpack/update_icon_state() icon_state = armed ? "notholstered" : "holstered" return ..() diff --git a/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm b/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm index 9ea2603cdf6..e360c24f270 100644 --- a/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm +++ b/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm @@ -22,8 +22,8 @@ /obj/item/storage/portable_chem_mixer/Initialize(mapload) . = ..() - register_context() + AddElement(/datum/element/drag_pickup) /obj/item/storage/portable_chem_mixer/Destroy() dispensable_reagents.Cut() @@ -239,13 +239,6 @@ update_appearance() return TRUE -/obj/item/storage/portable_chem_mixer/mouse_drop_dragged(atom/over_object) - if(ismob(loc)) - var/mob/M = loc - if(istype(over_object, /atom/movable/screen/inventory/hand)) - var/atom/movable/screen/inventory/hand/H = over_object - M.putItemFromInventoryInHandIfPossible(src, H.held_index) - /obj/item/storage/portable_chem_mixer/click_alt(mob/living/user) if(!atom_storage.locked) balloon_alert(user, "lock first to use alt eject!") diff --git a/code/modules/research/xenobiology/crossbreeding/_clothing.dm b/code/modules/research/xenobiology/crossbreeding/_clothing.dm index 91f13560f2f..bd91fa7f9e2 100644 --- a/code/modules/research/xenobiology/crossbreeding/_clothing.dm +++ b/code/modules/research/xenobiology/crossbreeding/_clothing.dm @@ -113,22 +113,10 @@ Slimecrossing Armor throw_speed = 1 throw_range = 3 -/obj/item/clothing/head/peaceflower/proc/at_peace_check(mob/user) - if(iscarbon(user)) - var/mob/living/carbon/carbon_user = user - if(src == carbon_user.head) - to_chat(user, span_warning("You feel at peace. Why would you want anything else?")) - return TRUE - return FALSE - -/obj/item/clothing/head/peaceflower/attack_hand(mob/user, list/modifiers) - if(at_peace_check(user)) - return - return ..() - -/obj/item/clothing/head/peaceflower/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params) - if(at_peace_check(user)) - return +/obj/item/clothing/head/peaceflower/can_mob_unequip(mob/user) + if(user.get_item_by_slot(slot_flags) == src) + to_chat(user, span_warning("You feel at peace. Why would you want anything else?")) + return FALSE return ..() /obj/item/clothing/suit/armor/heavy/adamantine diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index ba1a26b6883..1d387ffa057 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -322,6 +322,7 @@ #include "trauma_granting.dm" #include "turf_icons.dm" #include "tutorial_sanity.dm" +#include "unequip_defib.dm" #include "unit_test.dm" #include "verify_config_tags.dm" #include "verify_emoji_names.dm" diff --git a/code/modules/unit_tests/unequip_defib.dm b/code/modules/unit_tests/unequip_defib.dm new file mode 100644 index 00000000000..e2db399f2de --- /dev/null +++ b/code/modules/unit_tests/unequip_defib.dm @@ -0,0 +1,19 @@ +/// Test you can mouse-drop a defib off your back to unequip it +/datum/unit_test/unequip_defib + +/datum/unit_test/unequip_defib/Run() + var/mob/living/carbon/human/consistent/dummy = EASY_ALLOCATE() + dummy.mock_client = new() + dummy.set_hud_used(new dummy.hud_type(dummy)) + var/obj/item/defibrillator/defib = EASY_ALLOCATE() + dummy.equip_to_slot(defib, ITEM_SLOT_BACK) + + var/old_usr = usr + + usr = dummy // mouse drop still uses usr + + defib.MouseDrop(dummy.hud_used.hand_slots["1"]) + if(!dummy.is_holding(defib)) + TEST_FAIL("The dummy failed to remove the defib from their back via mouse drop.") + + usr = old_usr