From 7fd97ede747714d4d277af25ef05da1d079c2f8b Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Sat, 14 Jun 2025 00:13:48 +0200 Subject: [PATCH] Refactors pdapainter `attackby` into `item_interaction`. (#91548) ## About The Pull Request This mostly just refactors the pdapainter `attackby(...)` into our modern item interaction system, and adds screentips for such. On the side it does a minor amount of cleanup/improvements. Notable changes include: - It felt odd that almost all id cards could be put in here, despite them not really being traditionally changeable. Like, the cargo departmental budget card probably shouldn't be able to get a trim put on it, and neither should pretty much all non-advanced IDs with preset trims and no visual nor explained ability to change them. Hence, this limits it to advanced cards. - I didn't remove the `to_chat(...)` upon id insertion failure, as I felt the balloon alert wouldn't actually communicate the problem sufficiently, but leaving _just_ the `to_chat(...)` felt like it didn't give enough direct feedback on click. Hence, it uses both. ## Why It's Good For The Game Less jank, more screentips, more feedback, less use of `attackby(...)` when we shouldn't. ## Changelog :cl: refactor: Refactored tablet/ID painter item interactions. Please report any issues. fix: You can no longer circumvent the block on inserting chameleon IDs into tablet/ID painters by inserting them via the UI. fix: You can no longer insert non-advanced IDs into the tablet/ID painter and change their trims. sound: Inserting IDs into tablet/ID painters is no longer silent. qol: You can repair tablet/ID painters when they're damaged, instead of just when they're broken. qol: Improved feedback for tablet/ID painter interactions. qol: Added screentips to tablet/ID painters. /:cl: --------- Co-authored-by: san7890 --- code/game/machinery/PDApainter.dm | 133 ++++++++++++++------------- code/game/objects/items/cards_ids.dm | 4 + 2 files changed, 74 insertions(+), 63 deletions(-) diff --git a/code/game/machinery/PDApainter.dm b/code/game/machinery/PDApainter.dm index 97853c505fa..a52be682b34 100644 --- a/code/game/machinery/PDApainter.dm +++ b/code/game/machinery/PDApainter.dm @@ -44,6 +44,7 @@ /obj/machinery/pdapainter/Initialize(mapload) . = ..() + register_context() if(!target_dept) pda_types = SSid_access.station_pda_templates.Copy() @@ -103,53 +104,59 @@ stored_id_card = null update_appearance(UPDATE_ICON) +/obj/machinery/pdapainter/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_LMB] = "Open UI" + if(stored_pda) + context[SCREENTIP_CONTEXT_RMB] = "Eject PDA" + else if(stored_id_card) + context[SCREENTIP_CONTEXT_RMB] = "Eject ID" + return CONTEXTUAL_SCREENTIP_SET + + if(istype(held_item, /obj/item/modular_computer/pda)) + context[SCREENTIP_CONTEXT_LMB] = "[stored_pda ? "Swap" : "Insert"] PDA" + return CONTEXTUAL_SCREENTIP_SET + if(isidcard(held_item)) + context[SCREENTIP_CONTEXT_LMB] = "[stored_id_card ? "Swap" : "Insert"] ID" + return CONTEXTUAL_SCREENTIP_SET + + switch(held_item.tool_behaviour) + if(TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Una" : "A"]nchor" + return CONTEXTUAL_SCREENTIP_SET + if(TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "Repair" + return CONTEXTUAL_SCREENTIP_SET + return NONE + /obj/machinery/pdapainter/wrench_act(mob/living/user, obj/item/tool) . = ..() if(default_unfasten_wrench(user, tool)) power_change() return ITEM_INTERACT_SUCCESS -/obj/machinery/pdapainter/attackby(obj/item/O, mob/living/user, list/modifiers, list/attack_modifiers) - if(machine_stat & BROKEN) - if(O.tool_behaviour == TOOL_WELDER && !user.combat_mode) - if(!O.tool_start_check(user, amount=1)) - return - user.visible_message(span_notice("[user] is repairing [src]."), \ - span_notice("You begin repairing [src]..."), \ - span_hear("You hear welding.")) - if(O.use_tool(src, user, 40, volume=50)) - if(!(machine_stat & BROKEN)) - return - to_chat(user, span_notice("You repair [src].")) - set_machine_stat(machine_stat & ~BROKEN) - atom_integrity = max_integrity - update_appearance(UPDATE_ICON) - return - return ..() +/obj/machinery/pdapainter/welder_act(mob/living/user, obj/item/tool) + if(!(machine_stat & BROKEN) && (atom_integrity >= max_integrity)) + balloon_alert(user, "isn't broken!") + return ITEM_INTERACT_BLOCKING + if(!tool.tool_start_check(user, amount = 1)) + balloon_alert(user, "not enough fuel!") + return ITEM_INTERACT_BLOCKING - // Chameleon checks first so they can exit the logic early if they're detected. - if(istype(O, /obj/item/card/id/advanced/chameleon)) - to_chat(user, span_warning("The machine rejects your [O]. This ID card does not appear to be compatible with the PDA Painter.")) - return + if(!tool.use_tool(src, user, 40, volume = 50)) + return ITEM_INTERACT_BLOCKING - if(istype(O, /obj/item/modular_computer/pda)) - insert_pda(O, user) - return + set_machine_stat(machine_stat & ~BROKEN) + atom_integrity = max_integrity + balloon_alert(user, "repaired") + return ITEM_INTERACT_SUCCESS - if(isidcard(O)) - if(stored_id_card) - to_chat(user, span_warning("There is already an ID card inside!")) - return - - if(!user.transferItemToLoc(O, src)) - return - - stored_id_card = O - O.add_fingerprint(user) - update_appearance(UPDATE_ICON) - return - - return ..() +/obj/machinery/pdapainter/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(istype(tool, /obj/item/modular_computer/pda)) + return insert_pda(tool, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + if(isidcard(tool)) + return insert_id_card(tool, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + return NONE /obj/machinery/pdapainter/attack_hand_secondary(mob/user, list/modifiers) . = ..() @@ -168,23 +175,21 @@ * Returns TRUE on success, FALSE otherwise. * Arguments: * * new_pda - The PDA to insert. - * * user - The user to try and eject the PDA into the hands of. + * * user - The user attempting to insert the PDA. */ /obj/machinery/pdapainter/proc/insert_pda(obj/item/modular_computer/pda/new_pda, mob/living/user) - if(!istype(new_pda)) - return FALSE - - if(user && !user.transferItemToLoc(new_pda, src)) + if(user && !user.transferItemToLoc(new_pda, src, silent = FALSE)) return FALSE else new_pda.forceMove(src) if(stored_pda) eject_pda(user) + balloon_alert(user, "swapped") stored_pda = new_pda new_pda.add_fingerprint(user) - update_icon() + update_appearance(UPDATE_ICON) return TRUE /** @@ -194,14 +199,13 @@ * * user - The user to try and eject the PDA into the hands of. */ /obj/machinery/pdapainter/proc/eject_pda(mob/living/user) - if(stored_pda) - if(user && !issilicon(user) && in_range(src, user)) - user.put_in_hands(stored_pda) - else - stored_pda.forceMove(drop_location()) + if(isnull(stored_pda)) + return - stored_pda = null - update_icon() + try_put_in_hand(stored_pda, user) + + stored_pda = null + update_appearance(UPDATE_ICON) /** * Insert an ID card into the machine. @@ -210,23 +214,27 @@ * Returns TRUE on success, FALSE otherwise. * Arguments: * * new_id_card - The ID card to insert. - * * user - The user to try and eject the PDA into the hands of. + * * user - The user attempting to insert the ID. */ /obj/machinery/pdapainter/proc/insert_id_card(obj/item/card/id/new_id_card, mob/living/user) - if(!istype(new_id_card)) + if(!new_id_card.trim_changeable) + balloon_alert(user, "rejected!") + playsound(src, 'sound/machines/buzz/buzz-sigh.ogg', 50, TRUE) + to_chat(user, span_warning("This ID card does not appear to be compatible with the ID Painter.")) return FALSE - if(user && !user.transferItemToLoc(new_id_card, src)) + if(user && !user.transferItemToLoc(new_id_card, src, silent = FALSE)) return FALSE else new_id_card.forceMove(src) if(stored_id_card) eject_id_card(user) + balloon_alert(user, "swapped") stored_id_card = new_id_card new_id_card.add_fingerprint(user) - update_icon() + update_appearance(UPDATE_ICON) return TRUE /** @@ -236,15 +244,14 @@ * * user - The user to try and eject the ID card into the hands of. */ /obj/machinery/pdapainter/proc/eject_id_card(mob/living/user) - if(stored_id_card) - GLOB.manifest.modify(stored_id_card.registered_name, stored_id_card.assignment, stored_id_card.get_trim_assignment()) - if(user && !issilicon(user) && in_range(src, user)) - user.put_in_hands(stored_id_card) - else - stored_id_card.forceMove(drop_location()) + if(isnull(stored_id_card)) + return FALSE - stored_id_card = null - update_appearance(UPDATE_ICON) + GLOB.manifest.modify(stored_id_card.registered_name, stored_id_card.assignment, stored_id_card.get_trim_assignment()) + try_put_in_hand(stored_id_card, user) + + stored_id_card = null + update_appearance(UPDATE_ICON) /obj/machinery/pdapainter/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 66f70f32fea..ae75e604a31 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -99,6 +99,8 @@ /// Trim datum associated with the card. Controls which job icon is displayed on the card and which accesses do not require wildcards. var/datum/id_trim/trim + /// Whether the trim on this card can be changed. + var/trim_changeable = FALSE /// Access levels held by this card. var/list/access = list() @@ -1101,6 +1103,7 @@ wildcard_slots = WILDCARD_LIMIT_GREY flags_1 = UNPAINTABLE_1 + trim_changeable = TRUE /// An overlay icon state for when the card is assigned to a name. Usually manifests itself as a little scribble to the right of the job icon. var/assigned_icon_state = "assigned" @@ -1651,6 +1654,7 @@ Has special magnetic properties which force it to the front of wallets." trim = /datum/id_trim/chameleon wildcard_slots = WILDCARD_LIMIT_GOLD + trim_changeable = FALSE actions_types = list(/datum/action/item_action/chameleon/change/id, /datum/action/item_action/chameleon/change/id_trim) action_slots = ALL