diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 33f0635015..474b2d3b25 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -463,11 +463,11 @@ its easier to just keep the beam vertical. //spawn(0) //if(I) //It's possible that it could be deleted in the meantime. var/obj/O = I - O.show_message( message, 1, blind_message, 2) + O.show_message(message, 1, blind_message, 2) else if(ismob(I)) var/mob/M = I if(M.see_invisible >= invisibility) // Cannot view the invisible - M.show_message( message, 1, blind_message, 2) + M.show_message(message, 1, blind_message, 2) else if (blind_message) M.show_message(blind_message, 2) @@ -488,7 +488,24 @@ its easier to just keep the beam vertical. spawn(0) if(I) //It's possible that it could be deleted in the meantime. var/obj/O = I - O.show_message( message, 2, deaf_message, 1) + O.show_message(message, 2, deaf_message, 1) else if(ismob(I)) var/mob/M = I - M.show_message( message, 2, deaf_message, 1) + M.show_message(message, 2, deaf_message, 1) + +/atom/movable/proc/dropInto(var/atom/destination) + while(istype(destination)) + var/atom/drop_destination = destination.onDropInto(src) + if(!istype(drop_destination) || drop_destination == destination) + return forceMove(destination) + destination = drop_destination + return forceMove(null) + +/atom/proc/onDropInto(var/atom/movable/AM) + return // If onDropInto returns null, then dropInto will forceMove AM into us. + +/atom/movable/onDropInto(var/atom/movable/AM) + return loc // If onDropInto returns something, then dropInto will attempt to drop AM there. + +/atom/proc/InsertedContents() + return contents diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e45be4bb6a..d164485f38 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -63,13 +63,35 @@ return /atom/movable/proc/forceMove(atom/destination) + if(loc == destination) + return 0 + var/is_origin_turf = isturf(loc) + var/is_destination_turf = isturf(destination) + // It is a new area if: + // Both the origin and destination are turfs with different areas. + // When either origin or destination is a turf and the other is not. + var/is_new_area = (is_origin_turf ^ is_destination_turf) || (is_origin_turf && is_destination_turf && loc.loc != destination.loc) + + var/atom/origin = loc + loc = destination + + if(origin) + origin.Exited(src, destination) + if(is_origin_turf) + for(var/atom/movable/AM in origin) + AM.Uncrossed(src) + if(is_new_area && is_origin_turf) + origin.loc.Exited(src, destination) + if(destination) - if(loc) - loc.Exited(src) - loc = destination - loc.Entered(src) - return 1 - return 0 + destination.Entered(src, origin) + if(is_destination_turf) // If we're entering a turf, cross all movable atoms + for(var/atom/movable/AM in loc) + if(AM != src) + AM.Crossed(src) + if(is_new_area && is_destination_turf) + destination.loc.Entered(src, origin) + return 1 //called when src is thrown into hit_atom /atom/movable/proc/throw_impact(atom/hit_atom, var/speed) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index d88e8c5372..107ea11520 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -394,3 +394,6 @@ var/shake_dir = pick(-1, 1) animate(src, transform=turn(matrix(), 8*shake_dir), pixel_x=init_px + 2*shake_dir, time=1) animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING) + +/obj/structure/closet/onDropInto(var/atom/movable/AM) + return diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm index 3fcf07713b..42bd4b709b 100644 --- a/code/modules/games/cards.dm +++ b/code/modules/games/cards.dm @@ -146,7 +146,7 @@ for(var/datum/playingcard/P in cards) H.cards += P H.concealed = src.concealed - user.drop_from_inventory(src,user.loc) + user.drop_from_inventory(src) qdel(src) H.update_icon() return diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm index d608bb0988..5e4bfeb24a 100644 --- a/code/modules/mob/holder.dm +++ b/code/modules/mob/holder.dm @@ -50,6 +50,11 @@ var/list/holder_mob_icon_cache = list() continue M.forceMove(get_turf(src)) +/obj/item/weapon/holder/onDropInto(var/atom/movable/AM) + if(ismob(loc)) // Bypass our holding mob and drop directly to its loc + return loc.loc + return ..() + /obj/item/weapon/holder/GetID() for(var/mob/M in contents) var/obj/item/I = M.GetIdCard() diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index ad71cebe1f..1c6e2436d4 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -126,16 +126,12 @@ var/list/slot_equipment_priority = list( \ // Removes an item from inventory and places it in the target atom. // If canremove or other conditions need to be checked then use unEquip instead. -/mob/proc/drop_from_inventory(var/obj/item/W, var/atom/Target = null) +/mob/proc/drop_from_inventory(var/obj/item/W, var/atom/target = null) if(W) - if(!Target) - Target = loc - - remove_from_mob(W) - if(!(W && W.loc)) return 1 // self destroying objects (tk, grabs) - - W.forceMove(Target) + remove_from_mob(W, target) + if(!(W && W.loc)) + return 1 // self destroying objects (tk, grabs) update_icons() return 1 return 0 @@ -194,7 +190,9 @@ var/list/slot_equipment_priority = list( \ //Attemps to remove an object on a mob. -/mob/proc/remove_from_mob(var/obj/O) +/mob/proc/remove_from_mob(var/obj/O, var/atom/target) + if(!O) // Nothing to remove, so we succeed. + return 1 src.u_equip(O) if (src.client) src.client.screen -= O @@ -202,7 +200,10 @@ var/list/slot_equipment_priority = list( \ O.screen_loc = null if(istype(O, /obj/item)) var/obj/item/I = O - I.forceMove(src.loc) + if(target) + I.forceMove(target) + else + I.dropInto(loc) I.dropped(src) return 1