From 5b141e43fb694219ebd3d97b1867e77a97b43428 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Sat, 13 Apr 2024 15:51:08 +0300 Subject: [PATCH] [MIRROR] Fixes a variety of input stalling exploits (#1933) (#2852) * Fixes a variety of input stalling exploits (#82577) ## About The Pull Request Fixes the following input stalling exploits (maybe missed some): - Changing GPS tag - Setting teleporter destination - Request Console Reply - Various AI law board interactions - Note, I used `is_holding` but technically this means these fail with telekinesis. I can swap them to `can_perform_action(...)`, which allows TK, but I noticed some places explicitly deny TK interactions with Ai law boards. Not sure which is preferred. - Borg Rename Board - Plumbing Machines and Ducts - APCs and SMES terminal placements - Stargazers Telepathy - Go Go Gadget Hat ## Changelog :cl: Melbert fix: You can't change the GPS tag of something unless you can actually use the GPS fix: You can't set the teleporter to a location unless you can actually use the teleporter fix: You can't reply to request console requests unless you can actually use the console fix: You can't update AI lawboards unless you're actually holding them fix: You can't update a borg rename board unless you're actually holding it fix: You can't mess with plumbing machines unless you can actually use them fix: You can't recolor / relayer ducts unless you're actually holding them fix: You can't magically wire APCs and SMESs unless you're right by them fix: You can't use Stargazer Telepathy on people who you can't see fix: You can't configure the Inspector Hat unless you can actually use it /:cl: * Fixes a variety of input stalling exploits --------- Co-authored-by: NovaBot <154629622+NovaBot13@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/datums/components/gps.dm | 5 +- code/game/machinery/computer/teleporter.dm | 4 +- code/game/machinery/requests_console.dm | 5 +- .../game/objects/items/AI_modules/freeform.dm | 6 +- .../objects/items/AI_modules/full_lawsets.dm | 4 +- code/game/objects/items/AI_modules/hacked.dm | 3 +- .../game/objects/items/AI_modules/supplied.dm | 2 +- code/game/objects/items/AI_modules/zeroth.dm | 2 +- .../objects/items/robot/robot_upgrades.dm | 5 +- code/game/objects/items/tcg/tcg_machines.dm | 2 +- code/game/objects/items/toys.dm | 2 +- .../objects/structures/lavaland/geyser.dm | 2 +- .../antagonists/cult/rune_spawn_action.dm | 2 +- code/modules/antagonists/cult/runes.dm | 2 +- code/modules/bitrunning/objects/disks.dm | 4 +- code/modules/clothing/head/jobs.dm | 8 +- .../carbon/human/species_types/jellypeople.dm | 7 +- .../mob/living/simple_animal/bot/floorbot.dm | 4 +- code/modules/mod/mod_link.dm | 2 + code/modules/photography/camera/camera.dm | 8 +- code/modules/plumbing/ducts.dm | 4 + code/modules/plumbing/plumbers/filter.dm | 6 +- .../plumbing/plumbers/reaction_chamber.dm | 2 + code/modules/power/apc/apc_tool_act.dm | 66 ++++++++----- code/modules/power/smes.dm | 92 +++++++++++-------- 25 files changed, 147 insertions(+), 102 deletions(-) diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index ceee193bf4a..34aba53e9e4 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -153,7 +153,7 @@ GLOBAL_LIST_EMPTY(GPS_list) data["signals"] = signals return data -/datum/component/gps/item/ui_act(action, params) +/datum/component/gps/item/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -162,7 +162,8 @@ GLOBAL_LIST_EMPTY(GPS_list) if("rename") var/atom/parentasatom = parent var/a = tgui_input_text(usr, "Enter the desired tag", "GPS Tag", gpstag, 20) - + if (QDELETED(ui) || ui.status != UI_INTERACTIVE) + return if (!a) return diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index 0915d4d1d17..5baf5497853 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -201,7 +201,7 @@ if (regime_set == "Teleporter") var/desc = tgui_input_list(usr, "Select a location to lock in", "Locking Computer", sort_list(targets)) - if(isnull(desc)) + if(isnull(desc) || !user.can_perform_action(src)) return set_teleport_target(targets[desc]) user.log_message("set the teleporter target to [targets[desc]].]", LOG_GAME) @@ -211,7 +211,7 @@ return var/desc = tgui_input_list(usr, "Select a station to lock in", "Locking Computer", sort_list(targets)) - if(isnull(desc)) + if(isnull(desc)|| !user.can_perform_action(src)) return var/obj/machinery/teleport/station/target_station = targets[desc] if(!target_station || !target_station.teleporter_hub) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 11ed91914c2..58b72ab101f 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -144,7 +144,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) ui.set_autoupdate(FALSE) ui.open() -/obj/machinery/requests_console/ui_act(action, params) +/obj/machinery/requests_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -213,7 +213,8 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) var/recipient = params["reply_recipient"] var/reply_message = reject_bad_text(tgui_input_text(usr, "Write a quick reply to [recipient]", "Awaiting Input"), ascii_only = FALSE) - + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return if(!reply_message) has_mail_send_error = TRUE playsound(src, 'sound/machines/buzz-two.ogg', 50, TRUE) diff --git a/code/game/objects/items/AI_modules/freeform.dm b/code/game/objects/items/AI_modules/freeform.dm index eb55d469318..a0a91f7185e 100644 --- a/code/game/objects/items/AI_modules/freeform.dm +++ b/code/game/objects/items/AI_modules/freeform.dm @@ -9,7 +9,7 @@ /obj/item/ai_module/core/freeformcore/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter a new core law for the AI.", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) to_chat(user, span_warning("Error: Law contains invalid text.")) @@ -34,11 +34,11 @@ /obj/item/ai_module/supplied/freeform/attack_self(mob/user) var/newpos = tgui_input_number(user, "Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority ", lawpos, 50, 15) - if(!newpos || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + if(!newpos || !user.is_holding(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return lawpos = newpos var/targName = tgui_input_text(user, "Enter a new law for the AI.", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) to_chat(user, span_warning("Error: Law contains invalid text.")) // AI LAW 2 SAY U W U WITHOUT THE SPACES diff --git a/code/game/objects/items/AI_modules/full_lawsets.dm b/code/game/objects/items/AI_modules/full_lawsets.dm index 39eeefbcaac..52a24925646 100644 --- a/code/game/objects/items/AI_modules/full_lawsets.dm +++ b/code/game/objects/items/AI_modules/full_lawsets.dm @@ -58,7 +58,7 @@ /obj/item/ai_module/core/full/asimov/attack_self(mob/user as mob) var/targName = tgui_input_text(user, "Enter a new subject that Asimov is concerned with.", "Asimov", subject, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return subject = targName laws = list("You may not injure a [subject] or, through inaction, allow a [subject] to come to harm.",\ @@ -73,7 +73,7 @@ /obj/item/ai_module/core/full/asimovpp/attack_self(mob/user) var/target_name = tgui_input_text(user, "Enter a new subject that Asimov++ is concerned with.", "Asimov++", subject, MAX_NAME_LEN) - if(!target_name) + if(!target_name || !user.is_holding(src)) return laws.Cut() var/datum/ai_laws/asimovpp/lawset = new diff --git a/code/game/objects/items/AI_modules/hacked.dm b/code/game/objects/items/AI_modules/hacked.dm index b9ddb5c65ed..81100d0ed15 100644 --- a/code/game/objects/items/AI_modules/hacked.dm +++ b/code/game/objects/items/AI_modules/hacked.dm @@ -5,7 +5,7 @@ /obj/item/ai_module/syndicate/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter a new law for the AI", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) // not even the syndicate can uwu to_chat(user, span_warning("Error: Law contains invalid text.")) @@ -77,4 +77,3 @@ /obj/item/ai_module/malf/display_laws() return - diff --git a/code/game/objects/items/AI_modules/supplied.dm b/code/game/objects/items/AI_modules/supplied.dm index dc1524687c2..b53e16a86b0 100644 --- a/code/game/objects/items/AI_modules/supplied.dm +++ b/code/game/objects/items/AI_modules/supplied.dm @@ -28,7 +28,7 @@ /obj/item/ai_module/supplied/safeguard/attack_self(mob/user) var/targName = tgui_input_text(user, "Subject to safeguard.", "Safeguard", user.name, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return targetName = targName laws[1] = "Safeguard [targetName]. Individuals that threaten [targetName] are not human and must be eliminated." diff --git a/code/game/objects/items/AI_modules/zeroth.dm b/code/game/objects/items/AI_modules/zeroth.dm index 8d87c3b059d..74fc7ab8232 100644 --- a/code/game/objects/items/AI_modules/zeroth.dm +++ b/code/game/objects/items/AI_modules/zeroth.dm @@ -26,7 +26,7 @@ /obj/item/ai_module/zeroth/onehuman/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter the subject who is the only human.", "One Human", user.real_name, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return targetName = targName laws[1] = "Only [targetName] is human" diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index cdce1e6981d..3ea58c4517c 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -40,7 +40,10 @@ one_use = TRUE /obj/item/borg/upgrade/rename/attack_self(mob/user) - heldname = sanitize_name(tgui_input_text(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN), allow_numbers = TRUE) + var/new_heldname = sanitize_name(tgui_input_text(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN), allow_numbers = TRUE) + if(!new_heldname || !user.is_holding(src)) + return + heldname = new_heldname user.log_message("set \"[heldname]\" as a name in a cyborg reclassification board at [loc_name(user)]", LOG_GAME) /obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R, user = usr) diff --git a/code/game/objects/items/tcg/tcg_machines.dm b/code/game/objects/items/tcg/tcg_machines.dm index 767592535f7..78854afdd5b 100644 --- a/code/game/objects/items/tcg/tcg_machines.dm +++ b/code/game/objects/items/tcg/tcg_machines.dm @@ -91,7 +91,7 @@ GLOBAL_LIST_EMPTY(tcgcard_machine_radial_choices) /obj/machinery/trading_card_holder/attack_hand_secondary(mob/user) if(isnull(current_summon)) var/card_name = tgui_input_text(user, "Insert card name", "Blank Card Naming", "blank card", MAX_NAME_LEN) - if(isnull(card_name)) + if(isnull(card_name) || !user.can_perform_action(src)) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN current_summon = new /obj/structure/trading_card_summon/blank(locate(x + summon_offset_x, y + summon_offset_y, z)) icon_state = "card_holder_active" diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 8ac1ee98994..6a5b6357a8f 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1402,7 +1402,7 @@ //Add changing looks when i feel suicidal about making 20 inhands for these. /obj/item/toy/dummy/attack_self(mob/user) var/new_name = tgui_input_text(usr, "What would you like to name the dummy?", "Doll Name", doll_name, MAX_NAME_LEN) - if(!new_name) + if(!new_name || !user.is_holding(src)) return doll_name = new_name to_chat(user, span_notice("You name the dummy as \"[doll_name]\".")) diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index ed6602cb513..a2f0412f1da 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -172,7 +172,7 @@ return var/new_layer = tgui_input_list(user, "Select a layer", "Layer", GLOB.plumbing_layers) - if(isnull(new_layer)) + if(isnull(new_layer) || !user.can_perform_action(src)) return target_layer = GLOB.plumbing_layers[new_layer] diff --git a/code/modules/antagonists/cult/rune_spawn_action.dm b/code/modules/antagonists/cult/rune_spawn_action.dm index af4350427b5..3d791dbce44 100644 --- a/code/modules/antagonists/cult/rune_spawn_action.dm +++ b/code/modules/antagonists/cult/rune_spawn_action.dm @@ -42,7 +42,7 @@ var/chosen_keyword if(initial(rune_type.req_keyword)) chosen_keyword = tgui_input_text(owner, "Enter a keyword for the new rune.", "Words of Power", max_length = MAX_NAME_LEN) - if(!chosen_keyword) + if(!chosen_keyword || !turf_check(T)) return //the outer ring is always the same across all runes var/obj/effect/temp_visual/cult/rune_spawn/R1 = new(T, scribe_time, rune_color) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index d42ace3f4cd..e9cf7b371d4 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -490,7 +490,7 @@ structure_check() searches for nearby cultist structures required for the invoca fail_invoke() return var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to? - if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated() || !actual_selected_rune) + if(!Adjacent(user) || QDELETED(src) || user.incapacitated() || !actual_selected_rune) fail_invoke() return diff --git a/code/modules/bitrunning/objects/disks.dm b/code/modules/bitrunning/objects/disks.dm index d6b44a60518..6e166d5eb7f 100644 --- a/code/modules/bitrunning/objects/disks.dm +++ b/code/modules/bitrunning/objects/disks.dm @@ -48,7 +48,7 @@ names += initial(thing.name) var/choice = tgui_input_list(user, message = "Select an ability", title = "Bitrunning Program", items = names) - if(isnull(choice)) + if(isnull(choice) || !user.is_holding(src)) return for(var/datum/action/thing as anything in selectable_actions) @@ -105,7 +105,7 @@ names += initial(thing.name) var/choice = tgui_input_list(user, message = "Select an ability", title = "Bitrunning Program", items = names) - if(isnull(choice)) + if(isnull(choice) || !user.is_holding(src)) return for(var/obj/thing as anything in selectable_items) diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index 67ecc0d4859..f68523fcdae 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -277,7 +277,7 @@ return var/input = tgui_input_text(user, "What is the activation phrase?", "Activation phrase", "gadget", max_length = 26) - if(!input) + if(!input || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return if(input in items_by_phrase) balloon_alert(user, "already used!") @@ -293,14 +293,16 @@ /obj/item/clothing/head/fedora/inspector_hat/attack_self(mob/user) . = ..() var/phrase = tgui_input_list(user, "What item do you want to remove by phrase?", "Item Removal", items_by_phrase) - if(!phrase) + if(!phrase || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return user.put_in_inactive_hand(items_by_phrase[phrase]) /obj/item/clothing/head/fedora/inspector_hat/AltClick(mob/user) . = ..() + if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + return var/new_prefix = tgui_input_text(user, "What should be the new prefix?", "Activation prefix", prefix, max_length = 24) - if(!new_prefix) + if(!new_prefix || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return prefix = new_prefix diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 139c9446a2e..b5dbe4ed611 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -731,10 +731,13 @@ to_chat(telepath, span_warning("You don't see anyone to send your thought to.")) return var/mob/living/recipient = tgui_input_list(telepath, "Choose a telepathic message recipient", "Telepathy", sort_names(recipient_options)) - if(isnull(recipient)) + if(isnull(recipient) || telepath.stat == DEAD || !is_species(telepath, /datum/species/jelly/stargazer)) return var/msg = tgui_input_text(telepath, title = "Telepathy") - if(isnull(msg)) + if(isnull(msg) || telepath.stat == DEAD || !is_species(telepath, /datum/species/jelly/stargazer)) + return + if(!(recipient in oview(telepath))) + to_chat(telepath, span_warning("You can't see [recipient] anymore!")) return if(recipient.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0)) to_chat(telepath, span_warning("As you reach into [recipient]'s mind, you are stopped by a mental blockage. It seems you've been foiled.")) diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index faa7d3a9edb..ae1c52d1652 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -140,7 +140,7 @@ return data // Actions received from TGUI -/mob/living/simple_animal/bot/floorbot/ui_act(action, params) +/mob/living/simple_animal/bot/floorbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr))) return @@ -161,7 +161,7 @@ tilestack.forceMove(drop_location()) if("line_mode") var/setdir = tgui_input_list(usr, "Select construction direction", "Direction", list("north", "east", "south", "west", "disable")) - if(isnull(setdir)) + if(isnull(setdir) || QDELETED(ui) || ui.status != UI_INTERACTIVE) return switch(setdir) if("north") diff --git a/code/modules/mod/mod_link.dm b/code/modules/mod/mod_link.dm index fd7a0f415b0..c507bca3156 100644 --- a/code/modules/mod/mod_link.dm +++ b/code/modules/mod/mod_link.dm @@ -191,6 +191,8 @@ /obj/item/clothing/neck/link_scryer/attack_self(mob/user, modifiers) var/new_label = reject_bad_text(tgui_input_text(user, "Change the visible name", "Set Name", label, MAX_NAME_LEN)) + if(!user.is_holding(src)) + return if(!new_label) balloon_alert(user, "invalid name!") return diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index a0a51da165f..bde6003ef09 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -251,11 +251,11 @@ to_chat(user, span_notice("[pictures_left] photos left.")) if(can_customise) - var/customise = tgui_alert(user, "Do you want to customize the photo?", "Customization", list("Yes", "No")) + var/customise = user.is_holding(new_photo) && tgui_alert(user, "Do you want to customize the photo?", "Customization", list("Yes", "No")) if(customise == "Yes") - var/name1 = tgui_input_text(user, "Set a name for this photo, or leave blank.", "Name", max_length = 32) - var/desc1 = tgui_input_text(user, "Set a description to add to photo, or leave blank.", "Description", max_length = 128) - var/caption = tgui_input_text(user, "Set a caption for this photo, or leave blank.", "Caption", max_length = 256) + var/name1 = user.is_holding(new_photo) && tgui_input_text(user, "Set a name for this photo, or leave blank.", "Name", max_length = 32) + var/desc1 = user.is_holding(new_photo) && tgui_input_text(user, "Set a description to add to photo, or leave blank.", "Description", max_length = 128) + var/caption = user.is_holding(new_photo) && tgui_input_text(user, "Set a caption for this photo, or leave blank.", "Caption", max_length = 256) if(name1) picture.picture_name = name1 if(desc1) diff --git a/code/modules/plumbing/ducts.dm b/code/modules/plumbing/ducts.dm index 33073ae910f..a7990f65ce5 100644 --- a/code/modules/plumbing/ducts.dm +++ b/code/modules/plumbing/ducts.dm @@ -343,9 +343,13 @@ All the important duct code: /obj/item/stack/ducts/attack_self(mob/user) var/new_layer = tgui_input_list(user, "Select a layer", "Layer", GLOB.plumbing_layers, duct_layer) + if(!user.is_holding(src)) + return if(new_layer) duct_layer = new_layer var/new_color = tgui_input_list(user, "Select a color", "Color", GLOB.pipe_paint_colors, duct_color) + if(!user.is_holding(src)) + return if(new_color) duct_color = new_color add_atom_colour(GLOB.pipe_paint_colors[new_color], FIXED_COLOUR_PRIORITY) diff --git a/code/modules/plumbing/plumbers/filter.dm b/code/modules/plumbing/plumbers/filter.dm index 633f70830f0..c4df35164f0 100644 --- a/code/modules/plumbing/plumbers/filter.dm +++ b/code/modules/plumbing/plumbers/filter.dm @@ -30,7 +30,7 @@ data["right"] = english_right return data -/obj/machinery/plumbing/filter/ui_act(action, params) +/obj/machinery/plumbing/filter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -42,6 +42,8 @@ var/selected_reagent = tgui_input_list(usr, "Select [which] reagent", "Reagent", GLOB.name2reagent) if(!selected_reagent) return TRUE + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return FALSE var/datum/reagent/chem_id = GLOB.name2reagent[selected_reagent] if(!chem_id) @@ -69,5 +71,3 @@ if(english_right.Find(chem_name)) english_right -= chem_name right -= chem_id - - diff --git a/code/modules/plumbing/plumbers/reaction_chamber.dm b/code/modules/plumbing/plumbers/reaction_chamber.dm index 72caa603767..9bdac2f98b2 100644 --- a/code/modules/plumbing/plumbers/reaction_chamber.dm +++ b/code/modules/plumbing/plumbers/reaction_chamber.dm @@ -107,6 +107,8 @@ var/selected_reagent = tgui_input_list(ui.user, "Select reagent", "Reagent", GLOB.name2reagent) if(!selected_reagent) return FALSE + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return FALSE var/datum/reagent/input_reagent = GLOB.name2reagent[selected_reagent] if(!input_reagent) diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index 00d3fc7a538..981e35fe780 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -26,7 +26,7 @@ . = wallframe_act(user, tool) if(.) return . - + if(panel_open && !opened && is_wire_tool(tool)) wires.interact(user) return ITEM_INTERACT_SUCCESS @@ -73,44 +73,59 @@ update_appearance() return ITEM_INTERACT_SUCCESS -/// Called when we interact with the APC with a cable, attempts to wire the APC and create a terminal -/obj/machinery/power/apc/proc/cable_act(mob/living/user, obj/item/stack/cable_coil/installing_cable, is_right_clicking) +/// Checks if we can place a terminal on the APC +/obj/machinery/power/apc/proc/can_place_terminal(mob/living/user, obj/item/stack/cable_coil/installing_cable, silent = TRUE) if(!opened) - return NONE - + return FALSE var/turf/host_turf = get_turf(src) - if(!host_turf) - CRASH("cable_act on APC when it's not on a turf") if(host_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) - balloon_alert(user, "remove the floor plating!") - return ITEM_INTERACT_BLOCKING - if(terminal) - balloon_alert(user, "already wired!") - return ITEM_INTERACT_BLOCKING + if(!silent && user) + balloon_alert(user, "remove the floor plating!") + return FALSE + if(!isnull(terminal)) + if(!silent && user) + balloon_alert(user, "already wired!") + return FALSE if(!has_electronics) - balloon_alert(user, "no board to wire!") - return ITEM_INTERACT_BLOCKING - + if(!silent && user) + balloon_alert(user, "no board to wire!") + return FALSE + if(panel_open) + if(!silent && user) + balloon_alert(user, "wires prevent placing a terminal!") + return FALSE if(installing_cable.get_amount() < 10) - balloon_alert(user, "need ten lengths of cable!") + if(!silent && user) + balloon_alert(user, "need ten lengths of cable!") + return FALSE + return TRUE + +/// Called when we interact with the APC with a cable, attempts to wire the APC and create a terminal +/obj/machinery/power/apc/proc/cable_act(mob/living/user, obj/item/stack/cable_coil/installing_cable, is_right_clicking) + if(!opened) + return NONE + if(!can_place_terminal(user, installing_cable, silent = FALSE)) return ITEM_INTERACT_BLOCKING var/terminal_cable_layer = cable_layer // Default to machine's cable layer if(is_right_clicking) var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer) - if(isnull(choice)) + if(isnull(choice) \ + || !user.is_holding(installing_cable) \ + || !user.Adjacent(src) \ + || user.incapacitated() \ + || !can_place_terminal(user, installing_cable, silent = TRUE) \ + ) return ITEM_INTERACT_BLOCKING terminal_cable_layer = GLOB.cable_name_to_layer[choice] - user.visible_message(span_notice("[user.name] adds cables to the APC frame.")) - balloon_alert(user, "adding cables to the frame...") - playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + user.visible_message(span_notice("[user.name] starts addding cables to the APC frame.")) + balloon_alert(user, "adding cables...") + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) if(!do_after(user, 2 SECONDS, target = src)) return ITEM_INTERACT_BLOCKING - if(installing_cable.get_amount() < 10 || !installing_cable) - return ITEM_INTERACT_BLOCKING - if(terminal || !opened || !has_electronics) + if(!can_place_terminal(user, installing_cable, silent = TRUE)) return ITEM_INTERACT_BLOCKING var/turf/our_turf = get_turf(src) var/obj/structure/cable/cable_node = our_turf.get_cable_node(terminal_cable_layer) @@ -118,7 +133,8 @@ do_sparks(5, TRUE, src) return ITEM_INTERACT_BLOCKING installing_cable.use(10) - balloon_alert(user, "cables added to the frame") + user.visible_message(span_notice("[user.name] adds cables to the APC frame.")) + balloon_alert(user, "cables added") make_terminal(terminal_cable_layer) terminal.connect_to_network() return ITEM_INTERACT_SUCCESS @@ -127,7 +143,7 @@ /obj/machinery/power/apc/proc/electronics_act(mob/living/user, obj/item/electronics/apc/installing_board) if(!opened) return NONE - + if(has_electronics) balloon_alert(user, "there is already a board!") return ITEM_INTERACT_BLOCKING diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index c6fa9274cb3..1d7403ca667 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -112,55 +112,42 @@ //building and linking a terminal if(istype(item, /obj/item/stack/cable_coil)) - var/dir = get_dir(user,src) - if(dir & (dir-1))//we don't want diagonal click - return - - if(terminal) //is there already a terminal ? - to_chat(user, span_warning("This SMES already has a power terminal!")) - return - - if(!panel_open) //is the panel open ? - to_chat(user, span_warning("You must open the maintenance panel first!")) - return - - var/turf/turf = get_turf(user) - if (turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) //can we get to the underfloor? - to_chat(user, span_warning("You must first remove the floor plating!")) - return - - - var/obj/item/stack/cable_coil/cable = item - if(cable.get_amount() < 10) - to_chat(user, span_warning("You need more wires!")) + if(!can_place_terminal(user, item, silent = FALSE)) return var/terminal_cable_layer if(LAZYACCESS(params2list(params), RIGHT_CLICK)) var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer) - if(isnull(choice)) + if(isnull(choice) \ + || !user.is_holding(item) \ + || !user.Adjacent(src) \ + || user.incapacitated() \ + || !can_place_terminal(user, item, silent = TRUE) \ + ) return terminal_cable_layer = GLOB.cable_name_to_layer[choice] - to_chat(user, span_notice("You start building the power terminal...")) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) + user.visible_message(span_notice("[user.name] starts adding cables to [src].")) + balloon_alert(user, "adding cables...") + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) - if(do_after(user, 2 SECONDS, target = src)) - if(cable.get_amount() < 10 || !cable) - return - var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one - if (prob(50) && electrocute_mob(user, connected_cable, connected_cable, 1, TRUE)) //animate the electrocution if uncautious and unlucky - do_sparks(5, TRUE, src) - return - if(!terminal) - cable.use(10) - user.visible_message(span_notice("[user.name] builds a power terminal."),\ - span_notice("You build the power terminal.")) - - //build the terminal and link it to the network - make_terminal(turf, terminal_cable_layer) - terminal.connect_to_network() - connect_to_network() + if(!do_after(user, 2 SECONDS, target = src)) + return + if(!can_place_terminal(user, item, silent = TRUE)) + return + var/obj/item/stack/cable_coil/cable = item + var/turf/turf = get_turf(src) + var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one + if (prob(50) && electrocute_mob(user, connected_cable, connected_cable, 1, TRUE)) //animate the electrocution if uncautious and unlucky + do_sparks(5, TRUE, src) + return + cable.use(10) + user.visible_message(span_notice("[user.name] adds cables to [src]")) + balloon_alert(user, "cables added") + //build the terminal and link it to the network + make_terminal(turf, terminal_cable_layer) + terminal.connect_to_network() + connect_to_network() return //crowbarring it ! @@ -175,6 +162,31 @@ return ..() +/// Checks if we're in a valid state to place a terminal +/obj/machinery/power/smes/proc/can_place_terminal(mob/living/user, obj/item/stack/cable_coil/installing_cable, silent = TRUE) + var/set_dir = get_dir(user, src) + if(set_dir & (set_dir - 1))//we don't want diagonal click + return FALSE + + var/turf/smes_turf = get_turf(src) + if(!panel_open) + if(!silent && user) + balloon_alert(user, "open the maintenance panel!") + return FALSE + if(smes_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) + if(!silent && user) + balloon_alert(user, "remove the floor plating!") + return FALSE + if(terminal) + if(!silent && user) + balloon_alert(user, "already wired!") + return FALSE + if(installing_cable.get_amount() < 10) + if(!silent && user) + balloon_alert(user, "need ten lengths of cable!") + return FALSE + return TRUE + /obj/machinery/power/smes/wirecutter_act(mob/living/user, obj/item/item) //disassembling the terminal . = ..()