From 63e2f45ed3d5a9f736c4b0d23ecf0f33b1afbf1b Mon Sep 17 00:00:00 2001 From: DrTuxedo <42353186+DrDiasyl@users.noreply.github.com> Date: Sun, 21 Jul 2024 04:35:45 +0500 Subject: [PATCH] TSA: Scanner Gates and N-Spector update (#85077) ## About The Pull Request Scanner gates now have a much-refined sprite with dirs. https://github.com/user-attachments/assets/22659e12-5565-4feb-a8e7-0f1a56c4a99e _The message in the video is outdated, now working with the formula `src.say("[detected_thing][reverse ? " not ": " "]detected!!")`_ Scanner gates now can have false positive/negative which depends on the tier of scanning modules in it: - Tier 1 - 4% - Tier 2 - 3% - Tier 3 - 2% - Tier 4 - 1% Scanner gates now loudly blare into chat when they detect stuff. Now there is a preset scanner gate to detect **GUNS** in main Brig entrances on maps, they are not upgraded with N-Spector. *** N-Spector now can not only scan items for contraband but people too. It takes 4 seconds, makes a loud noise, and warns the person getting scanned in a chat with bold text. https://github.com/user-attachments/assets/6aaca7bb-8273-485b-a727-c84f132b92f5 *** Made scanner code using proper cooldowns. The scanner gate description now tells on which mode it's turned on. Now smuggler satchel description tells you that it can prevent items from being detected by contraband scanners. ## Why It's Good For The Game Scanner gates sprites were ancient and as such been updated. Scanner gates having false-positive will make sure for Security to always be on their toes, and also cause interaction between crew who got false-positive. Also, it finally makes use of scanner gates being upgradable, as before this there was no reason for using higher-tier scanning modules for its construction. Scanner gates blaring into the chat now make it clearer for spectators to acknowledge why the scanner got triggered. Putting not upgraded scanners in the Brig entrance doors gives them some use outside of being sometimes built by bored Security Officers. *** When N-Spector was upgraded, I immediately thought it should also be possible to scan people, like how TSA scans people with metal detectors. It takes around the same time as stripping a backpack, and backpack searches still would be more effective as they can show stuff that the scanner cannot detect. The warning and loud sound make it possible for the person getting scanned to walk away if they start getting scanned unprompted. This would not likely cause any trouble, as going up and starting scanning someone for no reason would be the same as going up to someone and starting to strip their backpack. With N-Spector Security can perform more fluff interesting searches. ## Changelog :cl: DrDiasyl aka DrTuxedo add: Scanner gates now blare into the chat the reason why it got triggered add: Scanner gates now can have false positives/negatives, and the chance of them being reduced when they are upgraded add: Brig entrances now have scanner gates preset to detect GUNS add: You can now scan people with N-Spector for contraband image: Scanner gates now have a better sprite with dirs qol: Scanner gates description now tells to what mode they are set fix: You no longer can remove N-Spector from scanner gates without unlocking them first /:cl: --------- Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com> --- _maps/map_files/Birdshot/birdshot.dmm | 2 + .../map_files/Deltastation/DeltaStation2.dmm | 2 + .../map_files/IceBoxStation/IceBoxStation.dmm | 2 + _maps/map_files/MetaStation/MetaStation.dmm | 2 + _maps/map_files/NorthStar/north_star.dmm | 4 ++ _maps/map_files/tramstation/tramstation.dmm | 4 ++ _maps/map_files/wawastation/wawastation.dmm | 2 + code/game/machinery/scanner_gate.dm | 63 +++++++++++++++--- .../machines/machine_circuitboards.dm | 2 +- code/game/objects/items/inspector.dm | 52 ++++++++++++--- code/game/objects/items/storage/backpack.dm | 2 +- .../cargo/markets/market_items/misc.dm | 2 +- .../uplink/uplink_items/stealthy_tools.dm | 2 +- icons/obj/machines/scangate.dmi | Bin 3219 -> 5364 bytes 14 files changed, 119 insertions(+), 22 deletions(-) diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index f50ee3821cc..3602de769e1 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -15189,6 +15189,7 @@ cycle_id = "sci-entrance" }, /obj/structure/disposalpipe/segment, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/textured_half, /area/station/security/brig/entrance) "fKx" = ( @@ -30896,6 +30897,7 @@ cycle_id = "sci-entrance" }, /obj/structure/disposalpipe/segment, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/textured_half, /area/station/security/brig/entrance) "kKD" = ( diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 8a25706a1f7..18116748bcc 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -50664,6 +50664,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/dark, /area/station/security/brig) "mEH" = ( @@ -80365,6 +80366,7 @@ dir = 4 }, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/dark, /area/station/security/brig) "ucA" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index e29c029d8d9..ef84443ce31 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -15783,6 +15783,7 @@ cycle_id = "brigoutpost" }, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/dark/textured_edge{ dir = 8 }, @@ -18827,6 +18828,7 @@ cycle_id = "brigoutpost" }, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/dark/textured_edge{ dir = 4 }, diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 9fd7c6aac01..b0f6d7f0690 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -15270,6 +15270,7 @@ cycle_id = "brig-entrance" }, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron, /area/station/security/brig) "frZ" = ( @@ -16178,6 +16179,7 @@ cycle_id = "brig-entrance" }, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron, /area/station/security/brig) "fMf" = ( diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 081edcaf677..8d7a99da8e7 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -10210,6 +10210,7 @@ /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/dark, /area/station/security/checkpoint) "cBq" = ( @@ -29793,6 +29794,7 @@ }, /obj/structure/disposalpipe/segment, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/dark, /area/station/security/brig) "hLP" = ( @@ -35063,6 +35065,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/dark, /area/station/security/brig) "jfs" = ( @@ -55322,6 +55325,7 @@ /obj/effect/turf_decal/tile/red/fourcorners, /obj/effect/mapping_helpers/airlock/access/all/security/general, /obj/structure/disposalpipe/segment, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron/dark, /area/station/security/checkpoint) "ojM" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index efc6e69075a..4be002dfd2d 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -32278,6 +32278,7 @@ }, /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron, /area/station/security/brig) "kul" = ( @@ -47384,6 +47385,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/landmark/navigate_destination/sec, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron, /area/station/security/brig) "pLs" = ( @@ -53602,6 +53604,7 @@ }, /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron, /area/station/security/brig) "rUe" = ( @@ -66155,6 +66158,7 @@ /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, /obj/structure/disposalpipe/segment, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron, /area/station/security/brig) "wiU" = ( diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index 17a558b4f5e..fbeea130c8b 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -2419,6 +2419,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron, /area/station/security/brig/entrance) "aNR" = ( @@ -39733,6 +39734,7 @@ /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/security/entrance, /obj/structure/disposalpipe/segment, +/obj/machinery/scanner_gate/preset_guns, /turf/open/floor/iron, /area/station/security/brig/entrance) "odG" = ( diff --git a/code/game/machinery/scanner_gate.dm b/code/game/machinery/scanner_gate.dm index 860a5b1bc05..04fcbe55dbd 100644 --- a/code/game/machinery/scanner_gate.dm +++ b/code/game/machinery/scanner_gate.dm @@ -23,11 +23,11 @@ desc = "A gate able to perform mid-depth scans on any organisms who pass under it." icon = 'icons/obj/machines/scangate.dmi' icon_state = "scangate" + layer = ABOVE_MOB_LAYER circuit = /obj/item/circuitboard/machine/scanner_gate + COOLDOWN_DECLARE(next_beep) var/scanline_timer - ///Internal timer to prevent audio spam. - var/next_beep = 0 ///Bool to check if the scanner's controls are locked by an ID. var/locked = FALSE ///Which setting is the scanner checking for? See defines in scanner_gate.dm for the list. @@ -46,6 +46,10 @@ var/light_fail = FALSE ///Does the scanner ignore light_pass and light_fail for sending signals? var/ignore_signals = FALSE + ///Modifier to the chance of scanner being false positive/negative + var/minus_false_beep = 0 + ///Base false positive/negative chance + var/base_false_beep = 5 ///Is an n-spect scanner attached to the gate? Enables contraband scanning. var/obj/item/inspector/n_spect = null @@ -60,6 +64,11 @@ AddElement(/datum/element/connect_loc, loc_connections) register_context() +/obj/machinery/scanner_gate/RefreshParts() + . = ..() + for(var/datum/stock_part/scanning_module/scanning_module in component_parts) + minus_false_beep = scanning_module.tier //The better are scanninning modules - the lower is chance of False Positives + /obj/machinery/scanner_gate/Destroy() qdel(wires) set_wires(null) @@ -73,6 +82,8 @@ /obj/machinery/scanner_gate/examine(mob/user) . = ..() + + . += span_notice("It's set to scan for [span_boldnotice(scangate_mode)].") if(locked) . += span_notice("The control panel is ID-locked. Swipe a valid ID to unlock it.") else @@ -143,6 +154,10 @@ /obj/machinery/scanner_gate/crowbar_act(mob/living/user, obj/item/tool) . = ..() if(n_spect) + if(locked) + balloon_alert(user, "locked!") + return ITEM_INTERACT_BLOCKING + to_chat(user, span_notice("You uninstall [n_spect] from [src].")) n_spect.forceMove(drop_location()) return ITEM_INTERACT_SUCCESS @@ -166,20 +181,24 @@ /obj/machinery/scanner_gate/proc/perform_scan(mob/living/M) var/beep = FALSE var/color = null + var/detected_thing = null switch(scangate_mode) if(SCANGATE_NONE) return if(SCANGATE_WANTED) if(ishuman(M)) + detected_thing = "Warrant" var/mob/living/carbon/human/H = M var/perpname = H.get_face_name(H.get_id_name()) var/datum/record/crew/target = find_record(perpname) if(!target || (target.wanted_status == WANTED_ARREST)) beep = TRUE if(SCANGATE_MINDSHIELD) + detected_thing = "Mindshield" if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) beep = TRUE if(SCANGATE_DISEASE) + detected_thing = "[disease_threshold] infection" if(iscarbon(M)) var/mob/living/carbon/C = M if(get_disease_severity_value(C.check_virus()) >= get_disease_severity_value(disease_threshold)) @@ -190,30 +209,41 @@ var/datum/species/scan_species = /datum/species/human switch(detect_species) if(SCANGATE_LIZARD) + detected_thing = "Lizardperson" scan_species = /datum/species/lizard if(SCANGATE_FLY) + detected_thing = "Flyperson" scan_species = /datum/species/fly if(SCANGATE_FELINID) + detected_thing = "Felinid" scan_species = /datum/species/human/felinid if(SCANGATE_PLASMAMAN) + detected_thing = "Plasmaman" scan_species = /datum/species/plasmaman if(SCANGATE_MOTH) + detected_thing = "Mothperson" scan_species = /datum/species/moth if(SCANGATE_JELLY) + detected_thing = "Jellyperson" scan_species = /datum/species/jelly if(SCANGATE_POD) + detected_thing = "Podperson" scan_species = /datum/species/pod if(SCANGATE_GOLEM) + detected_thing = "Golem" scan_species = /datum/species/golem if(SCANGATE_ZOMBIE) + detected_thing = "Zombie" scan_species = /datum/species/zombie if(is_species(H, scan_species)) beep = TRUE if(detect_species == SCANGATE_ZOMBIE) //Can detect dormant zombies + detected_thing = "Romerol infection" if(H.get_organ_slot(ORGAN_SLOT_ZOMBIE)) beep = TRUE if(SCANGATE_GUNS) for(var/I in M.get_contents()) + detected_thing = "Weapons" if(isgun(I)) beep = TRUE break @@ -222,10 +252,13 @@ var/mob/living/carbon/human/H = M if(H.nutrition <= detect_nutrition && detect_nutrition == NUTRITION_LEVEL_STARVING) beep = TRUE + detected_thing = "Starvation" if(H.nutrition >= detect_nutrition && detect_nutrition == NUTRITION_LEVEL_FAT) beep = TRUE + detected_thing = "Obesity" if(SCANGATE_CONTRABAND) for(var/obj/item/content in M.get_all_contents_skipping_traits(TRAIT_CONTRABAND_BLOCKER)) + detected_thing = "Contraband" if(content.is_contraband()) beep = TRUE break @@ -234,8 +267,12 @@ if(reverse) beep = !beep + + if(prob(base_false_beep - minus_false_beep)) //False positive/negative + beep = prob(50) + if(beep) - alarm_beep() + alarm_beep(detected_thing) SEND_SIGNAL(src, COMSIG_SCANGATE_PASS_TRIGGER, M) if(!ignore_signals) color = wires.get_color_of_wire(WIRE_ACCEPT) @@ -251,12 +288,15 @@ use_energy(active_power_usage) -/obj/machinery/scanner_gate/proc/alarm_beep() - if(next_beep <= world.time) - next_beep = world.time + (2 SECONDS) - playsound(src, 'sound/machines/scanbuzz.ogg', 100, FALSE) - var/mutable_appearance/alarm_display = mutable_appearance(icon, "alarm_light") - flick_overlay_view(alarm_display, 2 SECONDS) +/obj/machinery/scanner_gate/proc/alarm_beep(detected_thing) + if(!COOLDOWN_FINISHED(src, next_beep)) + return + + if(detected_thing) + say("[detected_thing][reverse ? " not " : " "]detected!!") + + COOLDOWN_START(src, next_beep, 2 SECONDS) + playsound(src, 'sound/machines/scanbuzz.ogg', 100, FALSE) set_scanline("alarm", 2 SECONDS) /obj/machinery/scanner_gate/can_interact(mob/user) @@ -321,6 +361,11 @@ detect_nutrition = NUTRITION_LEVEL_FAT . = TRUE +/obj/machinery/scanner_gate/preset_guns + locked = TRUE + req_access = ACCESS_SECURITY + scangate_mode = SCANGATE_GUNS + #undef SCANGATE_NONE #undef SCANGATE_MINDSHIELD #undef SCANGATE_DISEASE diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index f4168b7b377..96206b800e3 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -329,7 +329,7 @@ /obj/item/circuitboard/machine/scanner_gate name = "Scanner Gate" - greyscale_colors = CIRCUIT_COLOR_ENGINEERING + greyscale_colors = CIRCUIT_COLOR_SECURITY build_path = /obj/machinery/scanner_gate req_components = list( /datum/stock_part/scanning_module = 3) diff --git a/code/game/objects/items/inspector.dm b/code/game/objects/items/inspector.dm index b73917bfba8..e7546d4c1d9 100644 --- a/code/game/objects/items/inspector.dm +++ b/code/game/objects/items/inspector.dm @@ -8,7 +8,7 @@ */ /obj/item/inspector name = "\improper N-spect scanner" - desc = "Central Command standard issue inspection device. Can perform either wide area scans that central command can use to verify the security of the station, or detailed scans to determine if an item is contraband." + desc = "Central Command standard issue inspection device. Can perform either wide area scans that central command can use to verify the security of the station, or detailed scan. Can scan people for contraband on their person or items being contraband." icon = 'icons/obj/devices/scanner.dmi' icon_state = "inspector" worn_icon_state = "salestagger" @@ -20,6 +20,7 @@ interaction_flags_click = NEED_DEXTERITY throw_range = 1 throw_speed = 1 + COOLDOWN_DECLARE(scanning_person) //Cooldown for scanning a carbon ///How long it takes to print on time each mode, ordered NORMAL, FAST, HONK var/list/time_list = list(5 SECONDS, 1 SECONDS, 0.1 SECONDS) ///Which print time mode we're on. @@ -106,18 +107,28 @@ if(!cell || !cell.use(INSPECTOR_ENERGY_USAGE_LOW)) balloon_alert(user, "check cell!") return ITEM_INTERACT_BLOCKING - if(!isitem(interacting_with)) - return ITEM_INTERACT_BLOCKING - var/obj/item/contraband_item = interacting_with - var/contraband_status = contraband_item.is_contraband() - if((!contraband_status && scans_correctly) || (contraband_status && !scans_correctly)) + + if(iscarbon(interacting_with)) //Prevents insta scanning people + if(!COOLDOWN_FINISHED(src, scanning_person)) + return ITEM_INTERACT_BLOCKING + + visible_message(span_warning("[user] starts scanning [interacting_with] with [src]")) + to_chat(interacting_with, span_userdanger("[user] is trying to scan you for contraband!")) + balloon_alert_to_viewers("scanning...") + playsound(src, 'sound/effects/genetics.ogg', 40, FALSE) + COOLDOWN_START(src, scanning_person, 4 SECONDS) + if(!do_after(user, 4 SECONDS, interacting_with)) + return ITEM_INTERACT_BLOCKING + + if(contraband_scan(interacting_with, user)) + playsound(src, 'sound/machines/uplinkerror.ogg', 40) + balloon_alert(user, "contraband detected!") + return ITEM_INTERACT_SUCCESS + else playsound(src, 'sound/machines/ping.ogg', 20) balloon_alert(user, "clear") return ITEM_INTERACT_SUCCESS - playsound(src, 'sound/machines/uplinkerror.ogg', 40) - balloon_alert(user, "contraband detected!") - return ITEM_INTERACT_SUCCESS /obj/item/inspector/add_context(atom/source, list/context, obj/item/held_item, mob/user) var/update_context = FALSE @@ -145,6 +156,29 @@ return CONTEXTUAL_SCREENTIP_SET return NONE +/** + * Scans the carbon or item for contraband. + * + * Arguments: + * - scanned - what or who is scanned? + * - user - who is performing the scanning? + */ +/obj/item/inspector/proc/contraband_scan(scanned, user) + if(iscarbon(scanned)) + var/mob/living/carbon/scanned_carbon = scanned + for(var/obj/item/content in scanned_carbon.get_all_contents_skipping_traits(TRAIT_CONTRABAND_BLOCKER)) + var/contraband_content = content.is_contraband() + if((contraband_content && scans_correctly) || (!contraband_content && !scans_correctly)) + return TRUE + + if(isitem(scanned)) + var/obj/item/contraband_item = scanned + var/contraband_status = contraband_item.is_contraband() + if((contraband_status && scans_correctly) || (!contraband_status && !scans_correctly)) + return TRUE + + return FALSE + /** * Create our report * diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 77ca77e8ba0..a88da6537b6 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -377,7 +377,7 @@ /obj/item/storage/backpack/satchel/flat name = "smuggler's satchel" - desc = "A very slim satchel that can easily fit into tight spaces." + desc = "A very slim satchel that can easily fit into tight spaces. Its contents cannot be detected by contraband scanners." icon_state = "satchel-flat" inhand_icon_state = "satchel-flat" w_class = WEIGHT_CLASS_NORMAL //Can fit in backpacks itself. diff --git a/code/modules/cargo/markets/market_items/misc.dm b/code/modules/cargo/markets/market_items/misc.dm index 6e61bf87f0c..b0ea8948580 100644 --- a/code/modules/cargo/markets/market_items/misc.dm +++ b/code/modules/cargo/markets/market_items/misc.dm @@ -90,7 +90,7 @@ /datum/market_item/misc/smugglers_satchel name = "Smuggler's Satchel" - desc = "This easily hidden satchel can become a versatile tool to anybody with the desire to keep certain items out of sight and out of mind." + desc = "This easily hidden satchel can become a versatile tool to anybody with the desire to keep certain items out of sight and out of mind. Its contents cannot be detected by contraband scanners." item = /obj/item/storage/backpack/satchel/flat/empty price_min = CARGO_CRATE_VALUE * 3.75 diff --git a/code/modules/uplink/uplink_items/stealthy_tools.dm b/code/modules/uplink/uplink_items/stealthy_tools.dm index 48c25e638de..40e5df8febd 100644 --- a/code/modules/uplink/uplink_items/stealthy_tools.dm +++ b/code/modules/uplink/uplink_items/stealthy_tools.dm @@ -87,7 +87,7 @@ /datum/uplink_item/stealthy_tools/smugglersatchel name = "Smuggler's Satchel" desc = "This satchel is thin enough to be hidden in the gap between plating and tiling; great for stashing \ - your stolen goods. Comes with a crowbar, a floor tile and some contraband inside." + your stolen goods. Comes with a crowbar, a floor tile and some contraband inside. Its contents cannot be detected by contraband scanners." item = /obj/item/storage/backpack/satchel/flat/with_tools cost = 1 surplus = 30 diff --git a/icons/obj/machines/scangate.dmi b/icons/obj/machines/scangate.dmi index 6af8750414adebcd45d3d2fd26c88740984d2daf..9dacefab3539c92d384eb80c66bf7f86a6f6485a 100644 GIT binary patch literal 5364 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 literal 3219 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