From 9568c40d7a4e52651e54907d654b4e90a098f5da Mon Sep 17 00:00:00 2001
From: carlarctg <53100513+carlarctg@users.noreply.github.com>
Date: Mon, 15 May 2023 01:10:42 -0300
Subject: [PATCH] Adds the Syndicate Induction Kit for Nuclear Operatives
(#75055)
## About The Pull Request
Adds the Syndicate Induction Kit for Nuclear Operatives.
The kit contains the following
- One Ansem pistol
- One each of 10mm AP/HP magazines
- An energy dagger
- A syndicate bowman headset
- A nuclear PDA and agent card
- A syndicate fabric space suit and helmet, alongside a jet harness
- Combat boots, turtleneck, fingerless gloves
- The Fission Mailed book
- And the most important part, the induction implant.
The induction implant will make anyone who is implanted by it a
Syndicate Operative. This will give them the syndie faction and the nuke
op datum, alongside the usual weird name nukeops get.
The implant will NOT work on anyone who is not an antagonist in some way
or form. Normal crew members do not gain benefits from implanting, and
in fact the implant disintegrating inside gives them toxin.
It costs a total of 10 TC, for what is more or less 25 TC of gear. The
value is totally up to change, it's probably way too low.
Uplink spacesuits are randomized between all their different colored
variants! Visual only.
## Why It's Good For The Game
It's cool and rewards teamwork. Traitors can team up with nukies, and if
they choose to do so they gain some basic gear (a free gun, a space
suit, the dagger) that isn't really even close to the degree of gear
real ops get. As a downside, their name becomes an extremely obvious
nuclear operative name, meaning if they want to be stealthy they either
have to never talk or purchase a voice changer.
Being able to just obtain a whole new member of the team for so little
likely seems bonkers, but my intention is to just encourage something
that's neat and interesting ingame without hopefully being *too*
impactful and strong.
Imagine stumbling upon a heretic and inducting them into the team. Or a
changeling, or a wizard? Running around hypnoflashing people to be nuke
ops and then giving them the kit?? There's a lot of fun moments that
could arise from this, but they're balanced by the fact that, well,
nobody ever saves TC for the station.
Something I can see becoming a problem is EVERY traitor buying syndicate
encryption keys to beg for an induction kit every time war is declared.
I'm not sure if this is going to be a huge issue, but I think I'd rather
just get this ingame and see if that does turn out to be a problem. If
it does, we can just make it so that traitors can't be inducted, as the
syndicate has already hired them for something else and doesn't want to
flare inter-faction tensions.
## Changelog
:cl:
add: Adds the Syndicate Induction Kit for Nuclear Operatives, which lets
them induct any willing antagonist into the nuclear operative team for
10 TC.
add: Uplink spacesuits are randomized between all their different
colored variants! Visual only.
/:cl:
---
code/__DEFINES/antagonists.dm | 4 +
.../game/objects/items/storage/uplink_kits.dm | 120 ++++++++++++++++--
.../antagonists/_common/antag_datum.dm | 2 +
code/modules/antagonists/ert/ert.dm | 2 +
.../antagonists/valentines/valentine.dm | 2 +
code/modules/clothing/spacesuits/syndi.dm | 29 +++++
code/modules/uplink/uplink_items/nukeops.dm | 10 ++
7 files changed, 158 insertions(+), 11 deletions(-)
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index 4e3fe1927bc..9cfdc92b649 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -326,6 +326,10 @@ GLOBAL_LIST_INIT(human_invader_antagonists, list(
#define ANTAG_GROUP_WIZARDS "Wizard Federation"
#define ANTAG_GROUP_XENOS "Xenomorph Infestation"
+
+// If this flag is enabled the antagonist datum allows the antagonist to be inducted into a nuclear operative team.
+#define FLAG_ANTAG_CAN_BE_INDUCTED (1 << 0)
+
#define HUNTER_PACK_COPS "cop_hunters"
#define HUNTER_PACK_RUSSIAN "russian_hunters"
#define HUNTER_PACK_BOUNTY "bounty_hunters"
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index 4cb2edb024f..c9ace922962 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -87,8 +87,10 @@
new /obj/item/sbeacondrop/bomb(src) // 11 tc
new /obj/item/grenade/syndieminibomb(src) // 6 tc
new /obj/item/sbeacondrop/powersink(src) // 11 tc
- new /obj/item/clothing/suit/space/syndicate/black/red(src) // outfit 1 tc
- new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
+ var/obj/item/clothing/suit/space/syndicate/spess_suit = pick(GLOB.syndicate_space_suits_to_helmets)
+ new spess_suit(src) // Above allows me to get the helmet from a variable on the object
+ var/obj/item/clothing/head/helmet/space/syndicate/spess_helmet = GLOB.syndicate_space_suits_to_helmets[spess_suit]
+ new spess_helmet(src) // 4 TC for the space gear
new /obj/item/encryptionkey/syndicate(src) // 2 tc
if(KIT_MURDER)
@@ -120,8 +122,10 @@
if(KIT_LORD_SINGULOTH) //currently disabled, i might return with another anti-engine kit
new /obj/item/sbeacondrop(src) // 10 tc
- new /obj/item/clothing/suit/space/syndicate/black/red(src)
- new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
+ var/obj/item/clothing/suit/space/syndicate/spess_suit = pick(GLOB.syndicate_space_suits_to_helmets)
+ new spess_suit(src) // Above allows me to get the helmet from a variable on the object
+ var/obj/item/clothing/head/helmet/space/syndicate/spess_helmet = GLOB.syndicate_space_suits_to_helmets[spess_suit]
+ new spess_helmet(src) // 4 TC for the space gear
new /obj/item/card/emag(src) // 4 tc
new /obj/item/storage/toolbox/syndicate(src) // 1 tc
new /obj/item/card/id/advanced/mining(src)
@@ -409,13 +413,10 @@
atom_storage.set_holdable(list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate))
/obj/item/storage/box/syndie_kit/space/PopulateContents()
- if(prob(50))
- new /obj/item/clothing/suit/space/syndicate/black/red(src) // Black and red is so in right now
- new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
-
- else
- new /obj/item/clothing/head/helmet/space/syndicate(src)
- new /obj/item/clothing/suit/space/syndicate(src)
+ var/obj/item/clothing/suit/space/syndicate/spess_suit = pick(GLOB.syndicate_space_suits_to_helmets)
+ new spess_suit(src) // Above allows me to get the helmet from a variable on the object
+ var/obj/item/clothing/head/helmet/space/syndicate/spess_helmet = GLOB.syndicate_space_suits_to_helmets[spess_suit]
+ new spess_helmet(src) // 4 TC for the space gear
/obj/item/storage/box/syndie_kit/emp
name = "EMP kit"
@@ -642,6 +643,103 @@
new /obj/item/storage/belt/grenade(src)
new /obj/item/storage/belt/military/snack(src)
+/obj/item/storage/box/syndie_kit/induction_kit
+ name = "syndicate induction kit"
+ desc = "Contains all you need for introducing your newest comrade to the Syndicate and all its worker's benefits."
+
+/obj/item/storage/box/syndie_kit/induction_kit/PopulateContents()
+ // Basic weaponry, so they have something to use.
+ new /obj/item/gun/ballistic/automatic/pistol/clandestine(src) // 6 TC, but free for nukies
+ new /obj/item/ammo_box/magazine/m10mm/hp(src) // 3 TC, a reward for the teamwork involved
+ new /obj/item/ammo_box/magazine/m10mm/ap(src) // 3 TC, a reward for the teamwork involved
+ new /obj/item/pen/edagger(src) // 2 TC
+ // The necessary equipment to help secure that disky.
+ new /obj/item/radio/headset/syndicate/alt(src) // 5 TC / Free for nukies
+ new /obj/item/modular_computer/pda/nukeops(src) // ?? TC / Free for nukies
+ new /obj/item/card/id/advanced/chameleon(src) // 2 TC / Free for nukies
+ var/obj/item/clothing/suit/space/syndicate/spess_suit = pick(GLOB.syndicate_space_suits_to_helmets)
+ new spess_suit(src) // Above allows me to get the helmet from a variable on the object
+ var/obj/item/clothing/head/helmet/space/syndicate/spess_helmet = GLOB.syndicate_space_suits_to_helmets[spess_suit]
+ new spess_helmet(src) // 4 TC for the space gear
+ new /obj/item/tank/jetpack/oxygen/harness(src) // They kinda need this to fly to the cruiser.
+ // Tacticool gear
+ new /obj/item/clothing/shoes/combat(src)
+ new /obj/item/clothing/under/syndicate(src)
+ new /obj/item/clothing/gloves/fingerless(src)
+ new /obj/item/book/manual/nuclear(src) // Very important
+ // The most important part of the kit, the implant that gives them the syndicate faction.
+ new /obj/item/implanter/induction_implant(src)
+ // All in all, 6+3+3+2+5+2+4 = ~25 TC of 'miscellaneous' items.
+ // This is a lot of value for 10 TC, but you have to keep in mind that you NEED someone to get this stuff station-side.
+ // Pretty much all of it is a bad deal for reinforcements or yourself as they already have similar or good-enough alternatives.
+
+/obj/item/implanter/induction_implant
+ name = "implanter (nuclear operative)"
+ desc = "A sterile automatic implant injector. You can see a tiny, somehow legible sticker on the side: 'NOT A BRAINWASH DEVICE'"
+ imp_type = /obj/item/implant/nuclear_operative
+
+/obj/item/implant/nuclear_operative
+ name = "nuclear operative implant"
+ desc = "Registers you as a member of a Syndicate nuclear operative team."
+ implant_color = "r"
+
+/obj/item/implant/nuclear_operative/get_data()
+ var/dat = {"Implant Specifications:
+ Name: Suspicious Implant
+ Life: UNKNOWN
+ Implant Details:
+ Function: Strange implant that seems to resist any attempts at scanning it."}
+ return dat
+
+/obj/item/implant/nuclear_operative/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
+ . = ..()
+ if(!. || !ishuman(target) || !(target.mind))
+ return FALSE
+ var/mob/living/carbon/human/human_target = target
+
+ if(IS_NUKE_OP(human_target)) // this wont proc due to ..() but i guess its good as a just-in-case?
+ if(human_target == user)
+ to_chat(user, span_userdanger("You're already a nuclear operative, dumbass! The implant disintegrates within you! You feel sick..."))
+ human_target.Stun(10 SECONDS)
+ human_target.reagents.add_reagent(/datum/reagent/toxin, 10)
+ return FALSE
+ else
+ to_chat(user, span_notice("You finish implanting [human_target], but you don't really notice a difference. Huh."))
+ to_chat(human_target, span_userdanger("Nothing seems to really happen, but you start to feel a little ill.."))
+ human_target.reagents.add_reagent(/datum/reagent/toxin, 2)
+ return FALSE
+
+ /// If no antag datums which allow induction are there, disallow induction! No self-antagging.
+ var/allowed = FALSE
+ for(var/datum/antagonist/antag_datum as anything in human_target.mind.antag_datums)
+ if((antag_datum.antag_flags & FLAG_ANTAG_CAN_BE_INDUCTED))
+ allowed = TRUE
+
+ if(!allowed) // GTFO. Technically not foolproof but making a heartbreaker or a paradox clone a nuke op sounds hilarious
+ to_chat(human_target, span_notice("Huh? Nothing happened? But you're starting to feel a little ill..."))
+ human_target.reagents.add_reagent(/datum/reagent/toxin, 15)
+ return FALSE
+
+ var/datum/antagonist/nukeop/nuke_datum = new()
+ nuke_datum.send_to_spawnpoint = FALSE
+ nuke_datum.nukeop_outfit = null
+ human_target.mind?.add_antag_datum(nuke_datum)
+ human_target.faction |= ROLE_SYNDICATE
+ to_chat(human_target, span_warning("You are now a nuclear operative. Your main objective, if you were an antagonist and willing, is presumably to assist the nuclear operative team and secure the disk."))
+ to_chat(human_target, span_userdanger("This implant does NOT, in any way, brainwash you. If you were a normal crew member beforehand, forcibly implanted or otherwise, you are still one and cannot assist the nuclear operatives."))
+ return TRUE
+
+/obj/item/implant/nuclear_operative/removed(mob/target, silent = FALSE, special = FALSE)
+ . = ..()
+ if(!. || !isliving(target))
+ return FALSE
+ var/mob/living/living_target = target
+ living_target.mind.remove_antag_datum(/datum/antagonist/nukeop)
+ living_target.faction -= ROLE_SYNDICATE
+ to_chat(target, span_notice("You feel a little less nuclear."))
+ to_chat(target, span_userdanger("You're no longer identified as a nuclear operative! You are free to follow any valid goals you wish, even continuing to secure the disk. Just make sure neither any turrets nor operatives kill you on sight."))
+ return TRUE
+
#undef KIT_RECON
#undef KIT_BLOODY_SPAI
#undef KIT_STEALTHY
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index 74a634b83cb..709741abd96 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -50,6 +50,8 @@ GLOBAL_LIST_EMPTY(antagonists)
var/show_to_ghosts = FALSE
/// The typepath for the outfit to show in the preview for the preferences menu.
var/preview_outfit
+ /// Flags for antags to turn on or off and check!
+ var/antag_flags = FLAG_ANTAG_CAN_BE_INDUCTED
//ANTAG UI
diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm
index ab69df5a61d..c6dd121a8d5 100644
--- a/code/modules/antagonists/ert/ert.dm
+++ b/code/modules/antagonists/ert/ert.dm
@@ -12,6 +12,8 @@
antagpanel_category = ANTAG_GROUP_ERT
suicide_cry = "FOR NANOTRASEN!!"
count_against_dynamic_roll_chance = FALSE
+ // Not 'true' antags, cannot induct to prevent issues
+ antag_flags = NONE
var/datum/team/ert/ert_team
var/leader = FALSE
var/datum/outfit/outfit = /datum/outfit/centcom/ert/security
diff --git a/code/modules/antagonists/valentines/valentine.dm b/code/modules/antagonists/valentines/valentine.dm
index e76292e3d96..8883625fb1a 100644
--- a/code/modules/antagonists/valentines/valentine.dm
+++ b/code/modules/antagonists/valentines/valentine.dm
@@ -4,6 +4,8 @@
show_in_antagpanel = FALSE
prevent_roundtype_conversion = FALSE
suicide_cry = "FOR MY LOVE!!"
+ // Not 'true' antags, cannot induct
+ antag_flags = NONE
var/datum/mind/date
count_against_dynamic_roll_chance = FALSE
diff --git a/code/modules/clothing/spacesuits/syndi.dm b/code/modules/clothing/spacesuits/syndi.dm
index 000cb298551..d9939a46621 100644
--- a/code/modules/clothing/spacesuits/syndi.dm
+++ b/code/modules/clothing/spacesuits/syndi.dm
@@ -16,6 +16,22 @@
fire = 80
acid = 85
+// Don't blame me, blame whoever added this many variations
+GLOBAL_LIST_INIT(syndicate_space_suits_to_helmets,list(
+ /obj/item/clothing/suit/space/syndicate = /obj/item/clothing/head/helmet/space/syndicate,
+ /obj/item/clothing/suit/space/syndicate/green = /obj/item/clothing/head/helmet/space/syndicate/green,
+ /obj/item/clothing/suit/space/syndicate/green/dark = /obj/item/clothing/head/helmet/space/syndicate/green/dark,
+ /obj/item/clothing/suit/space/syndicate/orange = /obj/item/clothing/head/helmet/space/syndicate/orange,
+ /obj/item/clothing/suit/space/syndicate/blue = /obj/item/clothing/head/helmet/space/syndicate/blue,
+ /obj/item/clothing/suit/space/syndicate/black = /obj/item/clothing/head/helmet/space/syndicate/black,
+ /obj/item/clothing/suit/space/syndicate/black/green = /obj/item/clothing/head/helmet/space/syndicate/black/green,
+ /obj/item/clothing/suit/space/syndicate/black/blue = /obj/item/clothing/head/helmet/space/syndicate/black/blue,
+ /obj/item/clothing/suit/space/syndicate/black/orange = /obj/item/clothing/head/helmet/space/syndicate/black/orange,
+ /obj/item/clothing/suit/space/syndicate/black/red = /obj/item/clothing/head/helmet/space/syndicate/black/red,
+ /obj/item/clothing/suit/space/syndicate/black/med = /obj/item/clothing/head/helmet/space/syndicate/black/med,
+ /obj/item/clothing/suit/space/syndicate/black/engie = /obj/item/clothing/head/helmet/space/syndicate/black/engie,
+))
+
/obj/item/clothing/suit/space/syndicate
name = "red space suit"
icon_state = "syndicate"
@@ -25,6 +41,7 @@
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
armor_type = /datum/armor/space_syndicate
cell = /obj/item/stock_parts/cell/hyper
+ var/helmet_type = /obj/item/clothing/head/helmet/space/syndicate
//Green syndicate space suit
/obj/item/clothing/head/helmet/space/syndicate/green
@@ -36,6 +53,7 @@
name = "green space suit"
icon_state = "syndicate-green"
inhand_icon_state = "syndicate-green"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/green
//Dark green syndicate space suit
@@ -48,6 +66,7 @@
name = "dark green space suit"
icon_state = "syndicate-green-dark"
inhand_icon_state = "syndicate-green-dark"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/green/dark
//Orange syndicate space suit
@@ -60,6 +79,7 @@
name = "orange space suit"
icon_state = "syndicate-orange"
inhand_icon_state = "syndicate-orange"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/orange
//Blue syndicate space suit
/obj/item/clothing/head/helmet/space/syndicate/blue
@@ -71,6 +91,7 @@
name = "blue space suit"
icon_state = "syndicate-blue"
inhand_icon_state = "syndicate-blue"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/blue
//Black syndicate space suit
@@ -83,6 +104,7 @@
name = "black space suit"
icon_state = "syndicate-black"
inhand_icon_state = "syndicate-black"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black
//Black-green syndicate space suit
@@ -95,6 +117,7 @@
name = "black and green space suit"
icon_state = "syndicate-black-green"
inhand_icon_state = "syndicate-black-green"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black/green
//Black-blue syndicate space suit
@@ -107,6 +130,7 @@
name = "black and blue space suit"
icon_state = "syndicate-black-blue"
inhand_icon_state = "syndicate-black-blue"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black/blue
//Black medical syndicate space suit
@@ -119,6 +143,7 @@
name = "green space suit"
icon_state = "syndicate-black-med"
inhand_icon_state = "syndicate-black"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black/med
//Black-orange syndicate space suit
@@ -131,6 +156,7 @@
name = "black and orange space suit"
icon_state = "syndicate-black-orange"
inhand_icon_state = "syndicate-black"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black/orange
//Black-red syndicate space suit
@@ -143,6 +169,7 @@
name = "black and red space suit"
icon_state = "syndicate-black-red"
inhand_icon_state = "syndicate-black-red"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black/red
//Black-red syndicate contract varient
/obj/item/clothing/head/helmet/space/syndicate/contract
@@ -159,6 +186,7 @@
w_class = WEIGHT_CLASS_SMALL
icon_state = "syndicate-contract"
inhand_icon_state = null
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/contract
//Black with yellow/red engineering syndicate space suit
/obj/item/clothing/head/helmet/space/syndicate/black/engie
@@ -170,3 +198,4 @@
name = "black engineering space suit"
icon_state = "syndicate-black-engie"
inhand_icon_state = "syndicate-black"
+ helmet_type = /obj/item/clothing/head/helmet/space/syndicate/black/engie
diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm
index 70ca0377e8c..9d2a32d92ae 100644
--- a/code/modules/uplink/uplink_items/nukeops.dm
+++ b/code/modules/uplink/uplink_items/nukeops.dm
@@ -46,6 +46,16 @@
cost = 30
purchasable_from = UPLINK_NUKE_OPS
+/datum/uplink_item/bundles_tc/induction_kit
+ name = "Syndicate Induction Kit"
+ desc = "Met a fellow syndicate agent on the station? Kept some TC in reserve just in case? Or are you communicating with one via the Syndicate channel? \
+ Get this kit and you'll be able to induct them into your operative team via a special implant. \
+ Additionally, it contains an assortment of useful gear for new operatives, including a space suit, an Ansem pistol, two spare magazines, and more! \
+ *NOT* for usage with Reinforcements, and does not brainwash the target!"
+ item = /obj/item/storage/box/syndie_kit/induction_kit
+ cost = 10
+ purchasable_from = UPLINK_NUKE_OPS
+
/datum/uplink_item/dangerous/rawketlawnchair
name = "84mm Rocket Propelled Grenade Launcher"
desc = "A reusable rocket propelled grenade launcher preloaded with a low-yield 84mm HE round. \