diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 315efe48778..d0f64262549 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -482,8 +482,26 @@ return TRUE +/atom/movable/screen/storage/cell + +/atom/movable/screen/storage/cell/mouse_drop_receive(atom/target, mob/living/user, params) + var/datum/storage/storage = master_ref?.resolve() + + if (isnull(storage) || !istype(user) || storage != user.active_storage) + return + + if (!user.can_perform_action(storage.parent, FORBID_TELEKINESIS_REACH)) + return + + if (target.loc != storage.real_location) + return + + /// Due to items in storage ignoring transparency for click hitboxes, this only can happen if we drag onto a free cell - aka after all current contents + storage.real_location.contents -= target + storage.real_location.contents += target + storage.refresh_views() + /atom/movable/screen/storage/corner - name = "storage" icon_state = "storage_corner_topleft" /atom/movable/screen/storage/corner/top_right diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index a01bb21a451..7cdb9d40615 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -449,11 +449,38 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) SEND_SIGNAL(parent, COMSIG_ATOM_STORED_ITEM, to_insert, user, force) SEND_SIGNAL(src, COMSIG_STORAGE_STORED_ITEM, to_insert, user, force) + RegisterSignal(to_insert, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(mousedrop_receive)) to_insert.forceMove(real_location) item_insertion_feedback(user, to_insert, override) parent.update_appearance() return TRUE +/// Since items inside storages ignore transparency for QOL reasons, we're tracking when things are dropped onto them instead of our UI elements +/datum/storage/proc/mousedrop_receive(atom/dropped_onto, atom/movable/target, mob/user, params) + SIGNAL_HANDLER + + if (src != user.active_storage) + return + + if (!user.can_perform_action(parent, FORBID_TELEKINESIS_REACH)) + return + + if (target.loc != real_location) // what even + UnregisterSignal(target, COMSIG_MOUSEDROPPED_ONTO) + return + + if(numerical_stacking) + return + + var/drop_index = real_location.contents.Find(dropped_onto) + real_location.contents -= target + // Use an empty list if we're dropping onto the last item + var/list/to_move = real_location.contents.len >= drop_index ? real_location.contents.Copy(drop_index) : list() + real_location.contents -= to_move + real_location.contents += target + real_location.contents += to_move + refresh_views() + /** * Inserts every item in a given list, with a progress bar * @@ -544,6 +571,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) refresh_views() parent.update_appearance() + UnregisterSignal(thing, COMSIG_MOUSEDROPPED_ONTO) SEND_SIGNAL(parent, COMSIG_ATOM_REMOVED_ITEM, thing, remove_to_loc, silent) SEND_SIGNAL(src, COMSIG_STORAGE_REMOVED_ITEM, thing, remove_to_loc, silent) return TRUE @@ -719,7 +747,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) parent.add_fingerprint(user) return COMPONENT_CANCEL_MOUSEDROP_ONTO - else if(ismob(over_object)) + if(ismob(over_object)) if(over_object != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) return @@ -727,13 +755,24 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) INVOKE_ASYNC(src, PROC_REF(open_storage), user) return COMPONENT_CANCEL_MOUSEDROP_ONTO - else if(!istype(over_object, /atom/movable/screen)) - if(!user.can_perform_action(over_object, FORBID_TELEKINESIS_REACH)) - return + if(istype(over_object, /atom/movable/screen)) + return - parent.add_fingerprint(user) - INVOKE_ASYNC(src, PROC_REF(dump_content_at), over_object, user) - return COMPONENT_CANCEL_MOUSEDROP_ONTO + if(!user.can_perform_action(over_object, FORBID_TELEKINESIS_REACH)) + return + + parent.add_fingerprint(user) + + var/atom/dump_loc = over_object.get_dumping_location() + if(isnull(dump_loc)) + return + + /// 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 + + INVOKE_ASYNC(src, PROC_REF(dump_content_at), over_object, dump_loc, user) + return COMPONENT_CANCEL_MOUSEDROP_ONTO /** * Dumps all of our contents at a specific location. @@ -741,7 +780,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) * @param atom/dest_object where to dump to * @param mob/user the user who is dumping the contents */ -/datum/storage/proc/dump_content_at(atom/dest_object, mob/user) +/datum/storage/proc/dump_content_at(atom/dest_object, dump_loc, mob/user) if(locked) user.balloon_alert(user, "closed!") return @@ -764,10 +803,6 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) SEND_SIGNAL(src, COMSIG_STORAGE_DUMP_POST_TRANSFER, dest_object, user) return - var/atom/dump_loc = dest_object.get_dumping_location() - if(isnull(dump_loc)) - return - // Storage to loc transfer requires a do_after to_chat(user, span_notice("You start dumping out the contents of [parent] onto [dest_object]...")) if(!do_after(user, 2 SECONDS, target = dest_object)) diff --git a/code/datums/storage/storage_interface.dm b/code/datums/storage/storage_interface.dm index cd28b9eb3f7..c0cab0dd795 100644 --- a/code/datums/storage/storage_interface.dm +++ b/code/datums/storage/storage_interface.dm @@ -2,7 +2,7 @@ /datum/storage_interface /// UI elements for this theme var/atom/movable/screen/close/closer - var/atom/movable/screen/storage/cells + var/atom/movable/screen/storage/cell/cells var/atom/movable/screen/storage/corner/corner_top_left var/atom/movable/screen/storage/corner/top_right/corner_top_right var/atom/movable/screen/storage/corner/bottom_left/corner_bottom_left