diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 13b9420d836..d81e68d8bc1 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -1,13 +1,25 @@ #define MAXIMUM_EMP_WIRES 3 -/proc/is_wire_tool(obj/item/I) - if(!I) - return - - if(I.tool_behaviour == TOOL_WIRECUTTER || I.tool_behaviour == TOOL_MULTITOOL) - return TRUE - if(isassembly(I)) +/** + * Is the passed item a tool that would interact with wires? + * + * Arguments: + * * tool - The item to check. + * * check_secured - If TRUE, and the item ends up being an assembly, + * we will only return TRUE if the assembly is not secured. + * "Secured" is used to indicate an assembly that may have a use outside of wire interactions, + * so we don't want to falsely identify it as a wire tool in some contexts. + */ +/proc/is_wire_tool(obj/item/tool, check_secured = FALSE) + if(!istype(tool)) + return FALSE + if(tool.tool_behaviour == TOOL_WIRECUTTER || tool.tool_behaviour == TOOL_MULTITOOL) return TRUE + if(isassembly(tool)) + var/obj/item/assembly/assembly = tool + if(!check_secured || !assembly.secured) + return TRUE + return FALSE /atom/proc/attempt_wire_interaction(mob/user) if(!wires) diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm index 00fa02caab4..5e1467e41b0 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -123,10 +123,13 @@ // Check both our's and their's assembly flags to see if either should not duplicate // If so, and we match types, don't create a holder - block it if(((new_assembly.assembly_flags|assembly_flags) & ASSEMBLY_NO_DUPLICATES) && istype(new_assembly, type)) - balloon_alert(user, "can't attach another of that!") + balloon_alert(user, "can't attach another [new_assembly.name]!") return - if(new_assembly.secured || secured) - balloon_alert(user, "both devices not assembly_behavior!") + if(new_assembly.secured) + balloon_alert(user, "[new_assembly.name] is not attachable!") + return + if(secured) + balloon_alert(user, "[name] is not attachable!") return holder = new /obj/item/assembly_holder(drop_location()) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index a451166bcad..2646b465280 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -4,187 +4,208 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real /obj/item/clothing/head/chameleon/broken \ ))) -/mob/living/silicon/robot/attackby(obj/item/W, mob/living/user, params) - if(istype(W, /obj/item/stack/cable_coil) && wiresexposed) - user.changeNext_move(CLICK_CD_MELEE) - var/obj/item/stack/cable_coil/coil = W - if (getFireLoss() > 0 || getToxLoss() > 0) - if(src == user) - to_chat(user, span_notice("You start fixing yourself...")) - if(!do_after(user, 5 SECONDS, target = src)) - return - if (coil.use(1)) - adjustFireLoss(-30) - user.visible_message(span_notice("[user] fixes some of the burnt wires on [src]."), span_notice("You fix some of the burnt wires on [src].")) - else - to_chat(user, span_warning("You need more cable to repair [src]!")) - else - to_chat(user, span_warning("The wires seem fine, there's no need to fix them.")) - return - - if(istype(W, /obj/item/stock_parts/power_store/cell) && opened) // trying to put a cell inside +/mob/living/silicon/robot/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(is_wire_tool(tool, check_secured = TRUE)) if(wiresexposed) - to_chat(user, span_warning("Close the cover first!")) - else if(cell) - to_chat(user, span_warning("There is a power cell already installed!")) - else - if(!user.transferItemToLoc(W, src)) - return - cell = W - to_chat(user, span_notice("You insert the power cell.")) + wires.interact(user) + return ITEM_INTERACT_SUCCESS + if(user.combat_mode) + return ITEM_INTERACT_SKIP_TO_ATTACK + + balloon_alert(user, "expose the wires first!") + return ITEM_INTERACT_BLOCKING + + if(istype(tool, /obj/item/stack/cable_coil)) + if(!wiresexposed) + balloon_alert(user, "expose the wires first!") + return ITEM_INTERACT_BLOCKING + var/obj/item/stack/cable_coil/coil = tool + if (getFireLoss() <= 0) + balloon_alert(user, "wires are fine!") + return ITEM_INTERACT_BLOCKING + if(src == user) + balloon_alert(user, "repairing self...") + if(!do_after(user, 5 SECONDS, target = src)) + return ITEM_INTERACT_BLOCKING + if (!coil.use(1)) + balloon_alert(user, "not enough cable!") + return ITEM_INTERACT_BLOCKING + adjustFireLoss(-30) + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) + balloon_alert(user, "wires repaired") + user.visible_message( + span_notice("[user] fixes some of the burnt wires on [src]."), + span_notice("You fix some of the burnt wires on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + user.changeNext_move(CLICK_CD_MELEE) + return ITEM_INTERACT_SUCCESS + + if(istype(tool, /obj/item/stock_parts/power_store/cell) && opened) // trying to put a cell inside + if(wiresexposed) + balloon_alert(user, "unexpose the wires first!") + return ITEM_INTERACT_BLOCKING + if(cell) + balloon_alert(user, "already has a cell!") + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(tool, src)) + return ITEM_INTERACT_BLOCKING + cell = tool + balloon_alert(user, "cell inserted") update_icons() diag_hud_set_borgcell() - return + return ITEM_INTERACT_SUCCESS - if(is_wire_tool(W)) - if (wiresexposed) - wires.interact(user) - else - to_chat(user, span_warning("You can't reach the wiring!")) - return - - if((W.slot_flags & ITEM_SLOT_HEAD) && hat_offset != INFINITY && !user.combat_mode && !is_type_in_typecache(W, GLOB.blacklisted_borg_hats)) + if((tool.slot_flags & ITEM_SLOT_HEAD) \ + && hat_offset != INFINITY \ + && !user.combat_mode \ + && !is_type_in_typecache(tool, GLOB.blacklisted_borg_hats)) if(user == src) - to_chat(user, span_notice("You can't seem to manage to place [W] on your head by yourself!") ) - return + balloon_alert(user, "can't place on self!") + return ITEM_INTERACT_BLOCKING if(hat && HAS_TRAIT(hat, TRAIT_NODROP)) - to_chat(user, span_warning("You can't seem to remove [src]'s existing headwear!")) - return - to_chat(user, span_notice("You begin to place [W] on [src]'s head...")) - to_chat(src, span_notice("[user] is placing [W] on your head...")) - if(do_after(user, 3 SECONDS, target = src)) - if (user.temporarilyRemoveItemFromInventory(W, TRUE)) - place_on_head(W) - return + balloon_alert(user, "can't remove existing headwear!") + return ITEM_INTERACT_BLOCKING + balloon_alert(user, "placing on head...") + user.visible_message( + span_notice("[user] begins to place [tool] on [src]'s head..."), + span_notice("You begin to place [tool] on [src]'s head..."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + if(!do_after(user, 3 SECONDS, target = src)) + return ITEM_INTERACT_BLOCKING + if(hat && HAS_TRAIT(hat, TRAIT_NODROP)) + balloon_alert(user, "can't remove existing headwear!") + return ITEM_INTERACT_BLOCKING + if(!user.temporarilyRemoveItemFromInventory(tool)) + return ITEM_INTERACT_BLOCKING + balloon_alert(user, "headwear placed") + place_on_head(tool) + return ITEM_INTERACT_SUCCESS - if(istype(W, /obj/item/defibrillator) && !user.combat_mode) + if(istype(tool, /obj/item/defibrillator) && !user.combat_mode) if(!opened) - to_chat(user, span_warning("You must access the cyborg's internals!")) - return + balloon_alert(user, "chassis cover is closed!") + return ITEM_INTERACT_BLOCKING if(!istype(model, /obj/item/robot_model/medical)) - to_chat(user, span_warning("[src] does not have correct mounting points for a defibrillator!")) - return + balloon_alert(user, "wrong cyborg model!") + return ITEM_INTERACT_BLOCKING if(stat == DEAD) - to_chat(user, span_warning("This defibrillator unit will not function on a deceased cyborg!")) - return - var/obj/item/defibrillator/D = W - if(!(D.slot_flags & ITEM_SLOT_BACK)) //belt defibs need not apply - to_chat(user, span_warning("This defibrillator unit doesn't seem to fit correctly!")) - return - if(D.cell) - to_chat(user, span_warning("You cannot connect the defibrillator to the cyborg power supply with the defibrillator's cell in the way!")) - return - if(locate(/obj/item/borg/upgrade/defib) in src || locate(/obj/item/borg/upgrade/defib/backpack) in src) - to_chat(user, span_warning("[src] already has a defibrillator!")) - return - var/obj/item/borg/upgrade/defib/backpack/B = new(null, D) - apply_upgrade(B, user) - return + balloon_alert(user, "it's dead!") + return ITEM_INTERACT_BLOCKING + var/obj/item/defibrillator/defib = tool + if(!(defib.slot_flags & ITEM_SLOT_BACK)) //belt defibs need not apply + balloon_alert(user, "doesn't fit!") + return ITEM_INTERACT_BLOCKING + if(defib.get_cell()) + balloon_alert(user, "remove [tool]'s cell first!") + return ITEM_INTERACT_BLOCKING + if(locate(/obj/item/borg/upgrade/defib) in src) + balloon_alert(user, "already has a defibrillator!") + return ITEM_INTERACT_BLOCKING + var/obj/item/borg/upgrade/defib/backpack/defib_upgrade = new(null, defib) + if(apply_upgrade(defib_upgrade, user)) + balloon_alert(user, "defibrillator installed") + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING - if(istype(W, /obj/item/ai_module)) - var/obj/item/ai_module/MOD = W + if(istype(tool, /obj/item/ai_module)) if(!opened) - to_chat(user, span_warning("You need access to the robot's insides to do that!")) - return + balloon_alert(user, "chassis cover is closed!") + return ITEM_INTERACT_BLOCKING if(wiresexposed) - to_chat(user, span_warning("You need to close the wire panel to do that!")) - return + balloon_alert(user, "unexpose the wires first!") + return ITEM_INTERACT_BLOCKING if(!cell) - to_chat(user, span_warning("You need to install a power cell to do that!")) - return - if(shell) //AI shells always have the laws of the AI - to_chat(user, span_warning("[src] is controlled remotely! You cannot upload new laws this way!")) - return + balloon_alert(user, "install a power cell first!") + return ITEM_INTERACT_BLOCKING + if(shell) + balloon_alert(user, "can't upload laws to a shell!") + return ITEM_INTERACT_BLOCKING if(connected_ai && lawupdate) - to_chat(user, span_warning("[src] is receiving laws remotely from a synced AI!")) - return + balloon_alert(user, "linked to an ai!") + return ITEM_INTERACT_BLOCKING if(emagged) - to_chat(user, span_warning("The law interface glitches out!")) + balloon_alert(user, "law interface glitched!") emote("buzz") - return - if(!mind) //A player mind is required for law procs to run antag checks. - to_chat(user, span_warning("[src] is entirely unresponsive!")) - return - MOD.install(laws, user) //Proc includes a success mesage so we don't need another one - return + return ITEM_INTERACT_BLOCKING + if(!mind) + balloon_alert(user, "it's unresponsive!") + return ITEM_INTERACT_BLOCKING - if(istype(W, /obj/item/encryptionkey) && opened) - if(radio)//sanityyyyyy - radio.attackby(W,user)//GTFO, you have your own procs - else - to_chat(user, span_warning("Unable to locate a radio!")) - return + balloon_alert(user, "laws uploaded") + var/obj/item/ai_module/new_laws = tool + new_laws.install(laws, user) + return ITEM_INTERACT_SUCCESS - if (W.GetID()) // trying to unlock the interface with an ID card + if(istype(tool, /obj/item/encryptionkey) && opened) + if(radio) + return radio.item_interaction(user, tool) + + balloon_alert(user, "no radio found!") + return ITEM_INTERACT_BLOCKING + + if(tool.GetID()) if(opened) - to_chat(user, span_warning("You must close the cover to swipe an ID card!")) - else - if(allowed(user)) - locked = !locked - to_chat(user, span_notice("You [ locked ? "lock" : "unlock"] [src]'s cover.")) - update_icons() - if(emagged) - to_chat(user, span_notice("The cover interface glitches out for a split second.")) - logevent("ChÃ¥vÃis cover lock has been [locked ? "engaged" : "released"]") //ChÃ¥vÃis: see above line - else - logevent("Chassis cover lock has been [locked ? "engaged" : "released"]") - else - to_chat(user, span_danger("Access denied.")) - return + balloon_alert(user, "close the chassis cover first!") + return ITEM_INTERACT_BLOCKING + if(!allowed(user)) + balloon_alert(user, "access denied!") + return ITEM_INTERACT_BLOCKING + locked = !locked + update_icons() + balloon_alert(user, "chassis cover lock [emagged ? "glitches" : "toggled"]") + logevent("[emagged ? "ChÃ¥vÃis" : "Chassis"] cover lock has been [locked ? "engaged" : "released"]") + return ITEM_INTERACT_SUCCESS - if(istype(W, /obj/item/borg/upgrade)) - var/obj/item/borg/upgrade/U = W + if(istype(tool, /obj/item/borg/upgrade)) if(!opened) - to_chat(user, span_warning("You must access the cyborg's internals!")) - return - if(!src.model && U.require_model) - to_chat(user, span_warning("The cyborg must choose a model before it can be upgraded!")) - return - if(U.locked) - to_chat(user, span_warning("The upgrade is locked and cannot be used yet!")) - return - if(!user.canUnEquip(U)) - to_chat(user, span_warning("The upgrade is stuck to you and you can't seem to let go of it!")) - return - apply_upgrade(U, user) - return + balloon_alert(user, "chassis cover is closed!") + return ITEM_INTERACT_BLOCKING + var/obj/item/borg/upgrade/upgrade = tool + if(!model && upgrade.require_model) + balloon_alert(user, "choose a model first!") + return ITEM_INTERACT_BLOCKING + if(upgrade.locked) + balloon_alert(user, "upgrade locked!") + return ITEM_INTERACT_BLOCKING + if(apply_upgrade(upgrade, user)) + balloon_alert(user, "upgrade installed") + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING - if(istype(W, /obj/item/toner)) + if(istype(tool, /obj/item/toner)) if(toner >= tonermax) - to_chat(user, span_warning("The toner level of [src] is at its highest level possible!")) - return - if(!user.temporarilyRemoveItemFromInventory(W)) - return + balloon_alert(user, "toner full!") + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(tool, src)) + return ITEM_INTERACT_BLOCKING toner = tonermax - qdel(W) - to_chat(user, span_notice("You fill the toner level of [src] to its max capacity.")) - return + qdel(tool) + balloon_alert(user, "toner filled") + return ITEM_INTERACT_SUCCESS - if(istype(W, /obj/item/flashlight)) + if(istype(tool, /obj/item/flashlight)) if(!opened) - to_chat(user, span_warning("You need to open the panel to repair the headlamp!")) - return + balloon_alert(user, "open the chassis cover first!") + return ITEM_INTERACT_BLOCKING if(lamp_functional) - to_chat(user, span_warning("The headlamp is already functional!")) - return - if(!user.temporarilyRemoveItemFromInventory(W)) - to_chat(user, span_warning("[W] seems to be stuck to your hand. You'll have to find a different light.")) - return + balloon_alert(user, "headlamp already functional!") + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(tool, src)) + return ITEM_INTERACT_BLOCKING lamp_functional = TRUE - qdel(W) - to_chat(user, span_notice("You replace the headlamp bulbs.")) - return + qdel(tool) + balloon_alert(user, "headlamp repaired") + return ITEM_INTERACT_SUCCESS - if(istype(W, /obj/item/computer_disk)) //Allows borgs to install new programs with human help + if(istype(tool, /obj/item/computer_disk)) if(!modularInterface) stack_trace("Cyborg [src] ( [type] ) was somehow missing their integrated tablet. Please make a bug report.") create_modularInterface() - var/obj/item/computer_disk/floppy = W - floppy.forceMove(modularInterface) - modularInterface.inserted_disk = floppy - return + return modularInterface.computer_disk_act(user, tool) - return ..() + return NONE #define LOW_DAMAGE_UPPER_BOUND 1/3 #define MODERATE_DAMAGE_UPPER_BOUND 2/3 @@ -254,7 +275,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real if(!cell) return cell.add_fingerprint(user) - to_chat(user, span_notice("You remove \the [cell].")) + balloon_alert(user, "cell removed") user.put_in_active_hand(cell) update_icons() diag_hud_set_borgcell() @@ -274,68 +295,82 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real /mob/living/silicon/robot/welder_act(mob/living/user, obj/item/tool) if(user.combat_mode && user != src) - return FALSE - . = TRUE + return NONE + user.changeNext_move(CLICK_CD_MELEE) if (!getBruteLoss()) - to_chat(user, span_warning("[src] is already in good condition!")) - return + balloon_alert(user, "no dents to fix!") + return ITEM_INTERACT_BLOCKING if (!tool.tool_start_check(user, amount=1, heat_required = HIGH_TEMPERATURE_REQUIRED)) //The welder has 1u of fuel consumed by its afterattack, so we don't need to worry about taking any away. - return + return ITEM_INTERACT_BLOCKING if(src == user) - to_chat(user, span_notice("You start fixing yourself...")) - if(!tool.use_tool(src, user, 50)) - return + balloon_alert(user, "repairing self...") + if(!tool.use_tool(src, user, delay = 5 SECONDS, amount = 1, volume = 50)) + return ITEM_INTERACT_BLOCKING + else + if(!tool.use_tool(src, user, delay = 0 SECONDS, amount = 1, volume = 50)) + return ITEM_INTERACT_BLOCKING adjustBruteLoss(-30) add_fingerprint(user) - visible_message(span_notice("[user] fixes some of the dents on [src].")) + balloon_alert(user, "dents fixed") + user.visible_message( + span_notice("[user] fixes some of the dents on [src]."), + span_notice("You fix some of the dents on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + return ITEM_INTERACT_SUCCESS /mob/living/silicon/robot/crowbar_act(mob/living/user, obj/item/tool) - . = TRUE if(opened) - to_chat(user, span_notice("You close the cover.")) + balloon_alert(user, "chassis cover closed") opened = FALSE update_icons() else if(locked) - to_chat(user, span_warning("The cover is locked and cannot be opened!")) + balloon_alert(user, "chassis cover locked!") else - to_chat(user, span_notice("You open the cover.")) + balloon_alert(user, "chassis cover opened") opened = TRUE update_icons() - return TRUE + return ITEM_INTERACT_SUCCESS /mob/living/silicon/robot/screwdriver_act(mob/living/user, obj/item/tool) if(!opened) - return FALSE - . = TRUE + return NONE if(!cell) // haxing wiresexposed = !wiresexposed - to_chat(user, span_notice("The wires have been [wiresexposed ? "exposed" : "unexposed"].")) + balloon_alert(user, "wires [wiresexposed ? "exposed" : "unexposed"]") else // radio if(shell) - to_chat(user, span_warning("You cannot seem to open the radio compartment!")) //Prevent AI radio key theft + balloon_alert(user, "can't access radio!") // Prevent AI radio key theft else if(radio) radio.screwdriver_act(user, tool) // Push it to the radio to let it handle everything else to_chat(user, span_warning("Unable to locate a radio!")) + balloon_alert(user, "no radio found!") update_icons() + return ITEM_INTERACT_SUCCESS /mob/living/silicon/robot/wrench_act(mob/living/user, obj/item/tool) if(!(opened && !cell)) // Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module. - return FALSE - . = TRUE + return NONE if(!lockcharge) to_chat(user, span_warning("[src]'s bolts spark! Maybe you should lock them down first!")) spark_system.start() - return - to_chat(user, span_notice("You start to unfasten [src]'s securing bolts...")) - if(tool.use_tool(src, user, 5 SECONDS, volume = 50) && !cell) - user.visible_message(span_notice("[user] deconstructs [src]!"), span_notice("You unfasten the securing bolts, and [src] falls to pieces!")) - cyborg_deconstruct() - return + return ITEM_INTERACT_BLOCKING + balloon_alert(user, "deconstructing...") + if(!tool.use_tool(src, user, 5 SECONDS, volume = 50) && !cell) + return ITEM_INTERACT_BLOCKING + loc.balloon_alert(user, "deconstructed") + user.visible_message( + span_notice("[user] deconstructs [src]!"), + span_notice("You unfasten the securing bolts, and [src] falls to pieces!"), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + cyborg_deconstruct() + return ITEM_INTERACT_SUCCESS /mob/living/silicon/robot/fire_act() if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index e547d390fcd..71c27ecd6be 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -926,6 +926,8 @@ if(inserted_disk) user.put_in_hands(inserted_disk) balloon_alert(user, "disks swapped") + else + balloon_alert(user, "disk inserted") inserted_disk = disk playsound(src, 'sound/machines/card_slide.ogg', 50) return ITEM_INTERACT_SUCCESS