From 70d26adf1ca70e647677e7843ecef128b5e4b89f Mon Sep 17 00:00:00 2001 From: zxaber <37497534+zxaber@users.noreply.github.com> Date: Mon, 24 Jun 2024 11:32:51 -0700 Subject: [PATCH 01/85] Cyborg Omnitool Refactor (#83880) ## About The Pull Request - Complete rewrite of borg omnitool code; - - Borgs that use omnitools now have a "Omni Toolbox" that holds whatever tools the Omnitool would cover. The toolbox keeps track of Omnitool "Arms" in a list, as well as when to upgrade (or downgrade) tool speed. The toolbox is not seen by the player directly. - - Omnitool "Arms" will display available tools based on the Omni Toolbox's contents. Selecting one does not move the tool out of the toolbox, but instead simply overrides any following clicks with a melee attack chain of the selected item. This is reminiscent of how borg apparatus tools work. When selecting a tool, the Omnitool "arm" will also set its own icon state to match the tool selected. - - Because all Omnitool "arms" are using the same tools from the same toolbox, actions done with one can be seen from another. For example, using the first Omnitool to scan the Silo with the engineer borg's multitool will update the tool's buffer, and it can be used later, even if the multitool is selected by the second Omnitool. - Because we're now using real tools, rather than a single tool item faking tool usage via tool flags, almost all interactions with tools should properly carry over. - Added Cyborg versions of the medical toolset, for use with the Medical Cyborg omnitool, so that we can finally use the really nice borg-version medical tool sprites. ## Why It's Good For The Game Easier to read code. Fixes #83667 Fixes #83537 Fixes #83077 Fixes #82918 partially; Heating beakers works, but the tile quick-swap function will not function; the action is initiated by a click from the tile stack rather than the crowbar. ## Changelog :cl: fix: Refactored borg omnitool code, fixing most of the unique interaction issues. /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/datums/components/surgery_initiator.dm | 4 +- .../telecomms/machine_interactions.dm | 7 +- code/game/objects/items/robot/items/tools.dm | 309 +++++++----------- .../objects/items/robot/robot_upgrades.dm | 26 +- .../mob/living/silicon/robot/robot_model.dm | 14 + code/modules/surgery/surgery.dm | 4 + code/modules/surgery/tools.dm | 30 ++ icons/mob/silicon/robot_items.dmi | Bin 7003 -> 4251 bytes 8 files changed, 183 insertions(+), 211 deletions(-) diff --git a/code/datums/components/surgery_initiator.dm b/code/datums/components/surgery_initiator.dm index 41c5f1ef87ad7..de3f83739e546 100644 --- a/code/datums/components/surgery_initiator.dm +++ b/code/datums/components/surgery_initiator.dm @@ -136,8 +136,8 @@ if(iscyborg(user)) var/has_cautery = FALSE - for(var/obj/item/borg/cyborg_omnitool/medical/omnitool in user.held_items) - if(omnitool.tool_behaviour == TOOL_CAUTERY) + for(var/obj/item/borg/cyborg_omnitool/toolarm in user.held_items) + if(toolarm.selected && istype(toolarm.selected, /obj/item/cautery)) has_cautery = TRUE if(!has_cautery) patient.balloon_alert(user, "need a cautery in an inactive slot to stop the surgery!") diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index 5086f7e91a7f1..77e1efbdfa13d 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -254,8 +254,11 @@ var/mob/living/silicon/ai/U = user multitool = U.aiMulti else if(iscyborg(user) && in_range(user, src)) - if(istype(user.get_active_held_item(), /obj/item/multitool)) - multitool = user.get_active_held_item() + var/mob/living/silicon/robot/borguser = user + for(var/obj/item/borg/cyborg_omnitool/toolarm in borguser.held_items) + if(istype(toolarm.selected, /obj/item/multitool)) + multitool = toolarm.selected + break return multitool /obj/machinery/telecomms/proc/canAccess(mob/user) diff --git a/code/game/objects/items/robot/items/tools.dm b/code/game/objects/items/robot/items/tools.dm index b9f0c103ba540..8cdf65a431a6a 100644 --- a/code/game/objects/items/robot/items/tools.dm +++ b/code/game/objects/items/robot/items/tools.dm @@ -176,218 +176,145 @@ projectile.speed *= (1 / projectile_speed_coefficient) projectile.cut_overlay(projectile_effect) -//bare minimum omni-toolset for modularity -/obj/item/borg/cyborg_omnitool - name = "cyborg omni-toolset" - desc = "You shouldn't see this in-game normally." +////////////////////// +///CYBORG OMNITOOLS/// +////////////////////// + +/** + Onmi Toolboxs act as a cache of tools for a particular borg's omnitools. Not all borg + get a toolbox (as not all borgs use omnitools), and those that do can only have one + toolbox. The toolbox keeps track of a borg's omnitool arms, and handles speed upgrades. + + Omnitools are the actual tool arms for the cyborg to interact with. When attack_self + is called, they can select a tool from the toolbox. The tool is not moved, and instead + only referenced in place of the omnitool's own attacks. The omnitool also takes on + the tool's sprite, which completes the illusion. In this way, multiple tools are + shared between multiple omnitool arms. A multitool's buffer, for example, will not + depend on which omnitool arm was used to set it. +*/ +/obj/item/cyborg_omnitoolbox + name = "broken cyborg toolbox" + desc = "Some internal part of a broken cyborg." icon = 'icons/mob/silicon/robot_items.dmi' - icon_state = "toolkit_medborg" - ///our tools - var/list/radial_menu_options = list() - ///object we are referencing to for force, sharpness and sound - var/obj/item/reference - //is the toolset upgraded or not - var/upgraded = FALSE - ///how much faster should the toolspeed be? - var/upgraded_toolspeed = 0.7 + icon_state = "lollipop" + toolspeed = 10 + ///List of Omnitool "arms" that the borg has. + var/list/omnitools = list() + ///List of paths for tools. These will be created during Initialize() + var/list/toolpaths = list() + ///Target Toolspeed to set after reciving an omnitool upgrade + var/upgraded_toolspeed = 10 + ///Whether we currently have the upgraded speed + var/currently_upgraded = FALSE + +/obj/item/cyborg_omnitoolbox/Initialize(mapload) + . = ..() + if(!toolpaths.len) + return -/obj/item/borg/cyborg_omnitool/get_all_tool_behaviours() - return list(TOOL_SCALPEL, TOOL_HEMOSTAT) + var/obj/item/newitem + for(var/newpath in toolpaths) + newitem = new newpath(src) + newitem.toolspeed = toolspeed //In case thse have different base speeds as stand-alone tools on other borgs + ADD_TRAIT(newitem, TRAIT_NODROP, CYBORG_ITEM_TRAIT) -/obj/item/borg/cyborg_omnitool/Initialize(mapload) - . = ..() - AddComponent(/datum/component/butchering, \ - speed = 8 SECONDS, \ - effectiveness = 100, \ - disabled = TRUE, \ +/obj/item/cyborg_omnitoolbox/proc/set_upgrade(upgrade = FALSE) + for(var/obj/item/tool in contents) + if(upgrade) + tool.toolspeed = upgraded_toolspeed + else + tool.toolspeed = toolspeed + currently_upgraded = upgrade + +/obj/item/cyborg_omnitoolbox/engineering + toolspeed = 0.5 + upgraded_toolspeed = 0.3 + toolpaths = list( + /obj/item/wrench/cyborg, + /obj/item/wirecutters/cyborg, + /obj/item/screwdriver/cyborg, + /obj/item/crowbar/cyborg, + /obj/item/multitool/cyborg, ) - radial_menu_options = list( - NO_TOOL = image(icon = 'icons/mob/silicon/robot_items.dmi', icon_state = initial(icon_state)), - TOOL_SCALPEL = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_SCALPEL]"), - TOOL_HEMOSTAT = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_HEMOSTAT]"), + +/obj/item/cyborg_omnitoolbox/medical + toolspeed = 1 + upgraded_toolspeed = 0.7 + toolpaths = list( + /obj/item/scalpel/cyborg, + /obj/item/surgicaldrill/cyborg, + /obj/item/hemostat/cyborg, + /obj/item/retractor/cyborg, + /obj/item/cautery/cyborg, + /obj/item/circular_saw/cyborg, + /obj/item/bonesetter/cyborg, ) -/obj/item/borg/cyborg_omnitool/attack_self(mob/user) - var/new_tool_behaviour = show_radial_menu(user, src, radial_menu_options, require_near = TRUE, tooltips = TRUE) +/obj/item/borg/cyborg_omnitool + name = "broken cyborg tool arm" + desc = "Some internal part of a broken cyborg." + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "lollipop" + ///Ref to the toolbox, since our own loc will be changing + var/obj/item/cyborg_omnitoolbox/toolbox + ///Ref to currently selected tool, if any + var/obj/item/selected - if(isnull(new_tool_behaviour) || new_tool_behaviour == tool_behaviour) +/obj/item/borg/cyborg_omnitool/Initialize(mapload) + . = ..() + if(!iscyborg(loc.loc)) return - if(new_tool_behaviour == NO_TOOL) - tool_behaviour = null - else - tool_behaviour = new_tool_behaviour + var/obj/item/robot_model/model = loc + var/obj/item/cyborg_omnitoolbox/chassis_toolbox = model.toolbox + if(!chassis_toolbox) + return + toolbox = chassis_toolbox + toolbox.omnitools += src - reference_item_for_parameters() - update_tool_parameters(reference) - update_appearance(UPDATE_ICON_STATE) +/obj/item/borg/cyborg_omnitool/attack_self(mob/user) + var/list/radial_menu_options = list() + for(var/obj/item/borgtool in toolbox.contents) + radial_menu_options[borgtool] = image(icon = borgtool.icon, icon_state = borgtool.icon_state) + var/obj/item/potential_new_tool = show_radial_menu(user, src, radial_menu_options, require_near = TRUE, tooltips = TRUE) + if(!potential_new_tool) + return ..() + if(potential_new_tool == selected) + return ..() + for(var/obj/item/borg/cyborg_omnitool/coworker in toolbox.omnitools) + if(coworker.selected == potential_new_tool) + coworker.deselect() //Can I borrow that please + break + selected = potential_new_tool + icon_state = selected.icon_state playsound(src, 'sound/items/change_jaws.ogg', 50, TRUE) - -/// Used to get reference item for the tools -/obj/item/borg/cyborg_omnitool/proc/reference_item_for_parameters() - SHOULD_CALL_PARENT(FALSE) - switch(tool_behaviour) - if(TOOL_SCALPEL) - reference = /obj/item/scalpel - if(TOOL_HEMOSTAT) - reference = /obj/item/hemostat - -/// Used to update sounds and tool parameters during switching -/obj/item/borg/cyborg_omnitool/proc/update_tool_parameters(/obj/item/reference) - if(isnull(reference)) - sharpness = NONE - force = initial(force) - wound_bonus = 0 - bare_wound_bonus = 0 - armour_penetration = 0 - hitsound = initial(hitsound) - usesound = initial(usesound) - else - force = initial(reference.force) - wound_bonus = reference::wound_bonus - bare_wound_bonus = reference::bare_wound_bonus - armour_penetration = reference::armour_penetration - sharpness = initial(reference.sharpness) - hitsound = initial(reference.hitsound) - usesound = initial(reference.usesound) - -/obj/item/borg/cyborg_omnitool/update_icon_state() - icon_state = initial(icon_state) - - if (tool_behaviour) - icon_state += "_[sanitize_css_class_name(tool_behaviour)]" - - if(tool_behaviour) - inhand_icon_state = initial(inhand_icon_state) + "_deactivated" - else - inhand_icon_state = initial(inhand_icon_state) - return ..() -/** - * proc that's used when cyborg is upgraded with an omnitool upgrade board - * - * adds name and desc changes. also changes tools to default configuration to indicate it's been sucessfully upgraded - * changes the toolspeed to the upgraded_toolspeed variable - */ -/obj/item/borg/cyborg_omnitool/proc/upgrade_omnitool() - name = "advanced [name]" - desc += "\nIt seems that this one has been upgraded to perform tasks faster." - toolspeed = upgraded_toolspeed - upgraded = TRUE - tool_behaviour = null - reference_item_for_parameters() - update_tool_parameters(reference) - update_appearance(UPDATE_ICON_STATE) - playsound(src, 'sound/items/change_jaws.ogg', 50, TRUE) - -/** - * proc that's used when a cyborg with an upgraded omnitool is downgraded - * - * reverts all name and desc changes to it's initial variables. also changes tools to default configuration to indicate it's been downgraded - * changes the toolspeed to default variable - */ -/obj/item/borg/cyborg_omnitool/proc/downgrade_omnitool() - name = initial(name) - desc = initial(desc) - toolspeed = initial(toolspeed) - upgraded = FALSE - tool_behaviour = null - reference_item_for_parameters() - update_tool_parameters(reference) - update_appearance(UPDATE_ICON_STATE) +/obj/item/borg/cyborg_omnitool/proc/deselect() + if(!selected) + return + selected = null + icon_state = initial(icon_state) playsound(src, 'sound/items/change_jaws.ogg', 50, TRUE) -/obj/item/borg/cyborg_omnitool/medical - name = "surgical omni-toolset" - desc = "A set of surgical tools used by cyborgs to operate on various surgical operations." - item_flags = SURGICAL_TOOL - -/obj/item/borg/cyborg_omnitool/medical/get_all_tool_behaviours() - return list(TOOL_SCALPEL, TOOL_HEMOSTAT, TOOL_RETRACTOR, TOOL_SAW, TOOL_DRILL, TOOL_CAUTERY, TOOL_BONESET) +/obj/item/borg/cyborg_omnitool/cyborg_unequip() + deselect() + return ..() -/obj/item/borg/cyborg_omnitool/medical/Initialize(mapload) - . = ..() - AddComponent(/datum/component/butchering, \ - speed = 8 SECONDS, \ - effectiveness = 100, \ - disabled = TRUE, \ - ) - radial_menu_options = list( - TOOL_SCALPEL = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_SCALPEL]"), - TOOL_HEMOSTAT = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_HEMOSTAT]"), - TOOL_RETRACTOR = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_RETRACTOR]"), - TOOL_SAW = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_SAW]"), - TOOL_DRILL = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_DRILL]"), - TOOL_CAUTERY = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_CAUTERY]"), - TOOL_BONESET = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_BONESET]"), - TOOL_DRAPES = image(icon = 'icons/obj/medical/surgery_tools.dmi', icon_state = "[TOOL_DRAPES]"), - ) +/obj/item/borg/cyborg_omnitool/pre_attack(atom/atom, mob/living/user, params) + if(selected) + selected.melee_attack_chain(user, atom, params) + return TRUE + return ..() -/obj/item/borg/cyborg_omnitool/medical/reference_item_for_parameters() - var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering) - butchering.butchering_enabled = (tool_behaviour == TOOL_SCALPEL || tool_behaviour == TOOL_SAW) - RemoveElement(/datum/element/eyestab) - qdel(GetComponent(/datum/component/surgery_initiator)) - item_flags = SURGICAL_TOOL - switch(tool_behaviour) - if(TOOL_SCALPEL) - reference = /obj/item/scalpel - AddElement(/datum/element/eyestab) - if(TOOL_DRILL) - reference = /obj/item/surgicaldrill - AddElement(/datum/element/eyestab) - if(TOOL_HEMOSTAT) - reference = /obj/item/hemostat - if(TOOL_RETRACTOR) - reference = /obj/item/retractor - if(TOOL_CAUTERY) - reference = /obj/item/cautery - if(TOOL_SAW) - reference = /obj/item/circular_saw - if(TOOL_BONESET) - reference = /obj/item/bonesetter - if(TOOL_DRAPES) - reference = /obj/item/surgical_drapes - AddComponent(/datum/component/surgery_initiator) - item_flags = null - -//Toolset for engineering cyborgs, this is all of the tools except for the welding tool. since it's quite hard to implement (read:can't be arsed to) /obj/item/borg/cyborg_omnitool/engineering name = "engineering omni-toolset" desc = "A set of engineering tools used by cyborgs to conduct various engineering tasks." - icon = 'icons/obj/items_cyborg.dmi' icon_state = "toolkit_engiborg" - item_flags = null - toolspeed = 0.5 - upgraded_toolspeed = 0.3 - -/obj/item/borg/cyborg_omnitool/engineering/get_all_tool_behaviours() - return list(TOOL_SCREWDRIVER, TOOL_CROWBAR, TOOL_WRENCH, TOOL_WIRECUTTER, TOOL_MULTITOOL) -/obj/item/borg/cyborg_omnitool/engineering/Initialize(mapload) - . = ..() - radial_menu_options = list( - TOOL_SCREWDRIVER = image(icon = 'icons/obj/tools.dmi', icon_state = "[TOOL_SCREWDRIVER]_map"), - TOOL_CROWBAR = image(icon = 'icons/obj/tools.dmi', icon_state = "[TOOL_CROWBAR]"), - TOOL_WRENCH = image(icon = 'icons/obj/tools.dmi', icon_state = "[TOOL_WRENCH]"), - TOOL_WIRECUTTER = image(icon = 'icons/obj/tools.dmi', icon_state = "[TOOL_WIRECUTTER]_map"), - TOOL_MULTITOOL = image(icon = 'icons/obj/devices/tool.dmi', icon_state = "[TOOL_MULTITOOL]"), - ) - -/obj/item/borg/cyborg_omnitool/engineering/reference_item_for_parameters() - RemoveElement(/datum/element/eyestab) - switch(tool_behaviour) - if(TOOL_SCREWDRIVER) - reference = /obj/item/screwdriver - AddElement(/datum/element/eyestab) - if(TOOL_CROWBAR) - reference = /obj/item/crowbar - if(TOOL_WRENCH) - reference = /obj/item/wrench - if(TOOL_WIRECUTTER) - reference = /obj/item/wirecutters - if(TOOL_MULTITOOL) - reference = /obj/item/multitool +/obj/item/borg/cyborg_omnitool/medical + name = "surgical omni-toolset" + desc = "A set of surgical tools used by cyborgs to operate on various surgical operations." + icon_state = "toolkit_medborg" #undef PKBORG_DAMPEN_CYCLE_DELAY #undef POWER_RECHARGE_CYBORG_DRAIN_MULTIPLIER diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 1a695442d8a76..84de0c577c32a 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -425,21 +425,18 @@ . = ..() if(!.) return . + if(cyborg.model.toolbox.currently_upgraded) + to_chat(user, span_warning("This unit is already equipped with an omnitool upgrade!")) + return FALSE + cyborg.model.toolbox.set_upgrade(TRUE) ADD_TRAIT(cyborg, TRAIT_FASTMED, REF(src)) - for(var/obj/item/borg/cyborg_omnitool/medical/omnitool_upgrade in cyborg.model.modules) - if(omnitool_upgrade.upgraded) - to_chat(user, span_warning("This unit is already equipped with an omnitool upgrade!")) - return FALSE - for(var/obj/item/borg/cyborg_omnitool/medical/omnitool in cyborg.model.modules) - omnitool.upgrade_omnitool() /obj/item/borg/upgrade/surgery_omnitool/deactivate(mob/living/silicon/robot/cyborg, mob/living/user = usr) . = ..() if(!.) return . + cyborg.model.toolbox.set_upgrade(FALSE) REMOVE_TRAIT(cyborg, TRAIT_FASTMED, REF(src)) - for(var/obj/item/borg/cyborg_omnitool/omnitool in cyborg.model.modules) - omnitool.downgrade_omnitool() /obj/item/borg/upgrade/engineering_omnitool name = "cyborg engineering omni-tool upgrade" @@ -454,19 +451,16 @@ . = ..() if(!.) return . - for(var/obj/item/borg/cyborg_omnitool/engineering/omnitool_upgrade in cyborg.model.modules) - if(omnitool_upgrade.upgraded) - to_chat(user, span_warning("This unit is already equipped with an omnitool upgrade!")) - return FALSE - for(var/obj/item/borg/cyborg_omnitool/engineering/omnitool in cyborg.model.modules) - omnitool.upgrade_omnitool() + if(cyborg.model.toolbox.currently_upgraded) + to_chat(user, span_warning("This unit is already equipped with an omnitool upgrade!")) + return FALSE + cyborg.model.toolbox.set_upgrade(TRUE) /obj/item/borg/upgrade/engineering_omnitool/deactivate(mob/living/silicon/robot/cyborg, mob/living/user = usr) . = ..() if(!.) return . - for(var/obj/item/borg/cyborg_omnitool/omnitool in cyborg.model.modules) - omnitool.downgrade_omnitool() + cyborg.model.toolbox.set_upgrade(FALSE) /obj/item/borg/upgrade/defib name = "medical cyborg defibrillator" diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm index 1721d6ec2c102..4fc4bd5d8c15d 100644 --- a/code/modules/mob/living/silicon/robot/robot_model.dm +++ b/code/modules/mob/living/silicon/robot/robot_model.dm @@ -53,9 +53,17 @@ var/list/ride_offset_y = list("north" = 4, "south" = 4, "east" = 3, "west" = 3) ///List of skins the borg can be reskinned to, optional var/list/borg_skins + ///Omnitoolbox, holder of certain borg tools. Not all models have one + var/obj/item/cyborg_omnitoolbox/toolbox + ///Path to toolbox, if a model gets one + var/toolbox_path /obj/item/robot_model/Initialize(mapload) . = ..() + + if(toolbox_path) + toolbox = new toolbox_path(src) + for(var/path in basic_modules) var/obj/item/new_module = new path(src) basic_modules += new_module @@ -398,6 +406,7 @@ model_select_icon = "engineer" model_traits = list(TRAIT_NEGATES_GRAVITY) hat_offset = -4 + toolbox_path = /obj/item/cyborg_omnitoolbox/engineering /obj/item/robot_model/janitor name = "Janitor" @@ -678,6 +687,7 @@ /obj/item/reagent_containers/syringe, /obj/item/borg/cyborg_omnitool/medical, /obj/item/borg/cyborg_omnitool/medical, + /obj/item/surgical_drapes/cyborg, /obj/item/blood_filter, /obj/item/extinguisher/mini, /obj/item/emergency_bed/silicon, @@ -695,6 +705,7 @@ model_select_icon = "medical" model_traits = list(TRAIT_PUSHIMMUNE) hat_offset = 3 + toolbox_path = /obj/item/cyborg_omnitoolbox/medical borg_skins = list( "Machinified Doctor" = list(SKIN_ICON_STATE = "medical"), "Qualified Doctor" = list(SKIN_ICON_STATE = "qualified_doctor"), @@ -877,6 +888,7 @@ /obj/item/healthanalyzer, /obj/item/borg/cyborg_omnitool/medical, /obj/item/borg/cyborg_omnitool/medical, + /obj/item/surgical_drapes/cyborg, /obj/item/blood_filter, /obj/item/melee/energy/sword/cyborg/saw, /obj/item/emergency_bed/silicon, @@ -892,6 +904,7 @@ model_select_icon = "malf" model_traits = list(TRAIT_PUSHIMMUNE) hat_offset = 3 + toolbox_path = /obj/item/cyborg_omnitoolbox/medical /obj/item/robot_model/saboteur name = "Syndicate Saboteur" @@ -921,6 +934,7 @@ model_select_icon = "malf" model_traits = list(TRAIT_PUSHIMMUNE, TRAIT_NEGATES_GRAVITY) hat_offset = -4 + toolbox_path = /obj/item/cyborg_omnitoolbox/engineering canDispose = TRUE /obj/item/robot_model/syndicate/kiltborg diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index a555548e43268..17444590cf2ef 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -124,6 +124,10 @@ if(isnull(step)) return FALSE var/obj/item/tool = user.get_active_held_item() + if(istype(tool, /obj/item/borg/cyborg_omnitool)) //catches borg surgeries + var/obj/item/borg/cyborg_omnitool/toolarm = tool + if(toolarm.selected) + tool = toolarm.selected if(step.try_op(user, target, user.zone_selected, tool, src, try_to_fail)) return TRUE if(tool && tool.item_flags & SURGICAL_TOOL) //Just because you used the wrong tool it doesn't mean you meant to whack the patient with it diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index be4bdb6db5d24..6c3ee9c014713 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -22,6 +22,9 @@ desc = "Micro-mechanical manipulator for retracting stuff." toolspeed = 0.5 +/obj/item/retractor/cyborg + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg_retractor" /obj/item/hemostat name = "hemostat" @@ -49,6 +52,9 @@ desc = "Tiny servos power a pair of pincers to stop bleeding." toolspeed = 0.5 +/obj/item/hemostat/cyborg + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg_hemostat" /obj/item/cautery name = "cautery" @@ -80,6 +86,10 @@ desc = "A heated element that cauterizes wounds." toolspeed = 0.5 +/obj/item/cautery/cyborg + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg_cautery" + /obj/item/cautery/advanced name = "searing tool" desc = "It projects a high power laser used for medical applications." @@ -175,6 +185,10 @@ playsound(user, 'sound/machines/juicer.ogg', 20, TRUE) return MANUAL_SUICIDE +/obj/item/surgicaldrill/cyborg + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg_drill" + /obj/item/surgicaldrill/augment desc = "Effectively a small power drill contained within your arm. May or may not pierce the heavens." hitsound = 'sound/weapons/circsawhit.ogg' @@ -225,6 +239,10 @@ user.visible_message(span_suicide("[user] is slitting [user.p_their()] [pick("wrists", "throat", "stomach")] with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return BRUTELOSS +/obj/item/scalpel/cyborg + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg_scalpel" + /obj/item/scalpel/augment desc = "Ultra-sharp blade attached directly to your bone for extra-accuracy." toolspeed = 0.5 @@ -276,6 +294,10 @@ /obj/item/circular_saw/get_surgery_tool_overlay(tray_extended) return surgical_tray_overlay +/obj/item/circular_saw/cyborg + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg_saw" + /obj/item/circular_saw/augment desc = "A small but very fast spinning saw. It rips and tears until it is done." w_class = WEIGHT_CLASS_SMALL @@ -299,6 +321,10 @@ . = ..() AddComponent(/datum/component/surgery_initiator) +/obj/item/surgical_drapes/cyborg + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg_surgicaldrapes" + /obj/item/surgical_processor //allows medical cyborgs to scan and initiate advanced surgeries name = "surgical processor" desc = "A device for scanning and initiating surgeries from a disk or operating computer." @@ -580,6 +606,10 @@ /obj/item/bonesetter/get_surgery_tool_overlay(tray_extended) return "bonesetter" + (tray_extended ? "" : "_out") +/obj/item/bonesetter/cyborg + icon = 'icons/mob/silicon/robot_items.dmi' + icon_state = "toolkit_medborg_bonesetter" + /obj/item/blood_filter name = "blood filter" desc = "For filtering the blood." diff --git a/icons/mob/silicon/robot_items.dmi b/icons/mob/silicon/robot_items.dmi index 5ad091d6c9f8690d0edc0b977476d5ad4d8c760d..00c813ace7f48cceb06133a309f81f036dc778ca 100644 GIT binary patch literal 4251 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 From d1051ec8a80b34ca3f3cab2a14e75421e3bae3d6 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 25 Jun 2024 06:33:09 +1200 Subject: [PATCH 02/85] Automatic changelog for PR #83880 [ci skip] --- html/changelogs/AutoChangeLog-pr-83880.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83880.yml diff --git a/html/changelogs/AutoChangeLog-pr-83880.yml b/html/changelogs/AutoChangeLog-pr-83880.yml new file mode 100644 index 0000000000000..4962c62c8ceef --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83880.yml @@ -0,0 +1,4 @@ +author: "zxaber" +delete-after: True +changes: + - bugfix: "Refactored borg omnitool code, fixing most of the unique interaction issues." \ No newline at end of file From 5c6e837dee9f62d382e0e30a8a1c3cc5c54ee8e5 Mon Sep 17 00:00:00 2001 From: FlufflesTheDog Date: Mon, 24 Jun 2024 13:41:17 -0700 Subject: [PATCH 03/85] Fix printed structures/machines having a random offset (#84272) ## About The Pull Request Checks for isitem() when printing at a lathe, to avoid offsetting things that can't be picked up. Also removes a redundant nullcheck in machine/powered(), get_area already covers being in nullspace, and setting a machine that doesn't use power to be unpowered is erroneous- the area based power updating early returns for such machines, leaving them forever unusuable. ## Why It's Good For The Game Having structures (or possibly machines) offset on their tile looks really not good, and can't generally be fixed in-game. --- code/game/machinery/autolathe.dm | 10 ++++++---- code/modules/power/power.dm | 2 -- code/modules/research/machinery/_production.dm | 10 ++++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 6ed033886e60a..c1baa172dbfd3 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -355,8 +355,9 @@ var/number_to_make = (initial(stack_item.amount) * items_remaining) while(number_to_make > max_stack_amount) created = new stack_item(null, max_stack_amount) //it's imporant to spawn things in nullspace, since obj's like stacks qdel when they enter a tile/merge with other stacks of the same type, resulting in runtimes. - created.pixel_x = created.base_pixel_x + rand(-6, 6) - created.pixel_y = created.base_pixel_y + rand(-6, 6) + if(isitem(created)) + created.pixel_x = created.base_pixel_x + rand(-6, 6) + created.pixel_y = created.base_pixel_y + rand(-6, 6) created.forceMove(target) number_to_make -= max_stack_amount @@ -366,8 +367,9 @@ created = new design.build_path(null) split_materials_uniformly(materials_needed, material_cost_coefficient, created) - created.pixel_x = created.base_pixel_x + rand(-6, 6) - created.pixel_y = created.base_pixel_y + rand(-6, 6) + if(isitem(created)) + created.pixel_x = created.base_pixel_x + rand(-6, 6) + created.pixel_y = created.base_pixel_y + rand(-6, 6) SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[created.type]")) created.forceMove(target) diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index 71daf214019c7..ab4dfba49db7b 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -117,8 +117,6 @@ // returns true if the area has power on given channel (or doesn't require power). // defaults to power_channel /obj/machinery/proc/powered(chan = power_channel, ignore_use_power = FALSE) - if(!loc) - return FALSE if(!use_power && !ignore_use_power) return TRUE diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index d110dab03e02d..295cd05fe9040 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -416,8 +416,9 @@ var/number_to_make = (initial(stack_item.amount) * items_remaining) while(number_to_make > max_stack_amount) created = new stack_item(null, max_stack_amount) //it's imporant to spawn things in nullspace, since obj's like stacks qdel when they enter a tile/merge with other stacks of the same type, resulting in runtimes. - created.pixel_x = created.base_pixel_x + rand(-6, 6) - created.pixel_y = created.base_pixel_y + rand(-6, 6) + if(isitem(created)) + created.pixel_x = created.base_pixel_x + rand(-6, 6) + created.pixel_y = created.base_pixel_y + rand(-6, 6) created.forceMove(target) number_to_make -= max_stack_amount @@ -426,8 +427,9 @@ created = new design.build_path(null) split_materials_uniformly(design_materials, material_cost_coefficient, created) - created.pixel_x = created.base_pixel_x + rand(-6, 6) - created.pixel_y = created.base_pixel_y + rand(-6, 6) + if(isitem(created)) + created.pixel_x = created.base_pixel_x + rand(-6, 6) + created.pixel_y = created.base_pixel_y + rand(-6, 6) SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[created.type]")) created.forceMove(target) From a7b0af43cd0998567bbda0e26b2bd3107b588bd2 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 25 Jun 2024 08:41:35 +1200 Subject: [PATCH 04/85] Automatic changelog for PR #84272 [ci skip] --- html/changelogs/AutoChangeLog-pr-84272.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-84272.yml diff --git a/html/changelogs/AutoChangeLog-pr-84272.yml b/html/changelogs/AutoChangeLog-pr-84272.yml new file mode 100644 index 0000000000000..6eef91b50c43b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84272.yml @@ -0,0 +1,4 @@ +author: "FlufflesTheDog" +delete-after: True +changes: + - bugfix: "printed medical beds are no longer randomly offset" \ No newline at end of file From 224f01d333c3c30afedab366919a4429ee055d21 Mon Sep 17 00:00:00 2001 From: FlufflesTheDog Date: Mon, 24 Jun 2024 13:42:16 -0700 Subject: [PATCH 05/85] PDA messenger & message monitor show actual emoji, other fixes (#83819) ## About The Pull Request Makes pda messages actually appear in the messenger UI, as was supposed to be the case way back in #75820 Does the same for tcomm's message server monitor, making sure anyone trying to view pda messages is actually able to get a cohesive idea of what the message actually contained. Also a couple of other small fixes, listed in the changelogs ![image](https://github.com/tgstation/tgstation/assets/25628932/6ee5fd4a-d1bb-4c0a-9563-18d6b5541540) ![image](https://github.com/tgstation/tgstation/assets/25628932/65f74316-ac2e-4e28-9c5c-8ba4a9c22fcd) Fixes #77856 ## Why It's Good For The Game Consistency, fix bugs ## Changelog :cl: Fluffles fix: emoji show up in the messenger UI fix: emoji show up in the message server monitor UI fix: you can adjust your pda ringtone in-game fix: having an empty pAI in your pda doesn't break ringtones fix: pdas specifically set to not consume power don't constantly switch to messenger fix: you can use the quick-reply button for messages while resting fix: deadchat pda messages show the imprinted sender's name instead of whoever is holding the pda fix: emoji show up in deadchat pda messages /:cl: --- .../machinery/telecomms/computers/message.dm | 3 +++ .../programs/messenger/messenger_program.dm | 18 ++++++++++-------- .../tgui/interfaces/MessageMonitor.tsx | 7 ++++++- .../interfaces/NtosMessenger/ChatScreen.tsx | 7 ++++--- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm index 1998654df00b1..a38f18231fb76 100644 --- a/code/game/machinery/telecomms/computers/message.dm +++ b/code/game/machinery/telecomms/computers/message.dm @@ -268,6 +268,9 @@ ui = new(user, src, "MessageMonitor", name) ui.open() +/obj/machinery/computer/message_monitor/ui_assets(mob/user) + . = ..() + . += get_asset_datum(/datum/asset/spritesheet/chat) #undef MSG_MON_SCREEN_MAIN #undef MSG_MON_SCREEN_LOGS diff --git a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm index 0b2f478172b5e..4ad633aa94df4 100644 --- a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm +++ b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm @@ -166,7 +166,8 @@ if("PDA_ringSet") var/mob/living/user = usr var/new_ringtone = tgui_input_text(user, "Enter a new ringtone", "Ringtone", ringtone, encode = FALSE) - if(!in_range(computer, user) || computer.loc != user) + if(!computer.can_interact(user)) + computer.balloon_alert(user, "can't reach!") return FALSE return set_ringtone(new_ringtone, user) @@ -381,6 +382,10 @@ data["sending_virus"] = sending_virus return data +/datum/computer_file/program/messenger/ui_assets(mob/user) + . = ..() + . += get_asset_datum(/datum/asset/spritesheet/chat) + ////////////////////// // MESSAGE HANDLING // ////////////////////// @@ -463,7 +468,7 @@ if(sender && !check_pda_message_against_filter(message, sender)) return null - return message + return emoji_parse(message) /// Sends a message to targets via PDA. When sending to everyone, set `everyone` to true so the message is formatted accordingly /datum/computer_file/program/messenger/proc/send_message(atom/source, message, list/targets, everyone = FALSE) @@ -628,10 +633,8 @@ if(rigged) log_bomber(sender, "sent a rigged PDA message (Name: [fake_name]. Job: [fake_job]) to [english_list(stringified_targets)] [!is_special_character(sender) ? "(SENT BY NON-ANTAG)" : ""]") - message = emoji_parse(message) //already sent- this just shows the sent emoji as one to the sender in the to_chat - // Show it to ghosts - var/ghost_message = span_game_say("[span_name("[source]")] [rigged ? "(as [span_name(fake_name)]) Rigged " : ""]PDA Message --> [span_name("[signal.format_target()]")]: \"[signal.format_message()]\"") + var/ghost_message = span_game_say("[span_name(signal.format_sender())] [rigged ? "(as [span_name(fake_name)]) Rigged " : ""]PDA Message --> [span_name("[signal.format_target()]")]: \"[signal.format_message()]\"") var/list/message_listeners = GLOB.dead_player_list + GLOB.current_observers_list for(var/mob/listener as anything in message_listeners) if(!(get_chat_toggles(listener) & CHAT_GHOSTPDA)) @@ -678,7 +681,7 @@ viewing_messages_of = REF(chat) var/list/mob/living/receievers = list() - if(computer.inserted_pai) + if(computer.inserted_pai && computer.inserted_pai.pai) receievers += computer.inserted_pai.pai if(computer.loc && isliving(computer.loc)) receievers += computer.loc @@ -708,7 +711,6 @@ sender_title = "[sender_title]" var/inbound_message = "[signal.format_message()]" - inbound_message = emoji_parse(inbound_message) var/photo_message = signal.data["photo"] ? " (Photo Attached)" : "" to_chat(messaged_mob, span_infoplain("[icon2html(computer, messaged_mob)] PDA message from [sender_title], \"[inbound_message]\"[photo_message] [reply]")) @@ -727,7 +729,7 @@ if(QDELETED(src)) return - if(!usr.can_perform_action(computer, FORBID_TELEKINESIS_REACH)) + if(!usr.can_perform_action(computer, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) return // send an activation message and open the messenger diff --git a/tgui/packages/tgui/interfaces/MessageMonitor.tsx b/tgui/packages/tgui/interfaces/MessageMonitor.tsx index ed3afac07a2c2..fb237bb786d4d 100644 --- a/tgui/packages/tgui/interfaces/MessageMonitor.tsx +++ b/tgui/packages/tgui/interfaces/MessageMonitor.tsx @@ -133,7 +133,12 @@ const MessageLogsScreen = (props) => { {message.sender} {message.recipient} - {message.message} + + + ))} diff --git a/tgui/packages/tgui/interfaces/NtosMessenger/ChatScreen.tsx b/tgui/packages/tgui/interfaces/NtosMessenger/ChatScreen.tsx index b168b05729786..bdbd24adb25ec 100644 --- a/tgui/packages/tgui/interfaces/NtosMessenger/ChatScreen.tsx +++ b/tgui/packages/tgui/interfaces/NtosMessenger/ChatScreen.tsx @@ -1,5 +1,4 @@ import { BooleanLike } from 'common/react'; -import { decodeHtmlEntities } from 'common/string'; import { Component, createRef, RefObject } from 'react'; import { useBackend } from '../../backend'; @@ -402,12 +401,14 @@ const ChatMessage = (props: ChatMessageProps) => { const { message, everyone, outgoing, photoPath, timestamp, onPreviewImage } = props; - const displayMessage = decodeHtmlEntities(message); + const messageHTML = { + __html: `${message}`, + }; return ( - {displayMessage} + Date: Tue, 25 Jun 2024 08:42:45 +1200 Subject: [PATCH 06/85] Automatic changelog for PR #83819 [ci skip] --- html/changelogs/AutoChangeLog-pr-83819.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83819.yml diff --git a/html/changelogs/AutoChangeLog-pr-83819.yml b/html/changelogs/AutoChangeLog-pr-83819.yml new file mode 100644 index 0000000000000..2bb136f48bddb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83819.yml @@ -0,0 +1,11 @@ +author: "Fluffles" +delete-after: True +changes: + - bugfix: "emoji show up in the messenger UI" + - bugfix: "emoji show up in the message server monitor UI" + - bugfix: "you can adjust your pda ringtone in-game" + - bugfix: "having an empty pAI in your pda doesn't break ringtones" + - bugfix: "pdas specifically set to not consume power don't constantly switch to messenger" + - bugfix: "you can use the quick-reply button for messages while resting" + - bugfix: "deadchat pda messages show the imprinted sender's name instead of whoever is holding the pda" + - bugfix: "emoji show up in deadchat pda messages" \ No newline at end of file From 824e4c309778fba451bf7cd11bc00bc45d26f740 Mon Sep 17 00:00:00 2001 From: MrDas <62486730+Das15@users.noreply.github.com> Date: Mon, 24 Jun 2024 22:51:17 +0200 Subject: [PATCH 07/85] Fixes the duration of wizard spell mutate (#84263) ## About The Pull Request Fixes the remove_mutations proc of the wizard's spell mutate, so it calls the parent and actually removes the said mutations. Honestly the fact that it previously didn't call the parent function is byond me. Fixes #79491 ## Why It's Good For The Game No more infinite hulk for wizards! --- code/modules/spells/spell_types/self/mutate.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/spells/spell_types/self/mutate.dm b/code/modules/spells/spell_types/self/mutate.dm index 477c7e6723c3a..7ebd9ab4d1bfe 100644 --- a/code/modules/spells/spell_types/self/mutate.dm +++ b/code/modules/spells/spell_types/self/mutate.dm @@ -57,7 +57,7 @@ cast_on.add_atom_colour(COLOR_VIBRANT_LIME, TEMPORARY_COLOUR_PRIORITY) /datum/action/cooldown/spell/apply_mutations/mutate/remove_mutations(mob/living/carbon/human/cast_on) - if(QDELETED(cast_on) || !is_valid_target(cast_on)) + if(QDELETED(cast_on) || !is_valid_target(cast_on)) // Not 100% sure if this check is still needed, leaving it just in case return - + ..() cast_on.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY) From ac8c0edaefb937b896d36be839d83ca2d9fe031b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 25 Jun 2024 08:51:56 +1200 Subject: [PATCH 08/85] Automatic changelog for PR #84263 [ci skip] --- html/changelogs/AutoChangeLog-pr-84263.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-84263.yml diff --git a/html/changelogs/AutoChangeLog-pr-84263.yml b/html/changelogs/AutoChangeLog-pr-84263.yml new file mode 100644 index 0000000000000..070e280521d09 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84263.yml @@ -0,0 +1,4 @@ +author: "MrDas" +delete-after: True +changes: + - bugfix: "Fixed the duration of wizard's mutate spell." \ No newline at end of file From 46703dff791bb6f7c7dbf8258b69528b26008e06 Mon Sep 17 00:00:00 2001 From: the-orange-cow <76538214+the-orange-cow@users.noreply.github.com> Date: Mon, 24 Jun 2024 15:55:51 -0500 Subject: [PATCH 09/85] Fix chem reaction spawning issue (#84139) ## About The Pull Request Adds the instant reaction flag to the recipes for medicated sutures, advanced regenerative mesh, and mourning poultice. ## Why It's Good For The Game Fixes https://github.com/tgstation/tgstation/issues/84128. Full disclosure, I don't really know why this works, I kinda just copied SyncIt21's solution from https://github.com/tgstation/tgstation/pull/83354, and it worked locally without any runtimes. Edit : I've updated the linked issue with a better explanation of the bug. ## Changelog :cl: fix: Medicated suture, advanced regenerative mesh, and mourning poultice reactions should more consistently spawn the items they are meant to produce. /:cl: --- code/modules/reagents/chemistry/recipes/medicine.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm index b3a287707629b..868917893c90c 100644 --- a/code/modules/reagents/chemistry/recipes/medicine.dm +++ b/code/modules/reagents/chemistry/recipes/medicine.dm @@ -345,6 +345,7 @@ /datum/chemical_reaction/medicine/medsuture required_reagents = list(/datum/reagent/cellulose = 10, /datum/reagent/toxin/formaldehyde = 20, /datum/reagent/medicine/polypyr = 15) //This might be a bit much, reagent cost should be reviewed after implementation. + reaction_flags = REACTION_INSTANT reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_BRUTE /datum/chemical_reaction/medicine/medsuture/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -354,6 +355,7 @@ /datum/chemical_reaction/medicine/medmesh required_reagents = list(/datum/reagent/cellulose = 10, /datum/reagent/consumable/aloejuice = 20, /datum/reagent/space_cleaner/sterilizine = 10) + reaction_flags = REACTION_INSTANT reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_BURN /datum/chemical_reaction/medicine/medmesh/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) @@ -363,6 +365,7 @@ /datum/chemical_reaction/medicine/poultice required_reagents = list(/datum/reagent/toxin/bungotoxin = 20, /datum/reagent/cellulose = 20, /datum/reagent/consumable/aloejuice = 20) + reaction_flags = REACTION_INSTANT reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_BRUTE | REACTION_TAG_BURN /datum/chemical_reaction/medicine/poultice/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) From fabbdfcb023f7191f344cd753d170a6d218993c5 Mon Sep 17 00:00:00 2001 From: Bloop <13398309+vinylspiders@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:58:58 -0400 Subject: [PATCH 10/85] Fixes quirk config tooltips rendering behind the popper (#84269) ## About The Pull Request Essentially the same issue as https://github.com/tgstation/tgstation/pull/81571 , and the work has already been done for me there so I am just plugging in their solution. Shout out to MrMelbert for remembering this PR and pointing me in the right direction!! ## Why It's Good For The Game Fixes a prefs menu bug. --- tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx index 2dde5ab60cc5a..6a166bb06dbed 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx @@ -211,6 +211,7 @@ function QuirkPopper(props: QuirkPopperProps) { placement="bottom-end" onClickOutside={() => setCustomizationExpanded(false)} isOpen={customizationExpanded} + baseZIndex={1} content={
{!!customization_options && hasExpandableCustomization && ( From d3aca077330e2fcd719db3b4e879375b5504000b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 25 Jun 2024 08:59:29 +1200 Subject: [PATCH 11/85] Automatic changelog for PR #84139 [ci skip] --- html/changelogs/AutoChangeLog-pr-84139.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-84139.yml diff --git a/html/changelogs/AutoChangeLog-pr-84139.yml b/html/changelogs/AutoChangeLog-pr-84139.yml new file mode 100644 index 0000000000000..3f4f5a050da16 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84139.yml @@ -0,0 +1,4 @@ +author: "the-orange-cow" +delete-after: True +changes: + - bugfix: "Medicated suture, advanced regenerative mesh, and mourning poultice reactions should more consistently spawn the items they are meant to produce." \ No newline at end of file From 86ac773a692e04a3e9fb4839ed9e1d11271c276e Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 25 Jun 2024 08:59:47 +1200 Subject: [PATCH 12/85] Automatic changelog for PR #84269 [ci skip] --- html/changelogs/AutoChangeLog-pr-84269.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-84269.yml diff --git a/html/changelogs/AutoChangeLog-pr-84269.yml b/html/changelogs/AutoChangeLog-pr-84269.yml new file mode 100644 index 0000000000000..d5a3ba68b171c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84269.yml @@ -0,0 +1,4 @@ +author: "vinylspiders" +delete-after: True +changes: + - bugfix: "fixes an issue that was causing the quirk config tooltips to render behind the window, making them nearly impossible to read." \ No newline at end of file From 472fd3725795661898d22526586b4a829aa47954 Mon Sep 17 00:00:00 2001 From: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:00:43 -0400 Subject: [PATCH 13/85] Adds an admin secret to mass heal and revive everyone. (#84248) ## About The Pull Request Turns out, the only way to do this, if desired as an admin, is through SQL. And that's lame! So, this adds an admin secret to mass heal and revive everyone on the station with a mob. Not much else nuance to it really. ## Why It's Good For The Game Turns out we've been asking about it in bus for like, 3-4 years now? I was also asked about it in a round today, so here we go. --- code/modules/admin/verbs/secrets.dm | 19 +++++++++++++++++++ tgui/packages/tgui/interfaces/Secrets.jsx | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm index 379b9475dc50b..c124a5fba2266 100644 --- a/code/modules/admin/verbs/secrets.dm +++ b/code/modules/admin/verbs/secrets.dm @@ -604,6 +604,25 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w message_admins("[key_name_admin(holder)] [ctf_controller.instagib_mode ? "enabled" : "disabled"] instagib mode in CTF game: [selected_game]") log_admin("[key_name_admin(holder)] [ctf_controller.instagib_mode ? "enabled" : "disabled"] instagib mode in CTF game: [selected_game]") + if("mass_heal") + if(!is_funmin) + return + var/heal_mobs = tgui_alert(usr, "Heal all mobs and return ghosts to their bodies?", "Mass Healing", list("Yes", "No")) + if(!heal_mobs || heal_mobs != "Yes") + return + + for(var/mob/dead/observer/ghost in GLOB.player_list) //Return all ghosts if possible + if(!ghost.mind || !ghost.mind.current) //won't do anything if there is no body + continue + ghost.reenter_corpse() + + for(var/mob/living/player in GLOB.player_list) + player.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE) + + sound_to_playing_players('sound/effects/pray_chaplain.ogg') + message_admins("[key_name_admin(holder)] healed everyone.") + log_admin("[key_name(holder)] healed everyone.") + if(E) E.processing = FALSE if(E.announce_when>0) diff --git a/tgui/packages/tgui/interfaces/Secrets.jsx b/tgui/packages/tgui/interfaces/Secrets.jsx index ebd0b998d2c28..a0896ec750722 100644 --- a/tgui/packages/tgui/interfaces/Secrets.jsx +++ b/tgui/packages/tgui/interfaces/Secrets.jsx @@ -301,13 +301,13 @@ const FunTab = (props) => { /> - - Your admin button here, coder! - + content="Mass Heal everyone" + onClick={() => act('mass_heal')} + /> From c2b850a152a4a48f58efcf2c5b291657b57848d3 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 25 Jun 2024 09:01:29 +1200 Subject: [PATCH 14/85] Automatic changelog for PR #84248 [ci skip] --- html/changelogs/AutoChangeLog-pr-84248.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-84248.yml diff --git a/html/changelogs/AutoChangeLog-pr-84248.yml b/html/changelogs/AutoChangeLog-pr-84248.yml new file mode 100644 index 0000000000000..e4dc84bfa5e7c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84248.yml @@ -0,0 +1,4 @@ +author: "ArcaneMusic" +delete-after: True +changes: + - admin: "Admins have a new secret to mass revive and heal all players on the server." \ No newline at end of file From a85aabc97afb8c78b590fc10e70bf504cf36ad7d Mon Sep 17 00:00:00 2001 From: san7890 Date: Mon, 24 Jun 2024 15:02:47 -0600 Subject: [PATCH 15/85] Fixes non-sensical attack messages for certain mobs (#84195) ## About The Pull Request ![image](https://github.com/tgstation/tgstation/assets/34697715/4d56fc5f-b50c-45ac-9be4-da86929fbb96) There's a really long standing tradition in the code (at least 13 years old) that every mob should, at a base, be attacked in the chest. However, this can cause some strangeness for mobs that don't have chests (bots). Basically, what we do is we override this message so that bots don't get hit in the chest, because this proc will always require a zone input (and default input is the chest (and disentangling that will take more time that what I can afford)) so let's just hide the message to the user. this is also a nice thing to just have in general because a hook into the strike zone portion of the item attack message can have some pretty nice effects (e.g. what if you want to add on a descriptor of the head, or say eye for a creature that only has a eye for a head, or whatever). --- code/_onclick/item_attack.dm | 13 ++++++++++--- code/modules/mob/living/basic/bots/_bots.dm | 5 +++++ code/modules/mob/living/simple_animal/bot/bot.dm | 5 +++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index bb4cf4cd0299b..beeb1599f2038 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -458,9 +458,8 @@ return var/message_verb_continuous = length(I.attack_verb_continuous) ? "[pick(I.attack_verb_continuous)]" : "attacks" var/message_verb_simple = length(I.attack_verb_simple) ? "[pick(I.attack_verb_simple)]" : "attack" - var/message_hit_area = "" - if(hit_area) - message_hit_area = " in the [hit_area]" + var/message_hit_area = get_hit_area_message(hit_area) + var/attack_message_spectator = "[src] [message_verb_continuous][message_hit_area] with [I]!" var/attack_message_victim = "Something [message_verb_continuous] you[message_hit_area] with [I]!" var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [I]!" @@ -475,3 +474,11 @@ to_chat(src, span_danger("Someone hits you[message_hit_area]!")) to_chat(user, span_danger("[attack_message_attacker]")) return 1 + +/// Overridable proc so subtypes can have unique targetted strike zone messages, return a string. +/mob/living/proc/get_hit_area_message(input_area) + if(input_area) + return " in the [input_area]" + + return "" + diff --git a/code/modules/mob/living/basic/bots/_bots.dm b/code/modules/mob/living/basic/bots/_bots.dm index 03dc06dcda549..85cfdccf35fa4 100644 --- a/code/modules/mob/living/basic/bots/_bots.dm +++ b/code/modules/mob/living/basic/bots/_bots.dm @@ -814,6 +814,11 @@ GLOBAL_LIST_INIT(command_strings, list( /mob/living/basic/bot/spawn_gibs(drop_bitflags = NONE) new /obj/effect/gibspawner/robot(drop_location(), src) +/mob/living/basic/bot/get_hit_area_message(input_area) + // we just get hit, there's no complexity for hitting an arm (if it exists) or anything. + // we also need to return an empty string as otherwise it would falsely say that we get hit in the chest or something strange like that (bots don't have "chests") + return "" + /mob/living/basic/bot/proc/on_bot_movement(atom/movable/source, atom/oldloc, dir, forced) return diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 944a00af9b63e..c7507b677dc0b 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -1215,3 +1215,8 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/spawn_gibs(drop_bitflags = NONE) new /obj/effect/gibspawner/robot(drop_location(), src) + +/mob/living/simple_animal/bot/get_hit_area_message(input_area) + // we just get hit, there's no complexity for hitting an arm (if it exists) or anything. + // we also need to return an empty string as otherwise it would falsely say that we get hit in the chest or something strange like that (bots don't have "chests") + return "" From 01b63eb1cb2e0bc7a2271ba35e66cb70685a77a3 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 25 Jun 2024 09:03:18 +1200 Subject: [PATCH 16/85] Automatic changelog for PR #84195 [ci skip] --- html/changelogs/AutoChangeLog-pr-84195.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-84195.yml diff --git a/html/changelogs/AutoChangeLog-pr-84195.yml b/html/changelogs/AutoChangeLog-pr-84195.yml new file mode 100644 index 0000000000000..f8ea410db1f9b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84195.yml @@ -0,0 +1,4 @@ +author: "san7890" +delete-after: True +changes: + - bugfix: "You should no longer attack mobs that don't have a chest in the chest (bots)." \ No newline at end of file From c49ba598fca7e29d5b1e124123c7cd5b57640bb0 Mon Sep 17 00:00:00 2001 From: GoblinBackwards <22856555+GoblinBackwards@users.noreply.github.com> Date: Mon, 24 Jun 2024 22:03:51 +0100 Subject: [PATCH 17/85] Fixes some objects not being pulled with ctrl-click (#84190) ## About The Pull Request Fix for a bug where using ctrl-click to try to pull the bluespace gas sender and hydroponics tray isn't working. Seems to be broken since the ctrl-click refactor. Fixes #84222 ## Changelog :cl: fix: Fixed ctrl-click not dragging the bluespace gas sender or hydroponics trays. /:cl: --- .../machinery/components/unary_devices/bluespace_sender.dm | 5 +++-- code/modules/hydroponics/hydroponics.dm | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm b/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm index 6957389c351b7..ebe053663f9e0 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm @@ -61,7 +61,8 @@ GLOBAL_LIST_EMPTY_TYPED(bluespace_senders, /obj/machinery/atmospherics/component /obj/machinery/atmospherics/components/unary/bluespace_sender/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() - context[SCREENTIP_CONTEXT_CTRL_LMB] = "Turn [on ? "off" : "on"]" + if(anchored && !panel_open && is_operational) + context[SCREENTIP_CONTEXT_CTRL_LMB] = "Turn [on ? "off" : "on"]" if(!held_item) return CONTEXTUAL_SCREENTIP_SET switch(held_item.tool_behaviour) @@ -156,7 +157,7 @@ GLOBAL_LIST_EMPTY_TYPED(bluespace_senders, /obj/machinery/atmospherics/component investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS) update_appearance() return CLICK_ACTION_SUCCESS - return CLICK_ACTION_BLOCKING + return NONE /obj/machinery/atmospherics/components/unary/bluespace_sender/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 3f47982e16ee9..791b7ac51a253 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -1088,12 +1088,12 @@ user.examinate(src) /obj/machinery/hydroponics/click_ctrl(mob/user) + if(!anchored) + return NONE if(!powered()) to_chat(user, span_warning("[name] has no power.")) update_use_power(NO_POWER_USE) return CLICK_ACTION_BLOCKING - if(!anchored) - return CLICK_ACTION_BLOCKING set_self_sustaining(!self_sustaining) to_chat(user, span_notice("You [self_sustaining ? "activate" : "deactivated"] [src]'s autogrow function[self_sustaining ? ", maintaining the tray's health while using high amounts of power" : ""].")) return CLICK_ACTION_SUCCESS From 1f4fff4f5f66cfe4446a85e0c737f95785d490e1 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 25 Jun 2024 09:04:17 +1200 Subject: [PATCH 18/85] Automatic changelog for PR #84190 [ci skip] --- html/changelogs/AutoChangeLog-pr-84190.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-84190.yml diff --git a/html/changelogs/AutoChangeLog-pr-84190.yml b/html/changelogs/AutoChangeLog-pr-84190.yml new file mode 100644 index 0000000000000..b685dd6db6c1c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84190.yml @@ -0,0 +1,4 @@ +author: "GoblinBackwards" +delete-after: True +changes: + - bugfix: "Fixed ctrl-click not dragging the bluespace gas sender or hydroponics trays." \ No newline at end of file From a30a4fef827a1eea70e34050859039d73af647e3 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Tue, 25 Jun 2024 02:34:36 +0530 Subject: [PATCH 19/85] [NO GBP] Piggyback ,strip menu & Paraplegic mouse drop fixes (#84268) ## About The Pull Request - Fixes #84267 - Fixes #84264 - Fixes #84218 Adds `ALLOW_RESTING` to these actions. This should also fix some other cases of mouse drop w are not aware of since it's at the `mob/living` level. Also improved feedback messages for when an action cannot be performed to help in debugging --- code/datums/elements/strippable.dm | 2 +- code/modules/mob/living/living.dm | 6 +++--- code/modules/mob/living/living_defines.dm | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/code/datums/elements/strippable.dm b/code/datums/elements/strippable.dm index fc952b8a9e23c..1b932ce066590 100644 --- a/code/datums/elements/strippable.dm +++ b/code/datums/elements/strippable.dm @@ -40,7 +40,7 @@ return if (over != user) return - if(!user.can_perform_action(source, FORBID_TELEKINESIS_REACH)) + if(!user.can_perform_action(source, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) return // Cyborgs buckle people by dragging them onto them, unless in combat mode. diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index df15d979836b6..54fce885a8056 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1333,16 +1333,16 @@ // Note - AI's and borgs have the MOBILITY_UI bitflag set even though they don't have hands // Also if it is not set, the mob could be incapcitated, knocked out, unconscious, asleep, EMP'd, etc. if(!(mobility_flags & MOBILITY_UI) && !(action_bitflags & ALLOW_RESTING)) - to_chat(src, span_warning("You can't do that right now!")) + to_chat(src, span_warning("You don't have the mobility for this!")) return FALSE // NEED_HANDS is already checked by MOBILITY_UI for humans so this is for silicons if((action_bitflags & NEED_HANDS)) if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED)) - to_chat(src, span_warning("You can't do that right now!")) + to_chat(src, span_warning("You hands are blocked for this action!")) return FALSE if(!can_hold_items(isitem(target) ? target : null)) // almost redundant if it weren't for mobs - to_chat(src, span_warning("You don't have the physical ability to do this!")) + to_chat(src, span_warning("You don't have the hands for this action!")) return FALSE if(!(action_bitflags & BYPASS_ADJACENCY) && !recursive_loc_check(src, target) && !CanReach(target)) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index acc49dd572145..0b844a2362afb 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -3,6 +3,7 @@ hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD) pressure_resistance = 10 hud_type = /datum/hud/living + interaction_flags_mouse_drop = ALLOW_RESTING ///Tracks the current size of the mob in relation to its original size. Use update_transform(resize) to change it. var/current_size = RESIZE_DEFAULT_SIZE From 47d0b4b70d575a3a98ef9e51e835fd9b645b78f6 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 25 Jun 2024 00:04:50 +0300 Subject: [PATCH 20/85] NT Frontier can read files from data disks (#84189) ## About The Pull Request Made the NT Frontier app look for valid experiment files not only on the local file system, but also on the data disk. ## Why It's Good For The Game Less clicks. ## Changelog :cl: qol: NT Frontier app now allows to select experiments from inserted data disks /:cl: --- code/modules/modular_computers/computers/item/computer.dm | 6 ++++++ .../modular_computers/file_system/programs/frontier.dm | 6 +++--- tgui/packages/tgui/interfaces/NtosScipaper.jsx | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 0e2071a84b910..f9d86609012be 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -962,6 +962,12 @@ update_appearance(UPDATE_ICON) return TRUE +/// Get all stored files, including external disk files optionaly +/obj/item/modular_computer/proc/get_files(include_disk_files = FALSE) + if(!include_disk_files || !inserted_disk) + return stored_files + return stored_files + inserted_disk.stored_files + /** * Debug ModPC * Used to spawn all programs for Create and Destroy unit test. diff --git a/code/modules/modular_computers/file_system/programs/frontier.dm b/code/modules/modular_computers/file_system/programs/frontier.dm index 7a65513508d3e..53ce4128729b5 100644 --- a/code/modules/modular_computers/file_system/programs/frontier.dm +++ b/code/modules/modular_computers/file_system/programs/frontier.dm @@ -33,7 +33,7 @@ return TRUE /datum/computer_file/program/scipaper_program/proc/recheck_file_presence() - if(selected_file in computer.stored_files) + if(selected_file in computer.get_files(include_disk_files = TRUE)) return FALSE UnregisterSignal(selected_file, COMSIG_COMPUTER_FILE_DELETE) selected_file = null @@ -92,7 +92,7 @@ data["allowedTiers"] = list() data["allowedPartners"] = list() // Both the file and experiment list are assoc lists. ID as value, display name as keys. - for(var/datum/computer_file/data/ordnance/ordnance_file in computer.stored_files) + for(var/datum/computer_file/data/ordnance/ordnance_file in computer.get_files(include_disk_files = TRUE)) data["fileList"] += list(ordnance_file.filename = ordnance_file.uid) if(selected_file) for (var/possible_experiment in selected_file.possible_experiments) @@ -189,7 +189,7 @@ if(selected_file) UnregisterSignal(selected_file, COMSIG_COMPUTER_FILE_DELETE) paper_to_be.set_experiment() // Clears the paper info. - for(var/datum/computer_file/data/ordnance/ordnance_data in computer.stored_files) + for(var/datum/computer_file/data/ordnance/ordnance_data in computer.get_files(include_disk_files = TRUE)) if(ordnance_data.uid == params["selected_uid"]) selected_file = ordnance_data RegisterSignal(selected_file, COMSIG_COMPUTER_FILE_DELETE, PROC_REF(recheck_file_presence)) diff --git a/tgui/packages/tgui/interfaces/NtosScipaper.jsx b/tgui/packages/tgui/interfaces/NtosScipaper.jsx index 4d12fdc638931..f6636e0fd6757 100644 --- a/tgui/packages/tgui/interfaces/NtosScipaper.jsx +++ b/tgui/packages/tgui/interfaces/NtosScipaper.jsx @@ -50,7 +50,7 @@ const PaperPublishing = (props) => {
{fileList.length === 0 && ( - Use the File Manager app to download files from a disk. + Use data disk to download files from compressor or doppler array. )} @@ -58,7 +58,7 @@ const PaperPublishing = (props) => { label="File (required)" buttons={