From fa2ab65f077466fb3b05fd2ae4beb9e2c9a00aa0 Mon Sep 17 00:00:00 2001 From: SpaceLoveSs13 <68121607+SpaceLoveSs13@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:23:18 +0530 Subject: [PATCH] Missed mirrors (#28919) Handful of missed mirrors (#3739) * fix duplicate traits * Adds a Contraband trait, and implements contraband as a mechanic to security bounties. (#84003) 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. 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. 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.
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. 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). 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. :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: --------- * Adds six new strange object powers! (#84775) DESIGN CONCEPT: Strange Devices are at their best when they're odd tools which can help a department out, with some strange drawbacks that make them interesting and unique. Foam for the Janitor, Flashbang for Security, Teleporter for tiders, Corgimaker for the chef. They're also ambiguous enough that they can really be used by anyone for silly hijinks. Drink Dispenser: Creates a glass, then fills it up with a random drink. Bioscrambler: After a noticeable warning, bioscrambles people nearby. 33% chance to be used up on use. Recharger: Shocks you, but recharges one random item to max battery. Hugger: Hugs everyone in range as if you had the friendly trait. DImensional: Converts the surroundings to a random material-theme. Each use increases cooldown by two seconds. Disguiser: Drops your clothing to the ground and replaces it with a delete-on-drop costume and a randomly assigned cardboard ID. Removed an unused and unusable shock flag. Removed an unused dumb ghost item. Added a proc that returns a hex color with the # attached. > DESIGN CONCEPT: Strange Devices are at their best when they're odd tools which can help a department out, with some strange drawbacks that make them interesting and unique. Foam for the Janitor, Flashbang for Security, Teleporter for tiders, Corgimaker for the chef. They're also ambiguous enough that they can really be used by anyone for silly hijinks. Request by ArcaneMusic! He wanted new abilities to go along with the new sprites, and approved these. > Removed an unused dumb ghost item. please stop using costume subtypes for OP items. whats the damn point of the subtype if youre just going to screw with it > Added a proc that returns a hex color with the # attached. idk why it didnt have this tbh :cl: add: Adds six new strange object powers! Drink dispenser, bioscrambler, recharger, hugger, dimensional, disguiser. code: Removed some unused code and items, and added a proc that returns a random #colorstring. /:cl: * [NO GBP] the random spawner loot weight config is not an integer (#84814) Sets `integer` to false. Also a tidbit about the `skew_loot_weight` proc, though loot lists with uneven weights all tend to add a value to all entries so it isn't an issue. The config isn't an integer. N/A * The techweb no longer erroneously refers to MODsuits as exosuits (#84800) At some point, some of the techweb node descriptions were changed, so that it referred to certain modsuits as exosuits. This just changes it back. The term "exosuit" is generally used for mechs, not modsuits. The techweb descriptions should refer to modsuits as modsuits. :cl: spellcheck: The techweb no longer erroneously refers to MODsuits as exosuits. /:cl: * Adds new hairstyle - Short Bangs 2 (#84804) Adds a new hairstyle called Short Bangs 2. The hairstyle is basically an edit of the existing double buns, except the hair buns themselves are removed. https://github.com/tgstation/tgstation/assets/66234359/38fe3b09-c42b-43e6-9e30-949428aab506 More customization, variety and character flavor is great. Double buns itself is a good hairstyle but some may not like the hair buns out of personal preference or that it can look weird on non-human species like felinids. :cl: Hardly3D add: Added new hairstyle: Short Bangs 2 /:cl: * Offset render relays for non-offsetting planes to match highest matching render plane (#84184) **Alternate title: "Fix blind people getting so blind they become deaf when going down a flight of stairs"** So 'bout half a week to a week ago I overheard a friend complaining about blind people not seeing runechat on lower multi-z levels. Asked a bit, apparently they'd reported this about half a year ago, and it's still an issue. So in my never-ending hubris I decided to just go and fix it! Now, admittedly? I really _really_ do not get the rendering system we use. The simple options were right out: we can't allow the fullscreens plane to be offset, as this causes issues with looking up/down, or disallow runechat from being offset, which causes issues with runechat from other levels. After poking our very cool and smart rendering guy several times over the course of the last week, this is what we got to: We simply make the rendering relays for non-offsetting plane masters point to the highest rendering plane that matches the target. We do this by offsetting the rendering relays in place, by adjusting their plane and layer values to match the new offset, with a new `offset_relays_in_place(new_offset)` proc called in `/datum/plane_master_group/proc/transform_lower_turfs(...)`. Importantly, we compare the current layer values to what they should've been, so we don't accidentally override relays with custom-set layers. This fixes our issue (as tested on wawastation):
Images ![image](https://github.com/tgstation/tgstation/assets/42909981/c6a10e04-dd08-4642-bc4d-d99ae5004a40) ![image](https://github.com/tgstation/tgstation/assets/42909981/740dc894-7495-4c35-b729-ffcc539ca928) ![image](https://github.com/tgstation/tgstation/assets/42909981/986433a7-e66e-408a-8e77-1f1eb89cb67c)
Fixes #80376. :cl: fix: You can see runechat above fullscreen overlays on lower multi-z levels again. Rejoice, blind players. Please report any weird rendering layering issues. /:cl: * illegal tech flag got changed * Automatic changelog for PR #84003 [ci skip] * Automatic changelog for PR #84775 [ci skip] * Automatic changelog for PR #84800 [ci skip] * Automatic changelog for PR #84804 [ci skip] * Automatic changelog for PR #84184 [ci skip] * Makes the smoking pipe sprite not give you a phantom stache. (#84898) The smoking pipe currently gives you a phantom stache. Observe, note the black background and know this character has no facial hair. ![image](https://github.com/tgstation/tgstation/assets/70115628/2939afa9-e4e4-4ee2-b38b-fc517e207d01) I basically adjusted the pixels so it'd look better from different directions. This is the new look - approximately. ![image](https://github.com/tgstation/tgstation/assets/70115628/55e23d8e-2367-468a-94c2-9c5741f34762) Smoking pipe is cool for RP but the sprite's fucked. :cl: image: the smoking pipe's directional looks have been altered to make it less ugly /:cl: (cherry picked from commit c499c51bb3da8f6097691fe4f4028948f29767db) * Automatic changelog for PR #84898 [ci skip] (cherry picked from commit 1e80a72deed629a27c394c2bb2a66bb7936ecfc4) * Revert "Automatic changelog for PR #84898 [ci skip]" This reverts commit 1ddc7d43de30bb7ef029d1ddd39f86ded94e110c. * Revert "Makes the smoking pipe sprite not give you a phantom stache. (#84898)" This reverts commit b66b9d634e5f28e40e800586d4642468049767e6. --------- Co-authored-by: FlufflesTheDog Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: carlarctg <53100513+carlarctg@users.noreply.github.com> Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> Co-authored-by: GPeckman <21979502+GPeckman@users.noreply.github.com> Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com> Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com> Co-authored-by: orange man <61334995+comfyorange@users.noreply.github.com> Co-authored-by: NewyearnewmeUwu <70115628+NewyearnewmeUwu@users.noreply.github.com> Co-authored-by: SomeRandomOwl <2568378+SomeRandomOwl@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/antagonists.dm | 5 + code/__DEFINES/blackmarket.dm | 1 + code/__DEFINES/devices.dm | 1 + code/__DEFINES/layers.dm | 9 + code/__DEFINES/traits/declarations.dm | 7 +- code/__HELPERS/atoms.dm | 12 ++ code/__HELPERS/reagents.dm | 10 ++ code/__HELPERS/text.dm | 3 + code/_globalvars/traits/_traits.dm | 8 +- code/_onclick/hud/hud.dm | 9 +- .../hud/rendering/plane_master_group.dm | 18 +- .../rendering/plane_masters/_plane_master.dm | 6 +- .../plane_masters/plane_master_subtypes.dm | 12 +- code/_onclick/hud/rendering/render_plate.dm | 39 +++++ .../configuration/entries/game_options.dm | 1 + code/controllers/subsystem/blackmarket.dm | 4 +- code/controllers/subsystem/mapping.dm | 2 +- code/datums/sprite_accessories.dm | 4 + .../{scan_gate.dm => scanner_gate.dm} | 60 ++++++- .../anomalies/anomalies_bioscrambler.dm | 6 +- .../objects/effects/posters/contraband.dm | 4 + .../effects/spawners/random/contraband.dm | 6 + .../objects/effects/spawners/random/random.dm | 2 +- 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 + .../client/preferences/multiz_parallax.dm | 2 +- .../client/preferences/multiz_performance.dm | 2 +- .../chameleon/generic_chameleon_clothing.dm | 4 + code/modules/clothing/suits/ghostsheet.dm | 12 +- code/modules/hydroponics/grown/kronkus.dm | 8 + .../mob/living/carbon/carbon_defense.dm | 6 +- .../mob/living/carbon/human/human_defense.dm | 2 +- code/modules/mod/mod_types.dm | 3 + .../reagents/reagent_containers/syringes.dm | 4 + .../research/designs/machine_designs.dm | 2 +- code/modules/research/experimentor.dm | 164 ++++++++++++++++++ .../research/techweb/nodes/mech_nodes.dm | 40 ++--- .../research/techweb/nodes/modsuit_nodes.dm | 8 +- .../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 + html/changelogs/AutoChangeLog-pr-84003.yml | 10 ++ html/changelogs/AutoChangeLog-pr-84184.yml | 4 + html/changelogs/AutoChangeLog-pr-84775.yml | 5 + html/changelogs/AutoChangeLog-pr-84800.yml | 4 + html/changelogs/AutoChangeLog-pr-84804.yml | 4 + icons/mob/human/human_face.dmi | Bin 105368 -> 106047 bytes .../plate_compression_tech.dm | 2 +- .../code/categories/device_tools.dm | 4 +- .../code/categories/stealthy_weapons.dm | 2 +- .../skyrat-uplinks/code/categories/suits.dm | 6 +- 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 | 26 ++- 87 files changed, 715 insertions(+), 111 deletions(-) rename code/game/machinery/{scan_gate.dm => scanner_gate.dm} (84%) create mode 100644 html/changelogs/AutoChangeLog-pr-84003.yml create mode 100644 html/changelogs/AutoChangeLog-pr-84184.yml create mode 100644 html/changelogs/AutoChangeLog-pr-84775.yml create mode 100644 html/changelogs/AutoChangeLog-pr-84800.yml create mode 100644 html/changelogs/AutoChangeLog-pr-84804.yml diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 3332e46ee20..dee779f0b58 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/layers.dm b/code/__DEFINES/layers.dm index 0b3321ea450..03c8022208e 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -321,6 +321,15 @@ #define PLANE_CRITICAL_FUCKO_PARALLAX (PLANE_CRITICAL_DISPLAY|PLANE_CRITICAL_NO_RELAY|PLANE_CRITICAL_CUT_RENDER) +//---------- Plane Master offsetting_flags ------------- +// Describes how different plane masters behave regarding being offset +/// This plane master will not be offset itself, existing only once with an offset of 0 +/// Mostly used for planes that really don't need to be duplicated, like the hud planes +#define BLOCKS_PLANE_OFFSETTING (1<<0) +/// This plane master will have its relays offset to match the highest rendering plane that matches the target +/// Required for making things like the blind fullscreen not render over runechat +#define OFFSET_RELAYS_MATCH_HIGHEST (1<<1) + /// A value of /datum/preference/numeric/multiz_performance that disables the option #define MULTIZ_PERFORMANCE_DISABLE -1 /// We expect at most 3 layers of multiz diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index fe9e3d4282e..6c2fc4be7a0 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -770,6 +770,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" @@ -1164,7 +1166,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()) @@ -1183,6 +1185,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/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm index 012a1fd5cc0..cb87e21cefa 100644 --- a/code/__HELPERS/reagents.dm +++ b/code/__HELPERS/reagents.dm @@ -190,6 +190,16 @@ var/picked_reagent = pick(random_reagents) return picked_reagent +///Returns a random reagent consumable ethanol object minus blacklisted reagents +/proc/get_random_drink_id() + var/static/list/random_drinks = list() + if(!random_drinks.len) + for(var/datum/reagent/drink_path as anything in subtypesof(/datum/reagent/consumable/ethanol)) + if(initial(drink_path.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED) + random_drinks += drink_path + var/picked_drink = pick(random_drinks) + return picked_drink + ///Returns reagent datum from reagent name string /proc/get_chem_id(chem_name) for(var/X in GLOB.chemical_reagents_list) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index c1c9187f0a9..596e688a256 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -463,6 +463,9 @@ GLOBAL_LIST_INIT(binary, list("0","1")) /proc/random_color() return random_string(6, GLOB.hex_characters) +/proc/ready_random_color() + return "#" + random_string(6, GLOB.hex_characters) + //merges non-null characters (3rd argument) from "from" into "into". Returns result //e.g. into = "Hello World" // from = "Seeya______" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 2d1085d8bbd..08bd959b3b0 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -118,6 +118,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( // SKYRAT EDIT ADDITON END - Synthetic wounds /obj = list( "TRAIT_WALLMOUNTED" = TRAIT_WALLMOUNTED, + "TRAIT_CONTRABAND" = TRAIT_CONTRABAND, ), /mob = list( "TRAIT_ABDUCTOR_SCIENTIST_TRAINING" = TRAIT_ABDUCTOR_SCIENTIST_TRAINING, @@ -356,7 +357,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_EXTINGUISH" = TRAIT_NO_EXTINGUISH, "TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM, "TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE, - "TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, "TRAIT_NO_GUN_AKIMBO" = TRAIT_NO_GUN_AKIMBO, "TRAIT_NO_IMMOBILIZE" = TRAIT_NO_IMMOBILIZE, "TRAIT_NO_JUMPSUIT" = TRAIT_NO_JUMPSUIT, @@ -435,7 +435,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_ROD_SUPLEX" = TRAIT_ROD_SUPLEX, "TRAIT_ROUGHRIDER" = TRAIT_ROUGHRIDER, "TRAIT_SABRAGE_PRO" = TRAIT_SABRAGE_PRO, - "TRAIT_SACRIFICED" = TRAIT_SACRIFICED, "TRAIT_SECURITY_HUD" = TRAIT_SECURITY_HUD, "TRAIT_SEE_WORN_COLOURS" = TRAIT_SEE_WORN_COLOURS, "TRAIT_SELF_AWARE" = TRAIT_SELF_AWARE, @@ -534,9 +533,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, @@ -546,6 +547,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, @@ -559,8 +561,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/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 2a2b28d7ebe..cbfd80d97df 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -210,7 +210,7 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list( for(var/group_key as anything in master_groups) var/datum/plane_master_group/group = master_groups[group_key] - group.transform_lower_turfs(src, current_plane_offset) + group.build_planes_offset(src, current_plane_offset) /datum/hud/proc/should_use_scale() return should_sight_scale(mymob.sight) @@ -229,10 +229,9 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list( current_plane_offset = new_offset SEND_SIGNAL(src, COMSIG_HUD_OFFSET_CHANGED, old_offset, new_offset) - if(should_use_scale()) - for(var/group_key as anything in master_groups) - var/datum/plane_master_group/group = master_groups[group_key] - group.transform_lower_turfs(src, new_offset) + for(var/group_key as anything in master_groups) + var/datum/plane_master_group/group = master_groups[group_key] + group.build_planes_offset(src, new_offset) /datum/hud/Destroy() if(mymob.hud_used == src) diff --git a/code/_onclick/hud/rendering/plane_master_group.dm b/code/_onclick/hud/rendering/plane_master_group.dm index 894190984e6..23096cc0e9c 100644 --- a/code/_onclick/hud/rendering/plane_master_group.dm +++ b/code/_onclick/hud/rendering/plane_master_group.dm @@ -45,7 +45,7 @@ our_hud = viewing_hud our_hud.master_groups[key] = src show_hud() - transform_lower_turfs(our_hud, active_offset) + build_planes_offset(our_hud, active_offset) /// Hide the plane master from its current hud, fully clear it out /datum/plane_master_group/proc/orphan_hud() @@ -64,7 +64,7 @@ hide_hud() rebuild_plane_masters() show_hud() - transform_lower_turfs(our_hud, active_offset) + build_planes_offset(our_hud, active_offset) /// Regenerate our plane masters, this is useful if we don't have a mob but still want to rebuild. Such in the case of changing the screen_loc of relays /datum/plane_master_group/proc/rebuild_plane_masters() @@ -97,7 +97,7 @@ /datum/plane_master_group/proc/build_plane_masters(starting_offset, ending_offset) for(var/atom/movable/screen/plane_master/mytype as anything in get_plane_types()) for(var/plane_offset in starting_offset to ending_offset) - if(plane_offset != 0 && !initial(mytype.allows_offsetting)) + if(plane_offset != 0 && (initial(mytype.offsetting_flags) & BLOCKS_PLANE_OFFSETTING)) continue var/atom/movable/screen/plane_master/instance = new mytype(null, null, src, plane_offset) plane_masters["[instance.plane]"] = instance @@ -110,7 +110,7 @@ // It would be nice to setup parallaxing for stairs and things when doing this // So they look nicer. if you can't it's all good, if you think you can sanely look at monster's work // It's hard, and potentially expensive. be careful -/datum/plane_master_group/proc/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE) +/datum/plane_master_group/proc/build_planes_offset(datum/hud/source, new_offset, use_scale = TRUE) // Check if this feature is disabled for the client, in which case don't use scale. var/mob/our_mob = our_hud?.mymob if(!our_mob?.client?.prefs?.read_preference(/datum/preference/toggle/multiz_parallax)) @@ -158,7 +158,11 @@ for(var/plane_key in plane_masters) var/atom/movable/screen/plane_master/plane = plane_masters[plane_key] - if(!plane.allows_offsetting) + if(plane.offsetting_flags & BLOCKS_PLANE_OFFSETTING) + if(plane.offsetting_flags & OFFSET_RELAYS_MATCH_HIGHEST) + // Don't offset the plane, do offset where the relays point + // Required for making things like the blind fullscreen not render over runechat + plane.offset_relays_in_place(new_offset) continue var/visual_offset = plane.offset - new_offset @@ -199,13 +203,13 @@ #undef MAX_CLIENT_BUILD_WITH_WORKING_SECONDARY_MAPS -/datum/plane_master_group/popup/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE) +/datum/plane_master_group/popup/build_planes_offset(datum/hud/source, new_offset, use_scale = TRUE) return ..(source, new_offset, FALSE) /// Holds the main plane master /datum/plane_master_group/main -/datum/plane_master_group/main/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE) +/datum/plane_master_group/main/build_planes_offset(datum/hud/source, new_offset, use_scale = TRUE) if(use_scale) return ..(source, new_offset, source.should_use_scale()) return ..() diff --git a/code/_onclick/hud/rendering/plane_masters/_plane_master.dm b/code/_onclick/hud/rendering/plane_masters/_plane_master.dm index 13f94fa9f5a..bebf872f8eb 100644 --- a/code/_onclick/hud/rendering/plane_masters/_plane_master.dm +++ b/code/_onclick/hud/rendering/plane_masters/_plane_master.dm @@ -20,9 +20,9 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master) /// The plane master group we're a member of, our "home" var/datum/plane_master_group/home - /// If our plane master allows for offsetting - /// Mostly used for planes that really don't need to be duplicated, like the hud planes - var/allows_offsetting = TRUE + /// If our plane master has different offsetting logic + /// Possible flags are defined in [_DEFINES/layers.dm] + var/offsetting_flags = NONE /// Our offset from our "true" plane, see below var/offset /// When rendering multiz, lower levels get their own set of plane masters diff --git a/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm b/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm index fa438af4b70..c96361348f0 100644 --- a/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm +++ b/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm @@ -7,7 +7,7 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT render_relay_planes = list() // We do NOT allow offsetting, because there's no case where you would want to block only one layer, at least currently - allows_offsetting = FALSE + offsetting_flags = BLOCKS_PLANE_OFFSETTING // We mark as multiz_scaled FALSE so transforms don't effect us, and we draw to the planes below us as if they were us. // This is safe because we will ALWAYS be on the top z layer, so it DON'T MATTER multiz_scaled = FALSE @@ -368,7 +368,7 @@ appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR render_relay_planes = list(RENDER_PLANE_NON_GAME) mouse_opacity = MOUSE_OPACITY_TRANSPARENT - allows_offsetting = FALSE + offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST /atom/movable/screen/plane_master/runechat name = "Runechat" @@ -397,7 +397,7 @@ plane = HUD_PLANE appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE + offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST /atom/movable/screen/plane_master/above_hud name = "Above HUD" @@ -405,7 +405,7 @@ plane = ABOVE_HUD_PLANE appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE + offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST /atom/movable/screen/plane_master/splashscreen name = "Splashscreen" @@ -413,7 +413,7 @@ plane = SPLASHSCREEN_PLANE appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE + offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST /atom/movable/screen/plane_master/escape_menu name = "Escape Menu" @@ -421,4 +421,4 @@ plane = ESCAPE_MENU_PLANE appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR render_relay_planes = list(RENDER_PLANE_MASTER) - allows_offsetting = FALSE + offsetting_flags = BLOCKS_PLANE_OFFSETTING|OFFSET_RELAYS_MATCH_HIGHEST diff --git a/code/_onclick/hud/rendering/render_plate.dm b/code/_onclick/hud/rendering/render_plate.dm index aa7f9fe30c5..e8466352982 100644 --- a/code/_onclick/hud/rendering/render_plate.dm +++ b/code/_onclick/hud/rendering/render_plate.dm @@ -457,6 +457,8 @@ // That's what this is for if(show_to) show_to.screen += relay + if(offsetting_flags & OFFSET_RELAYS_MATCH_HIGHEST && home.our_hud) + offset_relay(relay, home.our_hud.current_plane_offset) return relay /// Breaks a connection between this plane master, and the passed in place @@ -479,3 +481,40 @@ return relay return null + +/** + * Offsets our relays in place using the given parameter by adjusting their plane and + * layer values, avoiding changing the layer for relays with custom-set layers. + * + * Used in [proc/build_planes_offset] to make the relays for non-offsetting planes + * match the highest rendering plane that matches the target, to avoid them rendering + * on the highest level above things that should be visible. + * + * Parameters: + * - new_offset: the offset we will adjust our relays to + */ +/atom/movable/screen/plane_master/proc/offset_relays_in_place(new_offset) + for(var/atom/movable/render_plane_relay/rpr in relays) + offset_relay(rpr, new_offset) + +/** + * Offsets a given render relay using the given parameter by adjusting its plane and + * layer values, avoiding changing the layer if it has a custom-set layer. + * + * Parameters: + * - rpr: the render plane relay we will offset + * - new_offset: the offset we will adjust it by + */ +/atom/movable/screen/plane_master/proc/offset_relay(atom/movable/render_plane_relay/rpr, new_offset) + var/base_relay_plane = PLANE_TO_TRUE(rpr.plane) + var/old_offset = PLANE_TO_OFFSET(rpr.plane) + rpr.plane = GET_NEW_PLANE(base_relay_plane, new_offset) + + var/old_offset_plane = real_plane - (PLANE_RANGE * old_offset) + var/old_layer = (old_offset_plane + abs(LOWEST_EVER_PLANE * 30)) + if(rpr.layer != old_layer) // Avoid overriding custom-set layers + return + + var/offset_plane = real_plane - (PLANE_RANGE * new_offset) + var/new_layer = (offset_plane + abs(LOWEST_EVER_PLANE * 30)) + rpr.layer = new_layer diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 8297085dbcf..30fdfe389ff 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -471,5 +471,6 @@ * If higher than 1, it'll lean toward common spawns even more. */ /datum/config_entry/number/random_loot_weight_modifier + integer = FALSE default = 1 min_val = 0.05 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/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 3aa9fba84e6..eac5ba56e09 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -898,7 +898,7 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away var/offset_plane = GET_NEW_PLANE(plane_to_use, plane_offset) var/string_plane = "[offset_plane]" - if(!initial(master_type.allows_offsetting)) + if(initial(master_type.offsetting_flags) & BLOCKS_PLANE_OFFSETTING) plane_offset_blacklist[string_plane] = TRUE var/render_target = initial(master_type.render_target) if(!render_target) diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm index e85c42e5226..dedb624078a 100644 --- a/code/datums/sprite_accessories.dm +++ b/code/datums/sprite_accessories.dm @@ -661,6 +661,10 @@ name = "Short Bangs" icon_state = "hair_shortbangs" +/datum/sprite_accessory/hair/shortbangs2 + name = "Short Bangs 2" + icon_state = "hair_shortbangs2" + /datum/sprite_accessory/hair/short name = "Short Hair" icon_state = "hair_a" diff --git a/code/game/machinery/scan_gate.dm b/code/game/machinery/scanner_gate.dm similarity index 84% rename from code/game/machinery/scan_gate.dm rename to code/game/machinery/scanner_gate.dm index 4ff8161de1b..ccee8fd3881 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" @@ -45,7 +46,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 @@ -62,6 +63,8 @@ ///Does the scanner ignore light_pass and light_fail for sending signals? var/ignore_signals = FALSE var/detect_gender = "male" //SKYRAT EDIT - MORE SCANNER GATE OPTIONS + ///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) @@ -72,18 +75,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 @@ -100,6 +122,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) @@ -122,6 +157,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 @@ -226,6 +275,13 @@ if(scanned_human.gender == detect_gender) beep = TRUE //SKYRAT EDIT END - MORE SCANNER GATE OPTIONS + 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 @@ -274,6 +330,7 @@ data["target_species"] = detect_species data["target_nutrition"] = detect_nutrition data["target_gender"] = detect_gender //SKYRAT EDIT - MORE SCANNER GATE OPTIONS + data["contraband_enabled"] = !!n_spect return data /obj/machinery/scanner_gate/ui_act(action, params) @@ -338,6 +395,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/anomalies/anomalies_bioscrambler.dm b/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm index c57a629d85c..2e2039dfaec 100644 --- a/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm +++ b/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm @@ -88,11 +88,15 @@ pixel_y = -16 duration = 0.5 SECONDS color = COLOR_LIME + var/max_alpha = 255 /obj/effect/temp_visual/bioscrambler_wave/Initialize(mapload) transform = matrix().Scale(0.1) animate(src, transform = matrix().Scale(2), time = duration, flags = ANIMATION_PARALLEL) - animate(src, alpha = 255, time = duration * 0.6, flags = ANIMATION_PARALLEL) + animate(src, alpha = max_alpha, time = duration * 0.6, flags = ANIMATION_PARALLEL) animate(alpha = 0, time = duration * 0.4) apply_wibbly_filters(src) return ..() + +/obj/effect/temp_visual/bioscrambler_wave/light + max_alpha = 128 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/effects/spawners/random/random.dm b/code/game/objects/effects/spawners/random/random.dm index fae8ff14cda..9614c4a1781 100644 --- a/code/game/objects/effects/spawners/random/random.dm +++ b/code/game/objects/effects/spawners/random/random.dm @@ -103,7 +103,7 @@ var/loot_weight = loot_list[loot_type] if(loot_weight <= 1) if(exponent < 1) - loot_list[loot_type] *= precision + loot_list[loot_type] = precision continue loot_list[loot_type] = round(loot_weight ** exponent * precision, 1) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 5105c5556a2..3a3f3371d1d 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1829,6 +1829,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 216d8481afa..e513967bc46 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 a8ed3b75725..ba072d79b74 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 7763025d767..9ac35368c1a 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_MAXIMUM, use_anchor = TRUE) // SKYRAT EDIT - Ghosts can't see smuggler's satchels 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 595d95c168e..0f0a47d162f 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 462f10f03c3..18e2dae715c 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook_entries/_entry.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook_entries/_entry.dm @@ -215,6 +215,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 a48e9db6bc6..6e5643e383e 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/client/preferences/multiz_parallax.dm b/code/modules/client/preferences/multiz_parallax.dm index d4f77e206b2..dab945e4bb3 100644 --- a/code/modules/client/preferences/multiz_parallax.dm +++ b/code/modules/client/preferences/multiz_parallax.dm @@ -13,4 +13,4 @@ for(var/group_key as anything in my_hud.master_groups) var/datum/plane_master_group/group = my_hud.master_groups[group_key] - group.transform_lower_turfs(my_hud, my_hud.current_plane_offset) + group.build_planes_offset(my_hud, my_hud.current_plane_offset) diff --git a/code/modules/client/preferences/multiz_performance.dm b/code/modules/client/preferences/multiz_performance.dm index 7591401f2d8..f4575357e34 100644 --- a/code/modules/client/preferences/multiz_performance.dm +++ b/code/modules/client/preferences/multiz_performance.dm @@ -18,4 +18,4 @@ for(var/group_key as anything in my_hud.master_groups) var/datum/plane_master_group/group = my_hud.master_groups[group_key] - group.transform_lower_turfs(my_hud, my_hud.current_plane_offset) + group.build_planes_offset(my_hud, my_hud.current_plane_offset) 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/clothing/suits/ghostsheet.dm b/code/modules/clothing/suits/ghostsheet.dm index 9bd8753f50b..65213fd176d 100644 --- a/code/modules/clothing/suits/ghostsheet.dm +++ b/code/modules/clothing/suits/ghostsheet.dm @@ -22,8 +22,18 @@ if(!isinhands && check_holidays(HALLOWEEN)) . += emissive_appearance('icons/mob/simple/mob.dmi', "ghost", offset_spokesman = src, alpha = src.alpha) -/obj/item/clothing/suit/costume/ghost_sheet/spooky +/obj/item/clothing/suit/spooky_ghost_sheet name = "spooky ghost" desc = "This is obviously just a bedsheet, but maybe try it on?" + icon = 'icons/obj/clothing/suits/costume.dmi' + worn_icon = 'icons/mob/clothing/suits/costume.dmi' user_vars_to_edit = list("name" = "Spooky Ghost", "real_name" = "Spooky Ghost" , "incorporeal_move" = INCORPOREAL_MOVE_BASIC, "appearance_flags" = KEEP_TOGETHER|TILE_BOUND, "alpha" = 150) + inhand_icon_state = null + throwforce = 0 + throw_speed = 1 + throw_range = 2 + w_class = WEIGHT_CLASS_TINY + flags_inv = HIDEGLOVES|HIDEEARS|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT + species_exception = list(/datum/species/golem) + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON alternate_worn_layer = ABOVE_BODY_FRONT_LAYER //so the bedsheet goes over everything but fire 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/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 706d22783b5..6f28cd9d068 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -294,8 +294,8 @@ else Knockdown(stun_duration) -/mob/living/carbon/proc/help_shake_act(mob/living/carbon/helper) - var/nosound = FALSE //SKYRAT EDIT ADDITION - EMOTES +/mob/living/carbon/proc/help_shake_act(mob/living/carbon/helper, force_friendly) + var/nosound = FALSE //SKYRATEDIT ADDITION - EMOTES if(on_fire) to_chat(helper, span_warning("You can't put [p_them()] out with just your bare hands!")) return @@ -419,7 +419,7 @@ else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) to_chat(helper, span_warning("It feels like [src] is freezing as you hug [p_them()].")) - if(HAS_TRAIT(helper, TRAIT_FRIENDLY)) + if(HAS_TRAIT(helper, TRAIT_FRIENDLY) || force_friendly) if (helper.mob_mood.sanity >= SANITY_GREAT) new /obj/effect/temp_visual/heart(loc) add_mood_event("friendly_hug", /datum/mood_event/besthug, helper) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index acec80f5652..41c129dc4ab 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -553,7 +553,7 @@ . = rand(-1000, 1000) ..() //Called afterwards because getting the mind after getting gibbed is sketchy -/mob/living/carbon/human/help_shake_act(mob/living/carbon/helper) +/mob/living/carbon/human/help_shake_act(mob/living/carbon/helper, force_friendly) if(!istype(helper)) return diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index d58e71ca8ff..e9b018bfcde 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -354,6 +354,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/experimentor.dm b/code/modules/research/experimentor.dm index e7c02c199aa..ec562dd4d26 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -616,6 +616,12 @@ PROC_REF(uncontrolled_teleport), PROC_REF(heat_and_explode), PROC_REF(rapid_self_dupe), + PROC_REF(drink_dispenser), + PROC_REF(tummy_ache), + PROC_REF(charger), + PROC_REF(hugger), + PROC_REF(dimensional_shift), + PROC_REF(disguiser), ) /obj/item/relic/attack_self(mob/user) @@ -721,6 +727,164 @@ throw_smoke(get_turf(user)) warn_admins(user, "Teleport", 0) +// Creates a glass and fills it up with a drink. +/obj/item/relic/proc/drink_dispenser(mob/user) + var/obj/item/reagent_containers/cup/glass/drinkingglass/freebie = new(get_step_rand(user)) + playsound(freebie, 'sound/effects/phasein.ogg', rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + addtimer(CALLBACK(src, PROC_REF(dispense_drink), freebie), 0.5 SECONDS) + +/obj/item/relic/proc/dispense_drink(obj/item/reagent_containers/cup/glass/glasser) + glasser.reagents.add_reagent(get_random_drink_id(), rand(glasser.volume * 0.3, glasser.volume)) + playsound(glasser, SFX_SPARKS, rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + throw_smoke(get_turf(glasser)) + +// Scrambles your organs. 33% chance to delete after use. +/obj/item/relic/proc/tummy_ache(mob/user) + new /obj/effect/temp_visual/bioscrambler_wave/light(get_turf(src)) + to_chat(user, span_notice("Your stomach starts growling...")) + addtimer(CALLBACK(src, PROC_REF(scrambliticus), user), rand(1 SECONDS, 3 SECONDS)) // throw it away! + +/obj/item/relic/proc/scrambliticus(mob/user) + new /obj/effect/temp_visual/bioscrambler_wave(get_turf(src)) + playsound(src, 'sound/magic/cosmic_energy.ogg', vol = 50, vary = TRUE) + for(var/mob/living/carbon/nearby in hearers(2, src)) + nearby.bioscramble(name) + playsound(nearby, SFX_SPARKS, rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + throw_smoke(get_turf(nearby)) + to_chat(nearby, span_notice("You feel weird.")) + if(prob(33)) + qdel(src) + +// Charges an item or two in your inventory. Also yourself. +/obj/item/relic/proc/charger(mob/living/user) + to_chat(user, span_danger("You're recharged!")) + var/stunner = 1.25 SECONDS + if(iscarbon(user)) + var/mob/living/carbon/carboner = user + carboner.electrocute_act(15, src, flags = SHOCK_NOGLOVES, stun_duration = stunner) + else + user.electrocute_act(15, src, flags = SHOCK_NOGLOVES) + playsound(user, SFX_SPARKS, rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + + var/list/chargeable_batteries = list() + for(var/obj/item/stock_parts/power_store/C in user.get_all_contents()) + if(C.charge < (C.maxcharge * 0.95)) // otherwise the PDA always gets recharged + chargeable_batteries |= C + + lightning_fx(user, stunner) + var/recharges = rand(1, 2) + if(!length(chargeable_batteries)) + to_chat(user, span_notice("You have a strange feeling for a moment, but then it passes.")) + return + for(var/obj/item/stock_parts/power_store/to_charge as anything in recharges) + to_charge = pick(chargeable_batteries) + to_charge.charge = to_charge.maxcharge + // The device powered by the cell is assumed to be its location. + var/obj/device = to_charge.loc + // If it's not an object, or the loc's assigned power_store isn't the cell, undo. + if(!istype(device) || (device.get_cell() != to_charge)) + device = to_charge + device.update_appearance(UPDATE_ICON|UPDATE_OVERLAYS) + to_chat(user, span_notice("[device] feels energized!")) + lightning_fx(device, 0.8 SECONDS) + +/obj/item/relic/proc/lightning_fx(atom/shocker, time) + var/lightning = mutable_appearance('icons/effects/effects.dmi', "electricity3", layer = ABOVE_MOB_LAYER) + shocker.add_overlay(lightning) + addtimer(CALLBACK(src, PROC_REF(cut_the_overlay), shocker, lightning), time) + +/obj/item/relic/proc/cut_the_overlay(atom/shocker, lightning) + shocker.cut_overlay(lightning) + +// Hugs/shakes everyone in range! +/obj/item/relic/proc/hugger(mob/user) + var/list/mob/living/carbon/huggeds = oviewers(3, user) + for(var/mob/living/carbon/victim in huggeds) + victim.help_shake_act(user, force_friendly = TRUE) + new /obj/effect/temp_visual/heart(victim.loc) + if(length(huggeds)) + to_chat(user, span_nicegreen("You feel friendly!")) + else + to_chat(user, pick(span_notice("You hug yourself, for some reason."), span_notice("You have a strange feeling for a moment, but then it passes."))) + +// Converts a 3x3 area into a random dimensional theme. +/obj/item/relic/proc/dimensional_shift(mob/user) + var/new_theme_path = pick(subtypesof(/datum/dimension_theme)) + var/datum/dimension_theme/shifter = SSmaterials.dimensional_themes[new_theme_path] + for(var/turf/shiftee in range(1, user)) + shifter.apply_theme(shiftee, show_effect = TRUE) + qdel(shifter) + // prevent *total* spam conversion + min_cooldown += 2 SECONDS + max_cooldown += 2 SECONDS + +// Replaces your clothing with a random costume, and your ID with a cardboard one. +// TODO: make them part of the same kit (lobster hat, lobster suit) +/obj/item/relic/proc/disguiser(mob/user) + if(!iscarbon(user)) + to_chat(user, span_notice("You have a strange feeling for a moment, but then it passes.")) + return + + if(prob(80)) // >:) + ADD_TRAIT(user, TRAIT_NO_JUMPSUIT, REF(src)) // prevent dropping pockets & belt + + // magic trick! + playsound(user, SFX_SPARKS, rand(25,50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + throw_smoke(user) + + // carbons always get a hat at least + var/mob/living/carbon/carbonius = user + //hat + var/obj/item/clothing/head/costume/disguise_hat = roll_costume(/obj/item/clothing/head/costume, HIDEMASK) + carbonius.dropItemToGround(carbonius.head) + carbonius.equip_to_slot_or_del(disguise_hat, ITEM_SLOT_HEAD) + if(!ishuman(carbonius)) + to_chat(user, span_notice("You have a peculiar feeling for a moment, but then it passes.")) + return + + var/mob/living/carbon/human/humerus = carbonius + // uniform + var/obj/item/clothing/under/costume/disguise_uniform = roll_costume(/obj/item/clothing/under/costume) + humerus.dropItemToGround(humerus.w_uniform) + humerus.equip_to_slot_or_del(disguise_uniform, ITEM_SLOT_ICLOTHING) + // suit + var/obj/item/clothing/suit/costume/disguise_suit = roll_costume(/obj/item/clothing/suit/costume) + humerus.dropItemToGround(humerus.wear_suit) + humerus.equip_to_slot_or_del(disguise_suit, ITEM_SLOT_OCLOTHING) + // id + var/obj/item/card/cardboard/card_id = new() + humerus.dropItemToGround(humerus.wear_id) + humerus.equip_to_slot_or_del(card_id, ITEM_SLOT_ID) + + // edit the card to a random job & name + if(!card_id) + return + card_id.scribbled_name = "[pick(GLOB.first_names)] [pick(GLOB.last_names)]" + card_id.update_name() + card_id.details_colors = list(ready_random_color(), ready_random_color(), ready_random_color()) + card_id.item_flags |= DROPDEL + + var/datum/id_trim/random_trim = pick(subtypesof(/datum/id_trim)) // this can pick silly things + random_trim = new random_trim() + if(random_trim.trim_state && random_trim.assignment) + card_id.scribbled_trim = replacetext(random_trim.trim_state, "trim_", "cardboard_") + card_id.scribbled_assignment = random_trim.assignment + card_id.update_overlays() + REMOVE_TRAIT(user, TRAIT_NO_JUMPSUIT, REF(src)) + +/obj/item/relic/proc/roll_costume(type, flagcheck) + var/list/candidates = list() + for(var/obj/item/thingy as anything in subtypesof(type)) + if(flagcheck && !(initial(thingy.flags_inv) & flagcheck)) + continue + if(isnull(initial(thingy.icon_state))) + continue + candidates |= thingy + var/obj/item/new_costume = pick(candidates) + new_costume = new new_costume() + new_costume.item_flags |= DROPDEL + return new_costume + //Admin Warning proc for relics /obj/item/relic/proc/warn_admins(mob/user, relic_type, priority = 1) var/turf/location = get_turf(src) diff --git a/code/modules/research/techweb/nodes/mech_nodes.dm b/code/modules/research/techweb/nodes/mech_nodes.dm index 6b7a9803ae4..d6b7171d55b 100644 --- a/code/modules/research/techweb/nodes/mech_nodes.dm +++ b/code/modules/research/techweb/nodes/mech_nodes.dm @@ -1,8 +1,8 @@ /datum/techweb_node/mech_assembly id = TECHWEB_NODE_MECH_ASSEMBLY starting_node = TRUE - display_name = "Mech Assembly" - description = "Development of mech designed to contend with artificial gravity while transporting cargo." + display_name = "Exosuit Assembly" + description = "Development of mechanical exosuits designed to contend with artificial gravity while transporting cargo." prereq_ids = list(TECHWEB_NODE_ROBOTICS) design_ids = list( "mechapower", @@ -21,7 +21,7 @@ /datum/techweb_node/mech_equipment id = TECHWEB_NODE_MECH_EQUIPMENT display_name = "Expedition Equipment" - description = "Specialized mech gear tailored for navigating space and celestial bodies, ensuring durability and functionality in the harshest conditions." + description = "Specialized exosuit gear tailored for navigating space and celestial bodies, ensuring durability and functionality in the harshest conditions." prereq_ids = list(TECHWEB_NODE_MECH_ASSEMBLY) design_ids = list( "mechacontrol", @@ -63,7 +63,7 @@ /datum/techweb_node/mech_medical id = TECHWEB_NODE_MECH_MEDICAL - display_name = "Medical Mech" + display_name = "Medical Exosuit" description = "Advanced robotic unit equipped with syringe guns and healing beams, revolutionizing medical assistance in hazardous environments." prereq_ids = list(TECHWEB_NODE_MECH_ASSEMBLY, TECHWEB_NODE_CHEM_SYNTHESIS) design_ids = list( @@ -83,8 +83,8 @@ /datum/techweb_node/mech_mining id = TECHWEB_NODE_MECH_MINING - display_name = "Mining Mech" - description = "Robust mech engineered to withstand lava and storms for continuous off-station mining operations." + display_name = "Mining Exosuit" + description = "Robust exosuit engineered to withstand lava and storms for continuous off-station mining operations." prereq_ids = list(TECHWEB_NODE_MECH_EQUIPMENT, TECHWEB_NODE_MINING) design_ids = list( "clarke_chassis", @@ -99,8 +99,8 @@ /datum/techweb_node/mech_combat id = TECHWEB_NODE_MECH_COMBAT - display_name = "Combat Mechs" - description = "Modular armor upgrades and specialized equipment for security mechs." + display_name = "Combat Exosuits" + description = "Modular armor upgrades and specialized equipment for security exosuits." prereq_ids = list(TECHWEB_NODE_MECH_EQUIPMENT) design_ids = list( "mech_ccw_armor", @@ -115,8 +115,8 @@ /datum/techweb_node/mech_assault id = TECHWEB_NODE_MECH_ASSAULT - display_name = "Assault Mech" - description = "Heavy battle mech boasting robust armor but sacrificing speed for enhanced durability." + display_name = "Assault Exosuits" + description = "Heavy battle exosuits boasting robust armor but sacrificing speed for enhanced durability." prereq_ids = list(TECHWEB_NODE_MECH_COMBAT) design_ids = list( "durand_armor", @@ -135,8 +135,8 @@ /datum/techweb_node/mech_light id = TECHWEB_NODE_MECH_LIGHT - display_name = "Light Combat Mech" - description = "Agile combat mech equipped with overclocking capabilities for temporary speed boosts, prioritizing speed over durability on the battlefield." + display_name = "Light Combat Exosuits" + description = "Agile combat exosuits equipped with overclocking capabilities for temporary speed boosts, prioritizing speed over durability on the battlefield." prereq_ids = list(TECHWEB_NODE_MECH_COMBAT) design_ids = list( "gygax_armor", @@ -155,7 +155,7 @@ /datum/techweb_node/mech_heavy id = TECHWEB_NODE_MECH_HEAVY - display_name = "Heavy Mech" + display_name = "Heavy Exosuits" description = "Advanced heavy mechanized unit with dual pilot capability, designed for robust battlefield performance and increased tactical versatility." prereq_ids = list(TECHWEB_NODE_MECH_ASSAULT) design_ids = list( @@ -175,8 +175,8 @@ /datum/techweb_node/mech_infiltrator id = TECHWEB_NODE_MECH_INFILTRATOR - display_name = "Infiltration Mech" - description = "Advanced mech with phasing capabilities, allowing it to move through walls and obstacles, ideal for covert and special operations." + display_name = "Infiltration Exosuits" + description = "Advanced exosuit with phasing capabilities, allowing it to move through walls and obstacles, ideal for covert and special operations." prereq_ids = list(TECHWEB_NODE_MECH_LIGHT, TECHWEB_NODE_ANOMALY_RESEARCH) design_ids = list( "phazon_armor", @@ -211,8 +211,8 @@ /datum/techweb_node/mech_energy_guns id = TECHWEB_NODE_MECH_ENERGY_GUNS - display_name = "Mech Energy Guns" - description = "Scaled-up versions of electric weapons optimized for mech deployment." + display_name = "Exosuit Energy Guns" + description = "Scaled-up versions of electric weapons optimized for exosuit deployment." prereq_ids = list(TECHWEB_NODE_MECH_COMBAT, TECHWEB_NODE_ELECTRIC_WEAPONS) design_ids = list( "mech_laser", @@ -225,7 +225,7 @@ /datum/techweb_node/mech_firearms id = TECHWEB_NODE_MECH_FIREARMS - display_name = "Mech Firearms" + display_name = "Exosuit Firearms" description = "Mounted ballistic weaponry, enhancing combat capabilities for mechanized units." prereq_ids = list(TECHWEB_NODE_MECH_ENERGY_GUNS, TECHWEB_NODE_EXOTIC_AMMO) design_ids = list( @@ -240,7 +240,7 @@ /datum/techweb_node/mech_heavy_arms id = TECHWEB_NODE_MECH_HEAVY_ARMS - display_name = "Heavy Mech Firearms" + display_name = "Heavy Exosuit Firearms" description = "High-impact weaponry integrated into mechs, optimized for maximum firepower." prereq_ids = list(TECHWEB_NODE_MECH_HEAVY, TECHWEB_NODE_EXOTIC_AMMO) design_ids = list( @@ -255,7 +255,7 @@ /datum/techweb_node/mech_equip_bluespace id = TECHWEB_NODE_BLUESPACE - display_name = "Bluespace Mech Equipment" + display_name = "Bluespace Exosuit Equipment" description = "An array of equipment empowered by bluespace, providing unmatched mobility and utility." prereq_ids = list(TECHWEB_NODE_MECH_INFILTRATOR, TECHWEB_NODE_BLUESPACE_TRAVEL) design_ids = list( diff --git a/code/modules/research/techweb/nodes/modsuit_nodes.dm b/code/modules/research/techweb/nodes/modsuit_nodes.dm index d4e30e9cd5d..56addbad127 100644 --- a/code/modules/research/techweb/nodes/modsuit_nodes.dm +++ b/code/modules/research/techweb/nodes/modsuit_nodes.dm @@ -1,7 +1,7 @@ /datum/techweb_node/mod_suit id = TECHWEB_NODE_MOD_SUIT starting_node = TRUE - display_name = "Modular Exosuit" + display_name = "Modular Suit" description = "Specialized back mounted power suits with various different modules." prereq_ids = list(TECHWEB_NODE_ROBOTICS) design_ids = list( @@ -52,7 +52,7 @@ /datum/techweb_node/mod_medical id = TECHWEB_NODE_MOD_MEDICAL display_name = "Medical Modular Suit" - description = "Medical exosuits for quick rescue purposes." + description = "Medical MODsuits for quick rescue purposes." prereq_ids = list(TECHWEB_NODE_MOD_SUIT, TECHWEB_NODE_CHEM_SYNTHESIS) design_ids = list( "mod_plating_medical", @@ -98,7 +98,7 @@ /datum/techweb_node/mod_medical_adv id = TECHWEB_NODE_MOD_MEDICAL_ADV display_name = "Field Surgery Modules" - description = "Medical exosuit equipment designed for conducting surgical operations in field conditions." + description = "Medical MODsuit equipment designed for conducting surgical operations in field conditions." prereq_ids = list(TECHWEB_NODE_MOD_MEDICAL, TECHWEB_NODE_SURGERY_ADV) design_ids = list( "mod_defib", @@ -130,7 +130,7 @@ /datum/techweb_node/mod_anomaly id = TECHWEB_NODE_MOD_ANOMALY display_name = "Anomalock Modular Suit" - description = "Modules for exosuits that require anomaly cores to function." + description = "Modules for MODsuits that require anomaly cores to function." prereq_ids = list(TECHWEB_NODE_MOD_ENGI_ADV, TECHWEB_NODE_ANOMALY_RESEARCH) design_ids = list( "mod_antigrav", 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 8d607cb0d5c..a5b4b0ec1df 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" @@ -159,4 +159,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 05252f8a1af..567d359e82e 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" @@ -113,7 +113,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" @@ -165,7 +165,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 626e5ca385b..aac6be5cdd1 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 94a5e3b3de4..de53589de2d 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 30b9ed53715..21f4831af36 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/html/changelogs/AutoChangeLog-pr-84003.yml b/html/changelogs/AutoChangeLog-pr-84003.yml new file mode 100644 index 00000000000..e180b38a1be --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84003.yml @@ -0,0 +1,10 @@ +author: "ArcaneMusic" +delete-after: True +changes: + - rscadd: "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." + - rscadd: "Scanner gates can now be upgraded by using an N-spect scanner on it to unlock \"contraband scanning\" mode." + - rscadd: "Security officers can now be offered a bounty to turn in pieces of contraband." + - rscadd: "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." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-84184.yml b/html/changelogs/AutoChangeLog-pr-84184.yml new file mode 100644 index 00000000000..3798eba1216 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84184.yml @@ -0,0 +1,4 @@ +author: "00-Steven" +delete-after: True +changes: + - bugfix: "You can see runechat above fullscreen overlays on lower multi-z levels again. Rejoice, blind players. Please report any weird rendering layering issues." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-84775.yml b/html/changelogs/AutoChangeLog-pr-84775.yml new file mode 100644 index 00000000000..b9d24b0c408 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84775.yml @@ -0,0 +1,5 @@ +author: "carlarctg" +delete-after: True +changes: + - rscadd: "Adds six new strange object powers! Drink dispenser, bioscrambler, recharger, hugger, dimensional, disguiser." + - code_imp: "Removed some unused code and items, and added a proc that returns a random #colorstring." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-84800.yml b/html/changelogs/AutoChangeLog-pr-84800.yml new file mode 100644 index 00000000000..7b3d21cd581 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84800.yml @@ -0,0 +1,4 @@ +author: "GPeckman" +delete-after: True +changes: + - spellcheck: "The techweb no longer erroneously refers to MODsuits as exosuits." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-84804.yml b/html/changelogs/AutoChangeLog-pr-84804.yml new file mode 100644 index 00000000000..189f718e576 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84804.yml @@ -0,0 +1,4 @@ +author: "Hardly3D" +delete-after: True +changes: + - rscadd: "Added new hairstyle: Short Bangs 2" \ No newline at end of file diff --git a/icons/mob/human/human_face.dmi b/icons/mob/human/human_face.dmi index d96800c3a8bb8beabc76245afaa329db6cbfe340..886094ec4957387f262ce253aeabf6b068fdf3b0 100644 GIT binary patch delta 42110 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 X*H8W?sS27H0>H8FywKH$@hSfTJ&|U= delta 41401 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 YHL|A-t<+!Um#YbTy8G;_-W#6wCm561EC2ui diff --git a/modular_skyrat/modules/company_imports/code/objects/nakamura_modsuits/plate_compression_tech.dm b/modular_skyrat/modules/company_imports/code/objects/nakamura_modsuits/plate_compression_tech.dm index ff9ab5becd5..7a6b808374e 100644 --- a/modular_skyrat/modules/company_imports/code/objects/nakamura_modsuits/plate_compression_tech.dm +++ b/modular_skyrat/modules/company_imports/code/objects/nakamura_modsuits/plate_compression_tech.dm @@ -1,2 +1,2 @@ /datum/uplink_item/suits/plate_compression - illegal_tech = FALSE + uplink_item_flags = NONE diff --git a/modular_skyrat/modules/skyrat-uplinks/code/categories/device_tools.dm b/modular_skyrat/modules/skyrat-uplinks/code/categories/device_tools.dm index c33882e6c72..977492ea7de 100644 --- a/modular_skyrat/modules/skyrat-uplinks/code/categories/device_tools.dm +++ b/modular_skyrat/modules/skyrat-uplinks/code/categories/device_tools.dm @@ -21,14 +21,14 @@ desc = "A pair of highly robust combat gripper gloves that excels at performing takedowns at close range, with an added lining of insulation. Careful not to hit a wall!" item = /obj/item/clothing/gloves/tackler/combat/insulated cost = 2 - illegal_tech = FALSE + uplink_item_flags = NONE /datum/uplink_item/device_tools/ammo_pouch name = "Ammo Pouch" desc = "A small yet large enough pouch that can fit in your pocket, and has room for three magazines." item = /obj/item/storage/pouch/ammo cost = 1 - illegal_tech = FALSE + uplink_item_flags = NONE /datum/uplink_item/device_tools/syndie_glue name = "Glue" diff --git a/modular_skyrat/modules/skyrat-uplinks/code/categories/stealthy_weapons.dm b/modular_skyrat/modules/skyrat-uplinks/code/categories/stealthy_weapons.dm index 2c42f87d34d..1ba86193d05 100644 --- a/modular_skyrat/modules/skyrat-uplinks/code/categories/stealthy_weapons.dm +++ b/modular_skyrat/modules/skyrat-uplinks/code/categories/stealthy_weapons.dm @@ -5,4 +5,4 @@ cost = 2 surplus = 0 progression_minimum = 10 MINUTES - illegal_tech = FALSE + uplink_item_flags = NONE diff --git a/modular_skyrat/modules/skyrat-uplinks/code/categories/suits.dm b/modular_skyrat/modules/skyrat-uplinks/code/categories/suits.dm index e03cf398757..f6cc2c94f6d 100644 --- a/modular_skyrat/modules/skyrat-uplinks/code/categories/suits.dm +++ b/modular_skyrat/modules/skyrat-uplinks/code/categories/suits.dm @@ -3,7 +3,7 @@ desc = "A slim Type I armored vest that provides decent protection against most types of damage." item = /obj/item/clothing/suit/armor/vest cost = 1 - illegal_tech = FALSE + uplink_item_flags = NONE progression_minimum = 10 MINUTES /datum/uplink_item/suits/bulletproof_armor @@ -11,7 +11,7 @@ desc = "A Type III heavy bulletproof vest that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent." item = /obj/item/clothing/suit/armor/bulletproof cost = 3 - illegal_tech = FALSE + uplink_item_flags = NONE progression_minimum = 15 MINUTES /datum/uplink_item/suits/swathelmet_traitor @@ -19,5 +19,5 @@ desc = "An extremely robust, space-worthy helmet in a nefarious red and black stripe pattern." item = /obj/item/clothing/head/helmet/swat cost = 2 - illegal_tech = FALSE + uplink_item_flags = NONE progression_minimum = 10 MINUTES diff --git a/tgstation.dme b/tgstation.dme index 26411a13c64..ae7e01aeebf 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2138,7 +2138,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 && ( + + + + )}