From 96b19c91ef17a77e925f8e677776f20db5a773df Mon Sep 17 00:00:00 2001 From: Alan Date: Sun, 17 May 2026 14:42:32 -0400 Subject: [PATCH] Migrate clipboard and photography to the new attack chain. (#31993) * Migrate clipboard to the new attack chain. * Migrate photos and held cameras to the new attack chain. * Fix spooky ghosts not showing up in photos. - Change image layers to their proper defines (GHOST_LAYER, MOB_LAYER) - Fix atom layer comparison to not compare planes of non-atoms * Apply suggestions from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * Fingerprints galore. --------- Signed-off-by: Alan Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> --- code/__HELPERS/cmp.dm | 4 +- code/modules/paperwork/clipboard.dm | 55 +++++++++++++++++---------- code/modules/paperwork/photography.dm | 53 +++++++++++++++++--------- 3 files changed, 71 insertions(+), 41 deletions(-) diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 300ff9e681a..a041196c65a 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -49,8 +49,8 @@ if(!.) . = B.qdels - A.qdels -/proc/cmp_atom_layer_asc(atom/A,atom/B) - if(A.plane != B.plane) +/proc/cmp_atom_layer_asc(atom/A, atom/B) + if(!istype(A) && !istype(B) && A.plane != B.plane) return A.plane - B.plane else return A.layer - B.layer diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index d649fd7900a..5472f8c91d2 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -15,6 +15,7 @@ GLOBAL_VAR(station_report) // Variable to save the station report var/obj/item/toppaper slot_flags = ITEM_SLOT_BELT resistance_flags = FLAMMABLE + new_attack_chain = TRUE /obj/item/clipboard/Initialize(mapload) . = ..() @@ -26,6 +27,7 @@ GLOBAL_VAR(station_report) // Variable to save the station report penPlacement(user, user.get_active_hand(), TRUE) else removePen(user) + return . = ..() @@ -56,6 +58,7 @@ GLOBAL_VAR(station_report) // Variable to save the station report to_chat(user, SPAN_NOTICE("You slide [P] into [src].")) user.transfer_item_to(P, src) containedpen = P + add_fingerprint(user) else if(!containedpen) to_chat(user, SPAN_WARNING("There isn't a pen in [src] for you to remove!")) @@ -63,6 +66,7 @@ GLOBAL_VAR(station_report) // Variable to save the station report to_chat(user, SPAN_NOTICE("You remove [containedpen] from [src].")) user.put_in_hands(containedpen) containedpen = null + add_fingerprint(user) update_icon() /obj/item/clipboard/proc/showClipboard(mob/user) //Show them what's on the clipboard @@ -95,30 +99,39 @@ GLOBAL_VAR(station_report) // Variable to save the station report break . += "clipboard_over" -/obj/item/clipboard/attackby__legacy__attackchain(obj/item/W, mob/user) - if(isPaperwork(W)) //If it's a photo, paper bundle, or piece of paper, place it on the clipboard. - user.unequip(W) - W.forceMove(src) - to_chat(user, SPAN_NOTICE("You clip [W] onto [src].")) +/obj/item/clipboard/item_interaction(mob/user, obj/item/used, list/modifiers) + if(isPaperwork(used)) //If it's a photo, paper bundle, or piece of paper, place it on the clipboard. + user.unequip(used) + used.forceMove(src) + to_chat(user, SPAN_NOTICE("You clip [used] onto [src].")) playsound(loc, "pageturn", 50, 1) - if(isPaperwork(W) == PAPERWORK) - toppaper = W + if(isPaperwork(used) == PAPERWORK) + toppaper = used update_icon() - else if(is_pen(W)) - if(!toppaper) //If there's no paper we can write on, just stick the pen into the clipboard - penPlacement(user, W, TRUE) - return - if(!Adjacent(user) || user.incapacitated()) - return - toppaper.attackby__legacy__attackchain(W, user) - else if(istype(W, /obj/item/stamp) && toppaper) //We can stamp the topmost piece of paper - toppaper.attackby__legacy__attackchain(W, user) - update_icon() - else - return ..() + add_fingerprint(user) + return ITEM_INTERACT_COMPLETE -/obj/item/clipboard/attack_self__legacy__attackchain(mob/user) + if(is_pen(used)) + if(!toppaper) //If there's no paper we can write on, just stick the pen into the clipboard + penPlacement(user, used, TRUE) + return ITEM_INTERACT_COMPLETE + toppaper.item_interaction(user, used, modifiers) + add_fingerprint(user) + return ITEM_INTERACT_COMPLETE + + if(istype(used, /obj/item/stamp) && toppaper) // We can stamp the topmost piece of paper. + toppaper.item_interaction(user, used, modifiers) + update_icon() + add_fingerprint(user) + return ITEM_INTERACT_COMPLETE + return ..() + +/obj/item/clipboard/activate_self(mob/user) + if(!user) + return ..() showClipboard(user) + add_fingerprint(user) + return ITEM_INTERACT_COMPLETE /obj/item/clipboard/Topic(href, href_list) ..() @@ -143,7 +156,7 @@ GLOBAL_VAR(station_report) // Variable to save the station report if(!isPaperwork(P)) return if(is_pen(I) && isPaperwork(P) != PHOTO) //Because you can't write on photos that aren't in your hand - P.attackby__legacy__attackchain(I, usr) + P.item_interaction(usr, I) else if(isPaperwork(P) == PAPERWORK) //Why can't these be subtypes of paper P.examine(usr) else if(isPaperwork(P) == PHOTO) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index 04578fed84f..fc8ac102023 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -34,38 +34,43 @@ var/photo_size = 3 var/max_length = 64 scatter_distance = 8 + new_attack_chain = TRUE -/obj/item/photo/attack_self__legacy__attackchain(mob/user as mob) +/obj/item/photo/activate_self(mob/user) + if(!user) + return ..() user.examinate(src) + return ITEM_INTERACT_COMPLETE -/obj/item/photo/attackby__legacy__attackchain(obj/item/P as obj, mob/user as mob, params) - if(is_pen(P) || istype(P, /obj/item/toy/crayon)) +/obj/item/photo/item_interaction(mob/user, obj/item/used, params) + if(is_pen(used) || istype(used, /obj/item/toy/crayon)) var/txt = tgui_input_text(user, "What would you like to write on the back?", "Photo Writing") if(!txt) - return + return ITEM_INTERACT_COMPLETE txt = copytext(txt, 1, max_length) if(loc == user && user.stat == CONSCIOUS) scribble = txt - else if(P.get_heat()) - burnphoto(P, user) - ..() + add_fingerprint(user) + else if(used.get_heat()) + burnphoto(used, user) + return ..() -/obj/item/photo/proc/burnphoto(obj/item/P, mob/user) +/obj/item/photo/proc/burnphoto(obj/item/used, mob/user) if(user.restrained()) return var/class = "warning" - if(istype(P, /obj/item/lighter/zippo)) + if(istype(used, /obj/item/lighter/zippo)) class = "rose" - user.visible_message("[user] holds [P] up to [src], it looks like [user.p_theyre()] trying to burn it!", \ - "You hold [P] up to [src], burning it slowly.") + user.visible_message("[user] holds [used] up to [src], it looks like [user.p_theyre()] trying to burn it!", \ + "You hold [used] up to [src], burning it slowly.") if(!do_after(user, 5 SECONDS, target = src)) return - if(user.get_active_hand() != P || !P.get_heat()) - to_chat(user, SPAN_WARNING("You must hold [P] steady to burn [src].")) + if(user.get_active_hand() != used || !used.get_heat()) + to_chat(user, SPAN_WARNING("You must hold [used] steady to burn [src].")) return user.visible_message("[user] burns right through [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ @@ -247,6 +252,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor if(nsize) size = nsize to_chat(user, SPAN_NOTICE("Camera will now take [size]x[size] photos.")) + add_fingerprint(user) /obj/item/camera/pre_attack(atom/target, mob/living/user, params) if(..() || ismob(target)) @@ -263,6 +269,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor else icon_state = icon_off to_chat(user, "You switch the camera [on ? "on" : "off"].") + add_fingerprint(user) /obj/item/camera/item_interaction(mob/living/user, obj/item/used, list/modifiers) if(istype(used, /obj/item/camera_film)) @@ -273,6 +280,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor user.drop_item() qdel(used) pictures_left = pictures_max + add_fingerprint(user) return ITEM_INTERACT_COMPLETE return ..() @@ -304,9 +312,9 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor if(O.orbiting_uid) continue if(user.mind && !(user.mind.assigned_role == "Chaplain")) - atoms.Add(image('icons/mob/mob.dmi', O.loc, pick(GLOB.SpookyGhosts), 4, SOUTH)) + atoms.Add(image('icons/mob/mob.dmi', O.loc, pick(GLOB.SpookyGhosts), GHOST_LAYER, SOUTH)) else - atoms.Add(image('icons/mob/mob.dmi', O.loc, "ghost", 4, SOUTH)) + atoms.Add(image('icons/mob/mob.dmi', O.loc, "ghost", GHOST_LAYER, SOUTH)) else//its not a ghost continue else//not invisable, not a spookyghost add it. @@ -314,7 +322,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor if(user.viewing_alternate_appearances && length(user.viewing_alternate_appearances) && ishuman(A) && A.alternate_appearances && length(A.alternate_appearances)) //This whole thing and the stuff below just checks if the atom is a Solid Snake cosplayer. for(var/datum/alternate_appearance/alt_appearance in user.viewing_alternate_appearances) if(alt_appearance.owner == A) //If it turns out they are, don't blow their cover. That'd be rude. - atoms.Add(image(alt_appearance.img, A.loc, layer = 4, dir = A.dir)) //Render their disguise. + atoms.Add(image(alt_appearance.img, A.loc, layer = MOB_LAYER, dir = A.dir)) //Render their disguise. atoms.Remove(A) //Don't blow their cover. disguised = 1 continue @@ -429,6 +437,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor handle_haunt(user) addtimer(CALLBACK(src, PROC_REF(reset_cooldown)), 6.4 SECONDS) // fucking magic numbers + add_fingerprint(user) return TRUE /obj/item/camera/proc/reset_cooldown() @@ -556,6 +565,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor on = FALSE on_cooldown = TRUE addtimer(CALLBACK(src, PROC_REF(reset_cooldown)), 6.4 SECONDS) // magic numbers here too + add_fingerprint(user) return TRUE /obj/item/camera/digital/captureimage(atom/target, mob/user) @@ -596,6 +606,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor if(picture) printpicture(user, picture) pictures_left -- + add_fingerprint(user) /obj/item/camera/digital/CtrlShiftClick(mob/user) if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user)) @@ -608,6 +619,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor picture = tgui_input_list(user, "Select image to delete", "Delete image", saved_pictures) if(picture) saved_pictures -= picture + add_fingerprint(user) /************** *video camera * @@ -625,6 +637,7 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor var/icon_on = "videocam_on" var/icon_off = "videocam" var/canhear_range = 7 + new_attack_chain = TRUE COOLDOWN_DECLARE(video_cooldown) @@ -660,11 +673,15 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor QDEL_NULL(camera) visible_message(SPAN_NOTICE("The video camera turns off.")) -/obj/item/videocam/attack_self__legacy__attackchain(mob/user) +/obj/item/videocam/activate_self(mob/user) + if(!user) + return ..() + add_fingerprint(user) if(!COOLDOWN_FINISHED(src, video_cooldown)) to_chat(user, SPAN_WARNING("[src] is overheating, give it some time.")) - return + return ITEM_INTERACT_COMPLETE camera_state(user) + return ITEM_INTERACT_COMPLETE /obj/item/videocam/examine(mob/user) . = ..()