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
🆑 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
/🆑

---------

Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
This commit is contained in:
DrTuxedo
2024-07-21 04:35:45 +05:00
committed by GitHub
parent 8da5069bc3
commit 63e2f45ed3
14 changed files with 119 additions and 22 deletions
+2
View File
@@ -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" = (
@@ -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" = (
@@ -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
},
@@ -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" = (
+4
View File
@@ -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" = (
@@ -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" = (
@@ -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" = (
+54 -9
View File
@@ -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
@@ -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)
+43 -9
View File
@@ -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
*
+1 -1
View File
@@ -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.
@@ -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
@@ -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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB