From 43e62163febea15d41c7279843ecb568935b89ed Mon Sep 17 00:00:00 2001
From: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
Date: Wed, 10 Jul 2024 21:08:25 -0400
Subject: [PATCH] Adds a Contraband trait, and implements contraband as a
mechanic to security bounties. (#84003)
## About The Pull Request
This PR does a few things but centrally it's all centered around
mechanically enforcing what items are and are-not considered contraband
in-game.
### What does something being contraband MEAN?
Contraband items are visually indistinguishable from non-contraband. If
an item is Contraband, it can only be detected in two ways:
* After being scanned by an N-Spect scanner, which is a standard item
security item, assuming it still has a charge to do so.
* Via a scanner gate, which can now be upgraded with an N-spect scanner
to allow for it to scan a person and all their contents for contraband.
### What items ARE contraband?
Contraband items are intended to be determined both logically and
through other relevant examine text. However, here's the short list of
items that are considered contraband, reserving the right to expand the
list.
In hindsight it's kind of a long list.
* Items that have "contraband" or "illegal" in the name or description.
* Items that allow for the player to obtain other illegal items, that
are NOT particularly stealthy.
* This means that a syndicate uplink is NOT considered contraband, as
they're typically hidden on your person as something else.
* Stealth items under the syndicate uplink, the revolutionary flash, and
some mapped in dangerous items that can come from both syndicate and
company-aligned resources are not considered dangerous.
* Items that are purchased from cargo after emagging or switching to
extended cargo range.
* Items purchased FROM syndicate uplinks, the wizard knowledge scroll,
or other antagonist shops.
* Cursed artifacts/tools magically produced by cultists or heretics.
* Items purchased from the blackmarket.
* Items purchased from the contraband section of vending machines.
* Some drugs and overtly dangerous or criminal byproducts.
### How does this interact with the round?
Well, primarily, this is an aid for in-game enforcement of space law.
Based on the length of the above list, we have a LONG, LONG list of
items in-game that are technically considered, in one way or another,
illegal to have on the station, and yet without either metaknowledge of
what those items are, or how they're used, security officers lack some
of the certainty of how to deal with these kinds of encounters.
Additionally to the knowledge aspect of this trait, security officers
may now receive a new civilian bounty to collect items that are
considered contraband, also giving them an incentive to look for and
confiscate contraband that's been found across the station while
upholding space law.
### Other minor changes that I rolled into this
Security has a bounty for 3 different rechargers, and considering access
limitations, most security players aren't going to make this exchange,
so I've lowered the required amount down to 1.
Adjusted the N-spect scanner's description to match it's new
functionality.
The Civilian bounty TGUI now has an additional 1 point of padding to
make it feel less cramped.
https://github.com/tgstation/tgstation/assets/41715314/c3cd4752-b03a-4e0b-959e-1252fcc2369d
**Updated as of 6/19/2024:**
Additionally, some storage items will block the presence of contraband
when going through a contraband aligned scanning gate. These items
include the infiltrator modsuit core, storage implant, void cloak, the
aptly named smuggler's satchel, and the chameleon kit's backpack.
**Updated as of 6/23/2024:**
N-spect scanner now has contextual screentips.
**Updated as of 6/29/2024:**
Scanner gates are now available in all lathes that have a feature
specific to how scanner gates function. So, includes cargo (contraband),
security (weapons), and medbay (diseases).
## Why It's Good For The Game
Originally, this started out as a way to be able to provide more
in-character and in-flavor bounties for security officers, because they
suck! Most security bounties as they exist right now do the worst
possible things from all respective bounties:
* They detract away from a job's actual responsibilities as opposed to
working with them.
* They're best completed while sitting next to your lathe and running
items back to the bounty pad.
* They exist with such esoteric rarity of high quantity of items that
it's miserable to fulfil.
As a result, I started work on this as a framework to allow security
officers to be further incentivized to collect contraband across the
station, either as a result of the gamemode or just through routine
patrols across the station.
Implementing it as a learning tool for security as well just happened to
work out as an additional bonus, and having a function in-game allowing
newer or less experienced players to know if an item is considered
dangerous or conspicuous also works as a particularly good way to
provide information where a player may not know what they're up against.
If nothing else, this might be interesting to try, and if not, I'll just
snip out the QOL changes from it and we'll see how it goes.
Going forward, I am a bit hesitant about the contraband scanner gate
mode, and as such, will try working with the admin team to determine if
that's a good feature to keep around for game health, while hoping to
give it a chance in the fullness of time.
## Changelog
:cl:
add: Items spawned via traitor uplinks or are known illegal contraband
on the station can now be scanned and identified as such by the N-spect
scanners in security. These only applies to overt traitor or antagonist
items, and "stealth" items will not be seen as such.
add: Scanner gates can now be upgraded by using an N-spect scanner on it
to unlock "contraband scanning" mode.
add: Security officers can now be offered a bounty to turn in pieces of
contraband.
add: Some stealthy storage items like storage implants, smuggler's
satchels, void cloaks, the infiltrator modsuit, and the chameleon
backpack will block the presence of contraband on your person when
placed inside.
qol: N-spect scanner contextual screentips.
balance: Recharger security bounties ask for a quantity of 1, down from
3.
qol: security, cargo, and medbay have access to scanner gate boards.
/:cl:
---------
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
---
code/__DEFINES/antagonists.dm | 5 ++
code/__DEFINES/blackmarket.dm | 1 +
code/__DEFINES/devices.dm | 1 +
code/__DEFINES/traits/declarations.dm | 7 ++-
code/__HELPERS/atoms.dm | 12 ++++
code/_globalvars/traits/_traits.dm | 6 +-
code/controllers/subsystem/blackmarket.dm | 4 +-
.../{scan_gate.dm => scanner_gate.dm} | 60 ++++++++++++++++++-
.../objects/effects/posters/contraband.dm | 4 ++
.../effects/spawners/random/contraband.dm | 6 ++
code/game/objects/items.dm | 14 +++++
code/game/objects/items/drug_items.dm | 9 +++
.../objects/items/implants/implant_storage.dm | 2 +-
code/game/objects/items/inspector.dm | 55 ++++++++++++++++-
code/game/objects/items/robot/ai_upgrades.dm | 7 +++
.../objects/items/robot/robot_upgrades.dm | 4 ++
code/game/objects/items/stickers.dm | 4 ++
code/game/objects/items/storage/backpack.dm | 1 +
code/modules/antagonists/cult/cult_items.dm | 5 ++
.../antagonists/cult/cult_structures.dm | 1 +
.../antagonists/cult/datums/cultist.dm | 3 +-
.../antagonists/heretic/heretic_knowledge.dm | 4 +-
.../heretic/items/heretic_armor.dm | 1 +
.../equipment/spellbook_entries/_entry.dm | 5 ++
code/modules/cargo/bounties/security.dm | 16 ++++-
code/modules/cargo/markets/_market.dm | 15 ++++-
code/modules/cargo/markets/market_item.dm | 29 +++++++--
code/modules/cargo/markets/market_telepad.dm | 1 +
code/modules/cargo/markets/market_uplink.dm | 3 +
code/modules/cargo/order.dm | 3 +
code/modules/cargo/orderconsole.dm | 1 +
code/modules/cargo/packs/_packs.dm | 1 +
.../chameleon/generic_chameleon_clothing.dm | 4 ++
code/modules/hydroponics/grown/kronkus.dm | 8 +++
code/modules/mod/mod_types.dm | 3 +
.../reagents/reagent_containers/syringes.dm | 4 ++
.../research/designs/machine_designs.dm | 2 +-
.../research/techweb/nodes/syndicate_nodes.dm | 2 +-
code/modules/surgery/organs/autosurgeon.dm | 4 ++
code/modules/uplink/uplink_items.dm | 18 ++++--
.../modules/uplink/uplink_items/ammunition.dm | 6 +-
code/modules/uplink/uplink_items/badass.dm | 8 +--
code/modules/uplink/uplink_items/clownops.dm | 6 +-
code/modules/uplink/uplink_items/dangerous.dm | 2 +-
.../uplink/uplink_items/device_tools.dm | 6 +-
code/modules/uplink/uplink_items/job.dm | 8 +--
code/modules/uplink/uplink_items/nukeops.dm | 2 +-
.../modules/uplink/uplink_items/spy_unique.dm | 12 ++++
code/modules/uplink/uplink_items/stealthy.dm | 1 +
.../uplink/uplink_items/stealthy_tools.dm | 3 +-
code/modules/vending/_vending.dm | 2 +
tgstation.dme | 2 +-
.../tgui/interfaces/Cargo/CargoCatalog.tsx | 5 ++
tgui/packages/tgui/interfaces/Cargo/types.ts | 1 +
.../tgui/interfaces/CivCargoHoldTerminal.jsx | 1 +
tgui/packages/tgui/interfaces/ScannerGate.jsx | 27 ++++++++-
56 files changed, 380 insertions(+), 47 deletions(-)
rename code/game/machinery/{scan_gate.dm => scanner_gate.dm} (80%)
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index 9a943474de6..f94871d10cc 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -314,6 +314,11 @@ GLOBAL_LIST_INIT(human_invader_antagonists, list(
#define UPLINK_SHARED_STOCK_KITS "uplink_shared_stock_kits"
#define UPLINK_SHARED_STOCK_SURPLUS "uplink_shared_stock_surplus"
+/// Does this item provide illegal tech?
+#define SYNDIE_ILLEGAL_TECH (1 << 0)
+/// Does this item go off when scanned by a contraband scanner?
+#define SYNDIE_TRIPS_CONTRABAND (1 << 1)
+
// Used for traitor objectives
/// If the objective hasn't been taken yet
#define OBJECTIVE_STATE_INACTIVE 1
diff --git a/code/__DEFINES/blackmarket.dm b/code/__DEFINES/blackmarket.dm
index c3b8ad0bf46..f0a19ad056d 100644
--- a/code/__DEFINES/blackmarket.dm
+++ b/code/__DEFINES/blackmarket.dm
@@ -9,3 +9,4 @@
#define SHIPPING_METHOD_LAUNCH "Launch"
// Sends a supply pod to the buyer's location, showy.
#define SHIPPING_METHOD_SUPPLYPOD "Supply Pod"
+
diff --git a/code/__DEFINES/devices.dm b/code/__DEFINES/devices.dm
index afd41570b5b..7368d8d0457 100644
--- a/code/__DEFINES/devices.dm
+++ b/code/__DEFINES/devices.dm
@@ -10,6 +10,7 @@
#define CLOWN_INSPECTOR_PRINT_SOUND_MODE_LAST 4
#define INSPECTOR_ENERGY_USAGE_HONK (0.015 * STANDARD_CELL_CHARGE)
#define INSPECTOR_ENERGY_USAGE_NORMAL (0.005 * STANDARD_CELL_CHARGE)
+#define INSPECTOR_ENERGY_USAGE_LOW (0.001 * STANDARD_CELL_CHARGE)
#define INSPECTOR_TIME_MODE_SLOW 1
#define INSPECTOR_TIME_MODE_FAST 2
#define INSPECTOR_TIME_MODE_HONK 3
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index 981ad0e6de8..1c03ecac2ee 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -767,6 +767,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_DANGEROUS_OBJECT "dangerous_object"
/// determines whether or not objects are haunted and teleport/attack randomly
#define TRAIT_HAUNTED "haunted"
+/// An item that, if it has contents, will ignore it's contents when scanning for contraband.
+#define TRAIT_CONTRABAND_BLOCKER "contraband_blocker"
//quirk traits
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
@@ -1160,7 +1162,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait which means whatever has this is dancing by a dance machine
#define TRAIT_DISCO_DANCER "disco_dancer"
-/// That which allows mobs to instantly break down boulders.
+/// Trait which allows mobs to instantly break down boulders.
#define TRAIT_INSTANTLY_PROCESSES_BOULDERS "instantly_processes_boulders"
/// Trait applied to objects and mobs that can attack a boulder and break it down. (See /obj/item/boulder/manual_process())
@@ -1174,6 +1176,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Does this item bypass ranged armor checks?
#define TRAIT_BYPASS_RANGED_ARMOR "bypass_ranged_armor"
+/// Trait which means that this item is considered illegal contraband, and valid for the contraband bounty or when scanned by an nspect scanner.
+#define TRAIT_CONTRABAND "illegal_contraband"
+
/// Traits given by settler, each with their own specific effects for cases where someone would have that trait, but not the other settler effects
#define TRAIT_EXPERT_FISHER "expert_fisher" // fishing is easier
diff --git a/code/__HELPERS/atoms.dm b/code/__HELPERS/atoms.dm
index 406ea75143c..7106ec81be1 100644
--- a/code/__HELPERS/atoms.dm
+++ b/code/__HELPERS/atoms.dm
@@ -33,6 +33,18 @@
processing += checked_atom.contents
. += checked_atom
+///Returns the src and all recursive contents, but skipping going any deeper if an atom has a specific trait.
+/atom/proc/get_all_contents_skipping_traits(skipped_trait)
+ . = list(src)
+ if(!skipped_trait)
+ CRASH("get_all_contents_skipping_traits called without a skipped_trait")
+ var/i = 0
+ while(i < length(.))
+ var/atom/checked_atom = .[++i]
+ if(HAS_TRAIT(checked_atom, skipped_trait))
+ continue
+ . += checked_atom.contents
+
///Returns a list of all locations (except the area) the movable is within.
/proc/get_nested_locs(atom/movable/atom_on_location, include_turf = FALSE)
. = list()
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index e012ea34329..592ceda2eac 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -112,6 +112,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
),
/obj = list(
"TRAIT_WALLMOUNTED" = TRAIT_WALLMOUNTED,
+ "TRAIT_CONTRABAND" = TRAIT_CONTRABAND,
),
/mob = list(
"TRAIT_ABDUCTOR_SCIENTIST_TRAINING" = TRAIT_ABDUCTOR_SCIENTIST_TRAINING,
@@ -525,9 +526,11 @@ GLOBAL_LIST_INIT(traits_by_type, list(
),
/obj/item = list(
"TRAIT_APC_SHOCKING" = TRAIT_APC_SHOCKING,
+ "TRAIT_BAKEABLE" = TRAIT_BAKEABLE,
"TRAIT_BASIC_QUALITY_BAIT" = TRAIT_BASIC_QUALITY_BAIT,
"TRAIT_BLIND_TOOL" = TRAIT_BLIND_TOOL,
"TRAIT_BYPASS_RANGED_ARMOR" = TRAIT_BYPASS_RANGED_ARMOR,
+ "TRAIT_CONTRABAND_BLOCKER" = TRAIT_CONTRABAND_BLOCKER,
"TRAIT_CUSTOM_TAP_SOUND" = TRAIT_CUSTOM_TAP_SOUND,
"TRAIT_DANGEROUS_OBJECT" = TRAIT_DANGEROUS_OBJECT,
"TRAIT_FISHING_BAIT" = TRAIT_FISHING_BAIT,
@@ -537,6 +540,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_HAUNTED" = TRAIT_HAUNTED,
"TRAIT_HONKSPAMMING" = TRAIT_HONKSPAMMING,
"TRAIT_INNATELY_FANTASTICAL_ITEM" = TRAIT_INNATELY_FANTASTICAL_ITEM,
+ "TRAIT_INSTANTLY_PROCESSES_BOULDERS" = TRAIT_INSTANTLY_PROCESSES_BOULDERS,
"TRAIT_ITEM_OBJECTIVE_BLOCKED" = TRAIT_ITEM_OBJECTIVE_BLOCKED,
"TRAIT_NEEDS_TWO_HANDS" = TRAIT_NEEDS_TWO_HANDS,
"TRAIT_NO_BARCODES" = TRAIT_NO_BARCODES,
@@ -550,8 +554,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_TRANSFORM_ACTIVE" = TRAIT_TRANSFORM_ACTIVE,
"TRAIT_UNCATCHABLE" = TRAIT_UNCATCHABLE,
"TRAIT_WIELDED" = TRAIT_WIELDED,
- "TRAIT_BAKEABLE" = TRAIT_BAKEABLE,
- "TRAIT_INSTANTLY_PROCESSES_BOULDERS" = TRAIT_INSTANTLY_PROCESSES_BOULDERS,
),
/obj/item/ammo_casing = list(
"TRAIT_DART_HAS_INSERT" = TRAIT_DART_HAS_INSERT,
diff --git a/code/controllers/subsystem/blackmarket.dm b/code/controllers/subsystem/blackmarket.dm
index f6a4aa25566..5c88177583b 100644
--- a/code/controllers/subsystem/blackmarket.dm
+++ b/code/controllers/subsystem/blackmarket.dm
@@ -79,7 +79,7 @@ SUBSYSTEM_DEF(blackmarket)
to_chat(buyer, span_notice("[purchase.uplink] flashes a message noting that the order is being teleported to [get_area(targetturf)] in 60 seconds."))
// do_teleport does not want to teleport items from nullspace, so it just forceMoves and does sparks.
- addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/blackmarket,fake_teleport), purchase, targetturf), 60 SECONDS)
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/blackmarket, fake_teleport), purchase, targetturf), 60 SECONDS)
// Get the current location of the uplink if it exists, then throws the item from space at the station from a random direction.
if(SHIPPING_METHOD_LAUNCH)
@@ -88,6 +88,7 @@ SUBSYSTEM_DEF(blackmarket)
var/pickedloc = spaceDebrisStartLoc(startSide, T.z)
var/atom/movable/item = purchase.entry.spawn_item(pickedloc, purchase)
+ purchase.post_purchase_effects(item)
item.throw_at(purchase.uplink, 3, 3, spin = FALSE)
to_chat(buyer, span_notice("[purchase.uplink] flashes a message noting the order is being launched at the station from [dir2text(startSide)]."))
@@ -110,6 +111,7 @@ SUBSYSTEM_DEF(blackmarket)
if(QDELETED(purchase))
return
var/atom/movable/thing = purchase.entry.spawn_item(target, purchase)
+ purchase.post_purchase_effects(thing)
var/datum/effect_system/spark_spread/sparks = new
sparks.set_up(5, 1, target)
sparks.attach(thing)
diff --git a/code/game/machinery/scan_gate.dm b/code/game/machinery/scanner_gate.dm
similarity index 80%
rename from code/game/machinery/scan_gate.dm
rename to code/game/machinery/scanner_gate.dm
index 3986b109ffc..860a5b1bc05 100644
--- a/code/game/machinery/scan_gate.dm
+++ b/code/game/machinery/scanner_gate.dm
@@ -5,6 +5,7 @@
#define SCANGATE_WANTED "Wanted"
#define SCANGATE_SPECIES "Species"
#define SCANGATE_NUTRITION "Nutrition"
+#define SCANGATE_CONTRABAND "Contraband"
#define SCANGATE_HUMAN "human"
#define SCANGATE_LIZARD "lizard"
@@ -29,7 +30,7 @@
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 scan_gate.dm for the list.
+ ///Which setting is the scanner checking for? See defines in scanner_gate.dm for the list.
var/scangate_mode = SCANGATE_NONE
///Is searching for a disease, what severity is enough to trigger the gate?
var/disease_threshold = DISEASE_SEVERITY_MINOR
@@ -45,6 +46,8 @@
var/light_fail = FALSE
///Does the scanner ignore light_pass and light_fail for sending signals?
var/ignore_signals = FALSE
+ ///Is an n-spect scanner attached to the gate? Enables contraband scanning.
+ var/obj/item/inspector/n_spect = null
/obj/machinery/scanner_gate/Initialize(mapload)
@@ -55,18 +58,37 @@
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
)
AddElement(/datum/element/connect_loc, loc_connections)
+ register_context()
/obj/machinery/scanner_gate/Destroy()
qdel(wires)
set_wires(null)
. = ..()
+/obj/machinery/scanner_gate/atom_deconstruct(disassembled)
+ . = ..()
+ if(n_spect)
+ n_spect.forceMove(drop_location())
+ n_spect = null
+
/obj/machinery/scanner_gate/examine(mob/user)
. = ..()
if(locked)
. += span_notice("The control panel is ID-locked. Swipe a valid ID to unlock it.")
else
. += span_notice("The control panel is unlocked. Swipe an ID to lock it.")
+ if(n_spect)
+ . += span_notice("The scanner is equipped with an N-Spect scanner. Use a [span_boldnotice("crowbar")] to uninstall.")
+
+/obj/machinery/scanner_gate/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+ if(n_spect && held_item?.tool_behaviour == TOOL_CROWBAR)
+ context[SCREENTIP_CONTEXT_LMB] = "Remove N-Spect scanner"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(!n_spect && istype(held_item, /obj/item/inspector))
+ context[SCREENTIP_CONTEXT_LMB] = "Install N-Spect scanner"
+ return CONTEXTUAL_SCREENTIP_SET
+
/obj/machinery/scanner_gate/proc/on_entered(datum/source, atom/movable/AM)
SIGNAL_HANDLER
@@ -83,6 +105,19 @@
if(duration)
scanline_timer = addtimer(CALLBACK(src, PROC_REF(set_scanline), "passive"), duration, TIMER_STOPPABLE)
+/obj/machinery/scanner_gate/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ if(istype(tool, /obj/item/inspector))
+ if(n_spect)
+ to_chat(user, span_warning("The scanner is already equipped with an N-Spect scanner."))
+ return ITEM_INTERACT_BLOCKING
+ else
+ to_chat(user, span_notice("You install an N-Spect scanner on [src]."))
+ n_spect = tool
+ if(!user.transferItemToLoc(tool, src))
+ return ITEM_INTERACT_BLOCKING
+ return ITEM_INTERACT_SUCCESS
+ return NONE
+
/obj/machinery/scanner_gate/attackby(obj/item/W, mob/user, params)
var/obj/item/card/id/card = W.GetID()
if(card)
@@ -105,6 +140,20 @@
wires.interact(user)
return ..()
+/obj/machinery/scanner_gate/crowbar_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(n_spect)
+ to_chat(user, span_notice("You uninstall [n_spect] from [src]."))
+ n_spect.forceMove(drop_location())
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/scanner_gate/Exited(atom/gone)
+ . = ..()
+ if(gone == n_spect)
+ n_spect = null
+ if(scangate_mode == SCANGATE_CONTRABAND)
+ scangate_mode = SCANGATE_NONE
+
/obj/machinery/scanner_gate/emag_act(mob/user, obj/item/card/emag/emag_card)
if(obj_flags & EMAGGED)
return FALSE
@@ -175,6 +224,13 @@
beep = TRUE
if(H.nutrition >= detect_nutrition && detect_nutrition == NUTRITION_LEVEL_FAT)
beep = TRUE
+ if(SCANGATE_CONTRABAND)
+ for(var/obj/item/content in M.get_all_contents_skipping_traits(TRAIT_CONTRABAND_BLOCKER))
+ if(content.is_contraband())
+ beep = TRUE
+ break
+ if(!n_spect.scans_correctly)
+ beep = !beep //We do a little trolling
if(reverse)
beep = !beep
@@ -222,6 +278,7 @@
data["disease_threshold"] = disease_threshold
data["target_species"] = detect_species
data["target_nutrition"] = detect_nutrition
+ data["contraband_enabled"] = !!n_spect
return data
/obj/machinery/scanner_gate/ui_act(action, params)
@@ -271,6 +328,7 @@
#undef SCANGATE_WANTED
#undef SCANGATE_SPECIES
#undef SCANGATE_NUTRITION
+#undef SCANGATE_CONTRABAND
#undef SCANGATE_HUMAN
#undef SCANGATE_LIZARD
diff --git a/code/game/objects/effects/posters/contraband.dm b/code/game/objects/effects/posters/contraband.dm
index 52528c251b6..04bc790daea 100644
--- a/code/game/objects/effects/posters/contraband.dm
+++ b/code/game/objects/effects/posters/contraband.dm
@@ -4,6 +4,10 @@
poster_type = /obj/structure/sign/poster/contraband/random
icon_state = "rolled_poster"
+/obj/item/poster/random_contraband/Initialize(mapload, obj/structure/sign/poster/new_poster_structure)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
/obj/structure/sign/poster/contraband
poster_item_name = "contraband poster"
poster_item_desc = "This poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface. Its vulgar themes have marked it as contraband aboard Nanotrasen space facilities."
diff --git a/code/game/objects/effects/spawners/random/contraband.dm b/code/game/objects/effects/spawners/random/contraband.dm
index f17656c6119..c32d46125c0 100644
--- a/code/game/objects/effects/spawners/random/contraband.dm
+++ b/code/game/objects/effects/spawners/random/contraband.dm
@@ -25,6 +25,12 @@
/obj/item/reagent_containers/pill/maintenance = 5,
)
+
+/obj/effect/spawner/random/contraband/make_item(spawn_loc, type_path_to_make)
+ var/obj/item/made = ..()
+ ADD_TRAIT(made, TRAIT_CONTRABAND, INNATE_TRAIT)
+ return made
+
/obj/effect/spawner/random/contraband/plus
name = "contraband loot spawner plus"
desc = "Where'd ya find this?"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 87e97b8703a..f18da132af0 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -1716,6 +1716,20 @@
SEND_SIGNAL(loc, COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED, src, old_w_class, new_w_class)
return TRUE
+/**
+ * Used to determine if an item should be considered contraband by N-spect scanners or scanner gates.
+ * Returns true when an item has the contraband trait, or is included in the traitor uplink.
+ */
+/obj/item/proc/is_contraband()
+ if(HAS_TRAIT(src, TRAIT_CONTRABAND))
+ return TRUE
+ for(var/datum/uplink_item/traitor_item as anything in SStraitor.uplink_items)
+ if(istype(src, traitor_item.item))
+ if(!(traitor_item.uplink_item_flags & SYNDIE_TRIPS_CONTRABAND))
+ return FALSE
+ return TRUE
+ return FALSE
+
/// Fetches embedding data
/obj/item/proc/get_embed()
RETURN_TYPE(/datum/embed_data)
diff --git a/code/game/objects/items/drug_items.dm b/code/game/objects/items/drug_items.dm
index f313dad5f74..d25c9571455 100644
--- a/code/game/objects/items/drug_items.dm
+++ b/code/game/objects/items/drug_items.dm
@@ -18,6 +18,10 @@
icon_state = "saturnx_glob" //tell kryson to sprite two more variants in the future.
food_reagents = list(/datum/reagent/drug/saturnx = 10)
+/obj/item/food/drug/saturnx/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
/obj/item/food/drug/moon_rock
name = "moon rock"
desc = "A small hard lump of kronkaine freebase.\nIt is said the average kronkaine addict causes as much criminal damage as four cat burglars, two arsonists and one rabid pit bull terrier combined."
@@ -28,6 +32,7 @@
. = ..()
icon_state = pick("moon_rock1", "moon_rock2", "moon_rock3")
AddElement(/datum/element/swabable, CELL_LINE_TABLE_MOONICORN, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
/obj/item/reagent_containers/cup/blastoff_ampoule
name = "bLaSToFF ampoule" //stylized name
@@ -70,3 +75,7 @@
SplashReagents(hit_atom, TRUE)
qdel(src)
hit_atom.Bumped(ampoule_shard)
+
+/obj/item/reagent_containers/cup/blastoff_ampoule/Initialize(mapload, vol)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
diff --git a/code/game/objects/items/implants/implant_storage.dm b/code/game/objects/items/implants/implant_storage.dm
index 5734beb7683..0ce71c1cbc1 100644
--- a/code/game/objects/items/implants/implant_storage.dm
+++ b/code/game/objects/items/implants/implant_storage.dm
@@ -36,7 +36,7 @@
return TRUE
return FALSE
create_storage(storage_type = /datum/storage/implant)
-
+ ADD_TRAIT(src, TRAIT_CONTRABAND_BLOCKER, INNATE_TRAIT)
return ..()
/obj/item/implanter/storage
diff --git a/code/game/objects/items/inspector.dm b/code/game/objects/items/inspector.dm
index 82a36336c42..b73917bfba8 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-issued inspection device. Performs inspections according to Nanotrasen protocols when activated, then prints an encrypted report regarding the maintenance of the station. Definitely not giving you cancer."
+ 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."
icon = 'icons/obj/devices/scanner.dmi'
icon_state = "inspector"
worn_icon_state = "salestagger"
@@ -32,11 +32,15 @@
var/cell_cover_open = FALSE
///Energy used per print.
var/energy_per_print = INSPECTOR_ENERGY_USAGE_NORMAL
+ ///Does this item scan for contraband correctly? If not, will provide a flipped response.
+ var/scans_correctly = TRUE
/obj/item/inspector/Initialize(mapload)
. = ..()
if(ispath(cell))
cell = new cell(src)
+ register_context()
+ register_item_context()
// Clean up the cell on destroy
/obj/item/inspector/Exited(atom/movable/gone, direction)
@@ -93,6 +97,54 @@
else
. += "\The [cell] is firmly in place. [span_info("Ctrl-click with an empty hand to remove it.")]"
+/obj/item/inspector/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(!user.Adjacent(interacting_with))
+ return ITEM_INTERACT_BLOCKING
+ if(cell_cover_open)
+ balloon_alert(user, "close cover first!")
+ return ITEM_INTERACT_BLOCKING
+ 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))
+ 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
+ if(cell_cover_open && cell)
+ context[SCREENTIP_CONTEXT_CTRL_LMB] = "Remove cell"
+ update_context = TRUE
+
+ if(cell_cover_open && !cell && istype(held_item, /obj/item/stock_parts/power_store/cell))
+ context[SCREENTIP_CONTEXT_LMB] = "Install cell"
+ update_context = TRUE
+
+ if(held_item?.tool_behaviour == TOOL_CROWBAR)
+ context[SCREENTIP_CONTEXT_LMB] = "[cell_cover_open ? "close" : "open"] battery panel"
+ update_context = TRUE
+
+ if(update_context)
+ return CONTEXTUAL_SCREENTIP_SET
+ return NONE
+
+/obj/item/inspector/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
+ if(cell_cover_open || !cell)
+ return NONE
+ if(isitem(target))
+ context[SCREENTIP_CONTEXT_LMB] = "Contraband Scan"
+ return CONTEXTUAL_SCREENTIP_SET
+ return NONE
+
/**
* Create our report
*
@@ -178,6 +230,7 @@
* Can be crafted into a bananium HONK-spect scanner
*/
/obj/item/inspector/clown
+ scans_correctly = FALSE
///will only cycle through modes with numbers lower than this
var/max_mode = CLOWN_INSPECTOR_PRINT_SOUND_MODE_LAST
///names of modes, ordered first to last
diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm
index 5660de8d604..f6357b229ef 100644
--- a/code/game/objects/items/robot/ai_upgrades.dm
+++ b/code/game/objects/items/robot/ai_upgrades.dm
@@ -8,6 +8,9 @@
icon = 'icons/obj/devices/circuitry_n_data.dmi'
icon_state = "datadisk3"
+/obj/item/malf_upgrade/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
/obj/item/malf_upgrade/pre_attack(atom/A, mob/living/user, proximity)
if(!proximity)
@@ -37,6 +40,10 @@
icon = 'icons/obj/devices/circuitry_n_data.dmi'
icon_state = "datadisk3"
+/obj/item/surveillance_upgrade/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
/obj/item/surveillance_upgrade/pre_attack(atom/A, mob/living/user, proximity)
if(!proximity)
return ..()
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 6fa32ae31e2..9a3e45fac42 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -213,6 +213,10 @@
icon_state = "cyborg_upgrade3"
require_model = TRUE
+/obj/item/borg/upgrade/syndicate/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/borg, mob/living/user = usr)
. = ..()
if(!.)
diff --git a/code/game/objects/items/stickers.dm b/code/game/objects/items/stickers.dm
index a02cfd9515e..19ac58f6f40 100644
--- a/code/game/objects/items/stickers.dm
+++ b/code/game/objects/items/stickers.dm
@@ -174,6 +174,10 @@
icon_state = "synd"
contraband = TRUE
+/obj/item/sticker/syndicate/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
/obj/item/sticker/syndicate/c4
name = "C-4 sticker"
icon_state = "c4"
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 5ae6e8d9fa6..77ca77e8ba0 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -387,6 +387,7 @@
AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE, INVISIBILITY_OBSERVER, use_anchor = TRUE)
atom_storage.max_total_storage = 15
atom_storage.set_holdable(cant_hold_list = /obj/item/storage/backpack/satchel/flat) //muh recursive backpacks
+ ADD_TRAIT(src, TRAIT_CONTRABAND_BLOCKER, INNATE_TRAIT)
/obj/item/storage/backpack/satchel/flat/PopulateContents()
for(var/items in 1 to 4)
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index ecd85253c21..307b4b7324b 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -85,6 +85,7 @@ Striking a noncultist, however, will tear their flesh."}
speed = 4 SECONDS, \
effectiveness = 100, \
)
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
/obj/item/melee/cultblade/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(IS_CULTIST(owner) && prob(final_block_chance))
@@ -658,6 +659,10 @@ Striking a noncultist, however, will tear their flesh."}
righthand_file = 'icons/mob/inhands/items/drinks_righthand.dmi'
list_reagents = list(/datum/reagent/fuel/unholywater = 50)
+/obj/item/reagent_containers/cup/beaker/unholywater/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
///how many times can the shuttle be cursed?
#define MAX_SHUTTLE_CURSES 3
///if the max number of shuttle curses are used within this duration, the entire cult gets an achievement
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index 5067dcf9799..2cdb2c2e6f4 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -131,6 +131,7 @@
COOLDOWN_START(src, use_cooldown, use_cooldown_duration)
for(var/item_to_make in spawned_items)
var/obj/item/made_item = new item_to_make(get_turf(src))
+ ADD_TRAIT(made_item, TRAIT_CONTRABAND, INNATE_TRAIT)
succcess_message(user, made_item)
diff --git a/code/modules/antagonists/cult/datums/cultist.dm b/code/modules/antagonists/cult/datums/cultist.dm
index b0fbea4421a..f56d79a8f4b 100644
--- a/code/modules/antagonists/cult/datums/cultist.dm
+++ b/code/modules/antagonists/cult/datums/cultist.dm
@@ -151,7 +151,8 @@
///Attempts to make a new item and put it in a potential inventory slot in the provided mob.
/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
- var/item = new item_path(mob)
+ var/obj/item = new item_path(mob)
+ ADD_TRAIT(item, TRAIT_CONTRABAND, INNATE_TRAIT)
var/where = mob.equip_conspicuous_item(item)
if(!where)
to_chat(mob, span_userdanger("Unfortunately, you weren't able to get [item]. This is very bad and you should adminhelp immediately (press F1)."))
diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm
index 6cfa8db0560..5b78d1b7efb 100644
--- a/code/modules/antagonists/heretic/heretic_knowledge.dm
+++ b/code/modules/antagonists/heretic/heretic_knowledge.dm
@@ -155,7 +155,9 @@
return FALSE
for(var/result in result_atoms)
- new result(loc)
+ var/atom/result_item = new result(loc)
+ if(isitem(result_item))
+ ADD_TRAIT(result_item, TRAIT_CONTRABAND, INNATE_TRAIT)
return TRUE
/**
diff --git a/code/modules/antagonists/heretic/items/heretic_armor.dm b/code/modules/antagonists/heretic/items/heretic_armor.dm
index 45ddea163fa..0c64e4a227e 100644
--- a/code/modules/antagonists/heretic/items/heretic_armor.dm
+++ b/code/modules/antagonists/heretic/items/heretic_armor.dm
@@ -97,6 +97,7 @@
. = ..()
create_storage(storage_type = /datum/storage/pockets/void_cloak)
make_visible()
+ ADD_TRAIT(src, TRAIT_CONTRABAND_BLOCKER, INNATE_TRAIT)
/obj/item/clothing/suit/hooded/cultrobes/void/equipped(mob/user, slot)
. = ..()
diff --git a/code/modules/antagonists/wizard/equipment/spellbook_entries/_entry.dm b/code/modules/antagonists/wizard/equipment/spellbook_entries/_entry.dm
index 0586d7ea6da..7dc220d516f 100644
--- a/code/modules/antagonists/wizard/equipment/spellbook_entries/_entry.dm
+++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/_entry.dm
@@ -203,6 +203,11 @@
log_spellbook("[key_name(user)] bought [src] for [cost] points")
SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
log_purchase(user.key)
+
+ ADD_TRAIT(spawned_path, TRAIT_CONTRABAND, INNATE_TRAIT)
+ for(var/obj/contained as anything in spawned_path.contents)
+ ADD_TRAIT(contained, TRAIT_CONTRABAND, INNATE_TRAIT)
+
try_equip_item(user, spawned_path)
return spawned_path
diff --git a/code/modules/cargo/bounties/security.dm b/code/modules/cargo/bounties/security.dm
index cc83aa228a8..8281408c179 100644
--- a/code/modules/cargo/bounties/security.dm
+++ b/code/modules/cargo/bounties/security.dm
@@ -1,8 +1,8 @@
/datum/bounty/item/security/recharger
- name = "Rechargers"
- description = "Nanotrasen military academy is conducting marksmanship exercises. They request that rechargers be shipped."
+ name = "Weapon Recharger"
+ description = "Nanotrasen military academy is conducting marksmanship exercises. They request that a recharger be shipped."
reward = CARGO_CRATE_VALUE * 4
- required_count = 3
+ required_count = 1
wanted_types = list(/obj/machinery/recharger = TRUE)
/datum/bounty/item/security/pepperspray
@@ -81,3 +81,13 @@
if(istype(slip.scanned_area, demanded_area))
return TRUE
return FALSE
+
+/datum/bounty/item/security/contraband
+ name = "Confiscated Contraband"
+ description = "The syndicate are constantly acting to subvert crewmates of Nanotrasen afilliated stations. Ship us your latest batch of confiscated contraband."
+ reward = CARGO_CRATE_VALUE * 4
+ required_count = 5
+ wanted_types = list(/obj/item = TRUE)
+
+/datum/bounty/item/security/contraband/applies_to(obj/O)
+ return HAS_TRAIT(O, TRAIT_CONTRABAND)
diff --git a/code/modules/cargo/markets/_market.dm b/code/modules/cargo/markets/_market.dm
index 78585ed842f..7bef341842f 100644
--- a/code/modules/cargo/markets/_market.dm
+++ b/code/modules/cargo/markets/_market.dm
@@ -10,6 +10,8 @@
var/list/available_items = list()
/// Item categories available from this market, only items which are in these categories can be gotten from this market. Automatically assigned, so don't manually adjust.
var/list/categories = list()
+ /// Are the items from this market legal or illegal? If illegal, apply a contrband trait to the bought object.
+ var/legal_status = TRUE
/// Adds item to the available items and add it's category if it is not in categories yet.
/datum/market/proc/add_item(datum/market_item/item)
@@ -30,7 +32,15 @@
if(!length(available_items[item.category]))
available_items -= item.category
-/// Handles buying the item, this is mainly for future use and moving the code away from the uplink.
+/**
+ * Handles buying the item for a market.
+ *
+ * @param identifier The identifier of the item to buy.
+ * @param category The category of the item to buy.
+ * @param method The shipping method to use to get the item on the station.
+ * @param uplink The uplink object that is buying the item.
+ * @param user The mob that is buying the item.
+ */
/datum/market/proc/purchase(identifier, category, method, obj/item/market_uplink/uplink, user)
var/datum/market_item/item = available_items[category][identifier]
if(isnull(item))
@@ -54,7 +64,7 @@
to_chat(user, span_warning("You don't have enough credits in [uplink] for [item] with [method] shipping."))
return FALSE
- if(item.buy(uplink, user, method))
+ if(item.buy(uplink, user, method, legal_status))
uplink.current_user.adjust_money(-price, "Other: Third Party Transaction")
if(ismob(user))
var/mob/m_user = user
@@ -70,3 +80,4 @@
SHIPPING_METHOD_LAUNCH = 10,
SHIPPING_METHOD_TELEPORT= 75,
)
+ legal_status = FALSE
diff --git a/code/modules/cargo/markets/market_item.dm b/code/modules/cargo/markets/market_item.dm
index 21ff3d01deb..5e3ce4efb6c 100644
--- a/code/modules/cargo/markets/market_item.dm
+++ b/code/modules/cargo/markets/market_item.dm
@@ -81,8 +81,15 @@
return new item(loc)
CRASH("Invalid item type for market item [item || "null"]")
-/// Buys the item and makes SSblackmarket handle it.
-/datum/market_item/proc/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method)
+/**
+ * Buys the item and makes SSblackmarket handle it.
+ *
+ * @param uplink The uplink that is buying the item.
+ * @param buyer The mob that is buying the item.
+ * @param shipping_method The shipping method used to get the market item onto the station.
+ * @param legal_status The legal status of the market. Determines if the item to be spawned is contraband.
+ */
+/datum/market_item/proc/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method, legal_status)
SHOULD_CALL_PARENT(TRUE)
// Sanity
if(!istype(uplink) || !istype(buyer))
@@ -93,7 +100,7 @@
return FALSE
// Alright, the item has been purchased.
- var/datum/market_purchase/purchase = new(src, uplink, shipping_method)
+ var/datum/market_purchase/purchase = new(src, uplink, shipping_method, legal_status)
// SSblackmarket takes care of the shipping.
if(SSblackmarket.queue_item(purchase))
@@ -102,6 +109,7 @@
return TRUE
return FALSE
+
// This exists because it is easier to keep track of all the vars this way.
/datum/market_purchase
/// The entry being purchased.
@@ -112,13 +120,16 @@
var/obj/item/market_uplink/uplink
/// Shipping method used to buy this item.
var/method
+ /// Is this item considered contraband? If illegal, applies the contraband trait to the item when spawned.
+ var/legallity
-/datum/market_purchase/New(datum/market_item/entry, obj/item/market_uplink/uplink, method)
+/datum/market_purchase/New(datum/market_item/entry, obj/item/market_uplink/uplink, method, legal_status)
if(!uplink || !entry || !method)
CRASH("[type] created with a false value arg: (entry: [entry] - uplink: [uplink] - method: [method])")
src.entry = entry
src.uplink = uplink
src.method = method
+ src.legallity = legal_status
RegisterSignal(entry, COMSIG_QDELETING, PROC_REF(on_instance_del))
RegisterSignal(uplink, COMSIG_QDELETING, PROC_REF(on_instance_del))
if(ismovable(entry.item))
@@ -137,3 +148,13 @@
return
// Uh oh, uplink or item is gone. We will just keep the money and you will not get your order.
qdel(src)
+
+/**
+ * Proc that applies secondary effects to objects that are spawned via a market.
+ *
+ * @param spawned_item - Reference to the atom being spawned.
+ * @param legal_status - Is this item considered legal? If illegal, will apply the contraband trait to the spawned item.
+ */
+/datum/market_purchase/proc/post_purchase_effects(atom/spawned_item)
+ if(!legallity && isobj(spawned_item))
+ ADD_TRAIT(spawned_item, TRAIT_CONTRABAND, INNATE_TRAIT)
diff --git a/code/modules/cargo/markets/market_telepad.dm b/code/modules/cargo/markets/market_telepad.dm
index 4545b07e487..7c5b509a942 100644
--- a/code/modules/cargo/markets/market_telepad.dm
+++ b/code/modules/cargo/markets/market_telepad.dm
@@ -91,6 +91,7 @@
if(receiving)
receiving.item = receiving.entry.spawn_item(turf, receiving)
+ receiving.post_purchase_effects(receiving.item)
use_energy(energy_usage_per_teleport / power_efficiency)
var/datum/effect_system/spark_spread/sparks = new
diff --git a/code/modules/cargo/markets/market_uplink.dm b/code/modules/cargo/markets/market_uplink.dm
index df8c8eb36a5..d13f59937b6 100644
--- a/code/modules/cargo/markets/market_uplink.dm
+++ b/code/modules/cargo/markets/market_uplink.dm
@@ -157,6 +157,9 @@
accessible_markets = list(/datum/market/blackmarket)
custom_premium_price = PAYCHECK_CREW * 2.5
+/obj/item/market_uplink/blackmarket/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
/datum/crafting_recipe/blackmarket_uplink
name = "Black Market Uplink"
diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm
index 3f8ceb5ca02..c675352d024 100644
--- a/code/modules/cargo/order.dm
+++ b/code/modules/cargo/order.dm
@@ -185,6 +185,9 @@
else
account_holder = "Cargo"
var/obj/structure/closet/crate/crate = pack.generate(A, paying_account)
+ if(pack.contraband)
+ for(var/atom/movable/item_within as anything in crate.get_all_contents())
+ ADD_TRAIT(item_within, TRAIT_CONTRABAND, INNATE_TRAIT)
if(department_destination)
crate.AddElement(/datum/element/deliver_first, department_destination, pack.cost)
generateManifest(crate, account_holder, pack, pack.cost)
diff --git a/code/modules/cargo/orderconsole.dm b/code/modules/cargo/orderconsole.dm
index 2f91ad4c820..d835c52f1e8 100644
--- a/code/modules/cargo/orderconsole.dm
+++ b/code/modules/cargo/orderconsole.dm
@@ -178,6 +178,7 @@
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
"goody" = P.goody,
"access" = P.access,
+ "contraband" = P.contraband,
))
return data
diff --git a/code/modules/cargo/packs/_packs.dm b/code/modules/cargo/packs/_packs.dm
index 662938320cb..b6c533050f6 100644
--- a/code/modules/cargo/packs/_packs.dm
+++ b/code/modules/cargo/packs/_packs.dm
@@ -77,6 +77,7 @@
continue
A.flags_1 |= ADMIN_SPAWNED_1
+
/// For generating supply packs at runtime. Returns a list of supply packs to use instead of this one.
/datum/supply_pack/proc/generate_supply_packs()
return
diff --git a/code/modules/clothing/chameleon/generic_chameleon_clothing.dm b/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
index 63bede9ec88..47b6f4db185 100644
--- a/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
+++ b/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
@@ -252,6 +252,10 @@ do { \
name = "backpack"
actions_types = list(/datum/action/item_action/chameleon/change/backpack)
+/obj/item/storage/backpack/chameleon/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND_BLOCKER, INNATE_TRAIT)
+
/obj/item/storage/backpack/chameleon/broken
/obj/item/storage/backpack/chameleon/broken/Initialize(mapload)
diff --git a/code/modules/hydroponics/grown/kronkus.dm b/code/modules/hydroponics/grown/kronkus.dm
index e0b6e6b66aa..90d264230e7 100644
--- a/code/modules/hydroponics/grown/kronkus.dm
+++ b/code/modules/hydroponics/grown/kronkus.dm
@@ -16,6 +16,10 @@
growing_icon = 'icons/obj/service/hydroponics/growing.dmi'
reagents_add = list(/datum/reagent/consumable/nutriment = 0.05)
+/obj/item/seeds/kronkus/Initialize(mapload, nogenes)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
/obj/item/food/grown/kronkus
seed = /obj/item/seeds/kronkus
name = "kronkus vine segment"
@@ -24,3 +28,7 @@
filling_color = "#37946e"
foodtypes = VEGETABLES | TOXIC
distill_reagent = /datum/reagent/kronkus_extract
+
+/obj/item/food/grown/kronkus/Initialize(mapload, nogenes)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm
index c6d0869c6e9..b74f05408a0 100644
--- a/code/modules/mod/mod_types.dm
+++ b/code/modules/mod/mod_types.dm
@@ -351,6 +351,9 @@
/obj/item/mod/module/quick_cuff,
)
+/obj/item/mod/control/pre_equipped/infiltrator/Initialize(mapload, new_theme, new_skin, new_core)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND_BLOCKER, INNATE_TRAIT)
/obj/item/mod/control/pre_equipped/interdyne
theme = /datum/mod_theme/interdyne
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 9fffd5ccc7c..06537e591c9 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -316,6 +316,10 @@
name = "unlabeled syringe"
desc = "A syringe containing some sort of unknown chemical cocktail."
+/obj/item/reagent_containers/syringe/contraband/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
/obj/item/reagent_containers/syringe/contraband/space_drugs
list_reagents = list(/datum/reagent/drug/space_drugs = 15)
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index b8b11e7b44f..7572a735292 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -660,7 +660,7 @@
category = list(
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_MEDICAL
)
- departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE
+ departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_SECURITY | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_MEDICAL
/datum/design/board/holopad
name = "AI Holopad Board"
diff --git a/code/modules/research/techweb/nodes/syndicate_nodes.dm b/code/modules/research/techweb/nodes/syndicate_nodes.dm
index 377ac392f93..7743b9442f8 100644
--- a/code/modules/research/techweb/nodes/syndicate_nodes.dm
+++ b/code/modules/research/techweb/nodes/syndicate_nodes.dm
@@ -33,7 +33,7 @@
required_items_to_unlock = list()
for(var/datum/uplink_item/item_path as anything in SStraitor.uplink_items_by_type)
var/datum/uplink_item/item = SStraitor.uplink_items_by_type[item_path]
- if(!item.item || !item.illegal_tech)
+ if(!item.item || !(item.uplink_item_flags & SYNDIE_ILLEGAL_TECH))
continue
required_items_to_unlock |= item.item //allows deconning to unlock.
diff --git a/code/modules/surgery/organs/autosurgeon.dm b/code/modules/surgery/organs/autosurgeon.dm
index 6e3d9a0ee7c..0bb8afc6ced 100644
--- a/code/modules/surgery/organs/autosurgeon.dm
+++ b/code/modules/surgery/organs/autosurgeon.dm
@@ -149,6 +149,10 @@
surgery_speed = 0.75
loaded_overlay = "autosurgeon_syndicate_loaded_overlay"
+/obj/item/autosurgeon/syndicate/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
+
/obj/item/autosurgeon/syndicate/laser_arm
desc = "A single use autosurgeon that contains a combat arms-up laser augment. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index e17488bc96a..bf963587ae1 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -78,8 +78,8 @@
var/purchase_log_vis = TRUE // Visible in the purchase log?
/// Whether this purchase is restricted or not (VR/Events related)
var/restricted = FALSE
- /// Can this item be deconstructed to unlock certain techweb research nodes?
- var/illegal_tech = TRUE
+ /// Flags related to if an item will provide illegal tech, or trips contraband detectors once spawned in as an item.
+ var/uplink_item_flags = SYNDIE_ILLEGAL_TECH | SYNDIE_TRIPS_CONTRABAND
/// String to be shown instead of the price, e.g for the Random item.
var/cost_override_string = ""
/// Whether this item locks all other items from being purchased. Used by syndicate balloon and a few other purchases.
@@ -142,6 +142,12 @@
spawned_item = spawn_path
if(refundable)
spawned_item.AddElement(/datum/element/uplink_reimburse, (refund_amount ? refund_amount : cost))
+
+
+ if(uplink_item_flags & SYNDIE_TRIPS_CONTRABAND) // Ignore things that shouldn't be detectable as contraband on the station.
+ ADD_TRAIT(spawned_item, TRAIT_CONTRABAND, INNATE_TRAIT)
+ for(var/obj/contained as anything in spawned_item.get_all_contents())
+ ADD_TRAIT(contained, TRAIT_CONTRABAND, INNATE_TRAIT)
var/mob/living/carbon/human/human_user = user
if(istype(human_user) && isitem(spawned_item) && human_user.put_in_hands(spawned_item))
to_chat(human_user, span_boldnotice("[spawned_item] materializes into your hands!"))
@@ -154,8 +160,10 @@
/// Can be used to "de-restrict" some items, such as Nukie guns spawning with Syndicate pins
/datum/uplink_item/proc/spawn_item_for_generic_use(mob/user)
var/atom/movable/created = new item(user.loc)
-
- if(isgun(created))
+ if(uplink_item_flags & SYNDIE_TRIPS_CONTRABAND) // Things that shouldn't be detectable as contraband on the station.
+ ADD_TRAIT(created, TRAIT_CONTRABAND, INNATE_TRAIT)
+ for(var/obj/contained as anything in created.get_all_contents())
+ ADD_TRAIT(contained, TRAIT_CONTRABAND, INNATE_TRAIT)
replace_pin(created)
else if(istype(created, /obj/item/storage/toolbox/guncase))
for(var/obj/item/gun/gun in created)
@@ -205,7 +213,7 @@
name = "Objective-Specific Equipment"
desc = "Equipment necessary for accomplishing specific objectives. If you are seeing this, something has gone wrong."
limited_stock = 1
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
purchasable_from = parent_type::purchasable_from & ~UPLINK_SPY // Ditto
/datum/uplink_item/special_equipment/purchase(mob/user, datum/component/uplink/U)
diff --git a/code/modules/uplink/uplink_items/ammunition.dm b/code/modules/uplink/uplink_items/ammunition.dm
index 705204f98a1..2276485a2b7 100644
--- a/code/modules/uplink/uplink_items/ammunition.dm
+++ b/code/modules/uplink/uplink_items/ammunition.dm
@@ -12,7 +12,7 @@
item = /obj/item/ammo_box/foambox/riot
cost = 2
surplus = 0
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
purchasable_from = ~UPLINK_SERIOUS_OPS
/datum/uplink_item/ammo/pistol
@@ -21,7 +21,7 @@
item = /obj/item/ammo_box/magazine/m9mm
cost = 1
purchasable_from = ~UPLINK_ALL_SYNDIE_OPS
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/ammo/pistolap
name = "9mm Armour Piercing Magazine"
@@ -54,4 +54,4 @@
item = /obj/item/ammo_box/a357
cost = 4
purchasable_from = ~(UPLINK_ALL_SYNDIE_OPS | UPLINK_SPY) //nukies get their own version
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
diff --git a/code/modules/uplink/uplink_items/badass.dm b/code/modules/uplink/uplink_items/badass.dm
index da7212ee8fc..08cf3affe07 100644
--- a/code/modules/uplink/uplink_items/badass.dm
+++ b/code/modules/uplink/uplink_items/badass.dm
@@ -14,7 +14,7 @@
cost = 20
lock_other_purchases = TRUE
cant_discount = TRUE
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/badass/balloon/spawn_item(spawn_path, mob/user, datum/uplink_handler/uplink_handler, atom/movable/source)
. = ..()
@@ -36,14 +36,14 @@
item = /obj/item/toy/cards/deck/syndicate
cost = 1
surplus = 40
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/badass/syndiecigs
name = "Syndicate Smokes"
desc = "Strong flavor, dense smoke, infused with omnizine."
item = /obj/item/storage/fancy/cigarettes/cigpack_syndicate
cost = 2
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/badass/syndiecash
name = "Syndicate Briefcase Full of Cash"
@@ -53,7 +53,7 @@
item = /obj/item/storage/briefcase/secure/syndie
cost = 3
restricted = TRUE
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/badass/costumes/clown
name = "Clown Costume"
diff --git a/code/modules/uplink/uplink_items/clownops.dm b/code/modules/uplink/uplink_items/clownops.dm
index 56c11fedc0c..6dce44aeef8 100644
--- a/code/modules/uplink/uplink_items/clownops.dm
+++ b/code/modules/uplink/uplink_items/clownops.dm
@@ -35,7 +35,7 @@
cost = 1 //much cheaper for clown ops than for clowns
item = /obj/item/firing_pin/clown/ultra
purchasable_from = UPLINK_CLOWN_OPS
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/weapon_kits/clownopsuperpin
name = "Super Ultra Hilarious Firing Pin"
@@ -43,7 +43,7 @@
cost = 4 //much cheaper for clown ops than for clowns
item = /obj/item/firing_pin/clown/ultra/selfdestruct
purchasable_from = UPLINK_CLOWN_OPS
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/weapon_kits/foamsmg
name = "Toy Submachine Gun"
@@ -157,4 +157,4 @@
item = /obj/item/dnainjector/clumsymut
cost = 1
purchasable_from = UPLINK_CLOWN_OPS
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
diff --git a/code/modules/uplink/uplink_items/dangerous.dm b/code/modules/uplink/uplink_items/dangerous.dm
index 11cca6c4426..691f4f2c8f3 100644
--- a/code/modules/uplink/uplink_items/dangerous.dm
+++ b/code/modules/uplink/uplink_items/dangerous.dm
@@ -29,7 +29,7 @@
throwing weapons. The bolas can knock a target down and the shurikens will embed into limbs."
item = /obj/item/storage/box/syndie_kit/throwing_weapons
cost = 3
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/dangerous/sword
name = "Energy Sword"
diff --git a/code/modules/uplink/uplink_items/device_tools.dm b/code/modules/uplink/uplink_items/device_tools.dm
index c1b0f8b2e02..714c3133482 100644
--- a/code/modules/uplink/uplink_items/device_tools.dm
+++ b/code/modules/uplink/uplink_items/device_tools.dm
@@ -12,7 +12,7 @@
item = /obj/item/soap/syndie
cost = 1
surplus = 50
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/device_tools/surgerybag
name = "Syndicate Surgery Duffel Bag"
@@ -111,7 +111,7 @@
item = /obj/item/disk/nuclear/fake
cost = 1
surplus = 1
- illegal_tech = FALSE
+ uplink_item_flags = NONE
/datum/uplink_item/device_tools/frame
name = "F.R.A.M.E. disk"
@@ -163,7 +163,7 @@
multitool and combat gloves that are resistant to shocks and heat."
item = /obj/item/storage/toolbox/syndicate
cost = 1
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/device_tools/rad_laser
name = "Radioactive Microlaser"
diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm
index b010755d67e..d9bcce6411f 100644
--- a/code/modules/uplink/uplink_items/job.dm
+++ b/code/modules/uplink/uplink_items/job.dm
@@ -21,7 +21,7 @@
desc = "A box of five (5) counterfeit devices. Each single-use device can hold one normal sized object, and impersonate an ordinary postal envelope addressed to whoever you choose. Optionally, can be rigged to activate held items - great for if you want to surprise someone with a primed grenade!"
item = /obj/item/storage/box/syndie_kit/mail_counterfeit
cost = 2
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
restricted_roles = list(JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER)
surplus = 5
@@ -45,7 +45,7 @@
item = /obj/item/dnainjector/clumsymut
cost = 1
restricted_roles = list(JOB_CLOWN)
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
surplus = 25
/datum/uplink_item/role_restricted/ancient_jumpsuit
@@ -70,7 +70,7 @@
cost = 4
item = /obj/item/firing_pin/clown/ultra
restricted_roles = list(JOB_CLOWN)
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
surplus = 25
/datum/uplink_item/role_restricted/clownsuperpin
@@ -79,7 +79,7 @@
cost = 7
item = /obj/item/firing_pin/clown/ultra/selfdestruct
restricted_roles = list(JOB_CLOWN)
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
surplus = 25
/datum/uplink_item/role_restricted/syndimmi
diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm
index 4f50994bc40..fa42be0d54d 100644
--- a/code/modules/uplink/uplink_items/nukeops.dm
+++ b/code/modules/uplink/uplink_items/nukeops.dm
@@ -385,7 +385,7 @@
item = /obj/item/ammo_box/magazine/plastikov9mm
cost = 1
purchasable_from = UPLINK_SERIOUS_OPS
- illegal_tech = FALSE
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
// Explosives and Grenades
// ~~ Grenades ~~
diff --git a/code/modules/uplink/uplink_items/spy_unique.dm b/code/modules/uplink/uplink_items/spy_unique.dm
index b53cf60cefd..7d2f5fb34cb 100644
--- a/code/modules/uplink/uplink_items/spy_unique.dm
+++ b/code/modules/uplink/uplink_items/spy_unique.dm
@@ -10,12 +10,14 @@
// Cost doesn't really matter since it's free, but it determines which loot pool it falls into.
// By default, these fall into easy-medium spy bounty loot pool
cost = SPY_LOWER_COST_THRESHOLD
+ uplink_item_flags = NONE
/datum/uplink_item/spy_unique/syndie_bowman
name = "Syndicate Bowman"
desc = "A bowman headset for members of the Syndicate. Not very conspicuous."
item = /obj/item/radio/headset/syndicate/alt
cost = 1
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH
/datum/uplink_item/spy_unique/megaphone
name = "Megaphone"
@@ -43,6 +45,7 @@
name = "Kudzu"
desc = "A packet of Kudzu - plant and forget, a great distraction."
item = /obj/item/seeds/kudzu
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/big_knife
name = "Combat Knife"
@@ -53,6 +56,7 @@
name = "Switchblade"
desc = "A switchblade. Switches between not sharp and sharp."
item = /obj/item/switchblade
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/sechud_implant
name = "SecHUD Implant"
@@ -64,30 +68,35 @@
desc = "A bolt-action rifle, with a scope. Won't jam, either."
item = /obj/item/gun/ballistic/rifle/boltaction/prime
cost = SPY_UPPER_COST_THRESHOLD
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH | SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/cycler_shotgun
name = "Cycler Shotgun"
desc = "A cycler shotgun. It's a shotgun that cycles between two barrels."
item = /obj/item/gun/ballistic/shotgun/automatic/dual_tube/deadly
cost = SPY_UPPER_COST_THRESHOLD
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH | SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/bulldog_shotgun
name = "Bulldog Shotgun"
desc = "A bulldog shotgun. It's a shotgun that shoots bulldogs."
item = /obj/item/gun/ballistic/shotgun/bulldog/unrestricted
cost = SPY_UPPER_COST_THRESHOLD
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH | SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/ansem_pistol
name = "Ansem Pistol"
desc = "A pistol that's really good at making people sleep."
item = /obj/item/gun/ballistic/automatic/pistol/clandestine
cost = SPY_UPPER_COST_THRESHOLD
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH | SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/rocket_launcher
name = "Rocket Launcher"
desc = "A rocket launcher. I would recommend against jumping with it."
item = /obj/item/gun/ballistic/rocketlauncher
cost = SPY_UPPER_COST_THRESHOLD - 1 // It's a meme item
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH | SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/shotgun_ammo
name = "Box of Buckshot"
@@ -110,17 +119,20 @@
desc = "A stealth belt that lets you sneak behind enemy lines."
item = /obj/item/shadowcloak/weaker
cost = SPY_UPPER_COST_THRESHOLD
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH
/datum/uplink_item/spy_unique/katana
name = "Katana"
desc = "A really sharp Katana. Did I mention it's sharp?"
item = /obj/item/katana
cost = /datum/uplink_item/dangerous/doublesword::cost // Puts it in the same pool as Desword
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH | SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/medkit_lite
name = "Syndicate First Medic Kit"
desc = "A syndicate tactical combat medkit, but only stocked enough to do basic first aid."
item = /obj/item/storage/medkit/tactical_lite
+ uplink_item_flags = SYNDIE_TRIPS_CONTRABAND
/datum/uplink_item/spy_unique/antistun
name = /datum/uplink_item/implants/nuclear/antistun::name
diff --git a/code/modules/uplink/uplink_items/stealthy.dm b/code/modules/uplink/uplink_items/stealthy.dm
index 898b82d1b6a..e4c4de412fb 100644
--- a/code/modules/uplink/uplink_items/stealthy.dm
+++ b/code/modules/uplink/uplink_items/stealthy.dm
@@ -4,6 +4,7 @@
/datum/uplink_item/stealthy_weapons
category = /datum/uplink_category/stealthy
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH
/datum/uplink_item/stealthy_weapons/dart_pistol
diff --git a/code/modules/uplink/uplink_items/stealthy_tools.dm b/code/modules/uplink/uplink_items/stealthy_tools.dm
index a225d04d667..48c25e638de 100644
--- a/code/modules/uplink/uplink_items/stealthy_tools.dm
+++ b/code/modules/uplink/uplink_items/stealthy_tools.dm
@@ -4,6 +4,7 @@
/datum/uplink_item/stealthy_tools
category = /datum/uplink_category/stealthy_tools
+ uplink_item_flags = SYNDIE_ILLEGAL_TECH
/datum/uplink_item/stealthy_tools/agent_card
@@ -90,7 +91,7 @@
item = /obj/item/storage/backpack/satchel/flat/with_tools
cost = 1
surplus = 30
- illegal_tech = FALSE
+ uplink_item_flags = NONE
/datum/uplink_item/stealthy_tools/mail_counterfeit
name = "GLA Brand Mail Counterfeit Device"
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 737a2993d9b..336f3b72ce1 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -1445,6 +1445,8 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
var/obj/item/vended_item
if(!LAZYLEN(item_record.returned_products)) //always give out free returned stuff first, e.g. to avoid walling a traitor objective in a bag behind paid items
vended_item = new item_record.product_path(get_turf(src))
+ if(vended_item.type in contraband)
+ ADD_TRAIT(vended_item, TRAIT_CONTRABAND, INNATE_TRAIT)
on_dispense(vended_item)
else
vended_item = LAZYACCESS(item_record.returned_products, LAZYLEN(item_record.returned_products)) //first in, last out
diff --git a/tgstation.dme b/tgstation.dme
index bb2a7559aa8..550c0429abb 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2036,7 +2036,7 @@
#include "code\game\machinery\recycler.dm"
#include "code\game\machinery\requests_console.dm"
#include "code\game\machinery\roulette_machine.dm"
-#include "code\game\machinery\scan_gate.dm"
+#include "code\game\machinery\scanner_gate.dm"
#include "code\game\machinery\sheetifier.dm"
#include "code\game\machinery\shieldgen.dm"
#include "code\game\machinery\sleepers.dm"
diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx
index baccf90c4bd..aea852ce5e7 100644
--- a/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx
+++ b/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx
@@ -206,6 +206,11 @@ function CatalogList(props: CatalogListProps) {
)}
+ {!!pack.contraband && (
+
+
+
+ )}