Skip to content

Commit

Permalink
[MIRROR] New operative reinforcement option: Intelligence Overwatch A…
Browse files Browse the repository at this point in the history
…gent (#2753)

* New operative reinforcement option: Intelligence Overwatch Agent (#82307)

## About The Pull Request

Introducing a new Nuclear Operative reinforcement option: The Overwatch
Intelligence Agent.

Equipped with multi-hudglasses, they have an advanced camera console,
station alerts, and bodycams of every operative! If something can be
known, they will know about it.

They can also remotely pilot your ship. Finally, everyone can ride in
the Steel Rain without getting stuck on the station!

This role spawns in the formerly unused outpost just north of the nukie
base. With a few shelves of supplies and some tools in the back room,
they can set up their workplace however they like. This also gives them
something to work on while they wait for the operatives to gear up.


![image](https://github.com/tgstation/tgstation/assets/28870487/4a39ec5f-0578-4825-8c6b-cc4db47bf726)

As you can see, it's rather cramped and the lights are quite dim in the
backroom. Set it up however you like, this is how I did mine:


![image](https://github.com/tgstation/tgstation/assets/28870487/f80b65fa-dcd1-425e-a6ce-c0ed94a8a3a5)

Total price? 12 TC per agent. It might get a bit cramped, but you could
buy a second to make sure the first guy doesn't get lonely!

This turned into a 30-commit ugly because the bodycams were originally
meant to be accomplished via a refactoring of the spyglass kit. Big
mistake that made me shelve the project -- until Melbert's simple
bodycam component conveniently did exactly what I needed in a much
simpler way.
## Why It's Good For The Game

Having a "guy in the chair" for your kickass murder operator squad
enables more brainy strategizing, and is thematically sound. Also,
nukies have the opportunity to bring in another player to participate in
the fun!
## Changelog
:cl: Rhials
add: Nuclear Operatives now purchase an Intelligence Agent, who can
watch cameras and bodycams, move the shuttle, and provide radio support.
Only 12 Telecrystals!
/:cl:

* New operative reinforcement option: Intelligence Overwatch Agent

---------

Co-authored-by: NovaBot <[email protected]>
Co-authored-by: Rhials <[email protected]>
  • Loading branch information
3 people authored Apr 5, 2024
1 parent eaa9cb8 commit 7bf5d43
Show file tree
Hide file tree
Showing 17 changed files with 379 additions and 40 deletions.
229 changes: 197 additions & 32 deletions _maps/templates/lazy_templates/nukie_base.dmm

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions code/__DEFINES/cameranets.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@
#define CAMERANET_NETWORK_BAR "bar"
#define CAMERANET_NETWORK_INTERROGATION "interrogation"
#define CAMERANET_NETWORK_ABDUCTOR "abductor"
#define OPERATIVE_CAMERA_NET "operative"
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/signals_operatives.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// For when a new teammate is added to a nukie team
#define COMSIG_NUKE_TEAM_ADDITION "nuke_team_addition"
1 change: 1 addition & 0 deletions code/__DEFINES/role_preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
#define ROLE_WIZARD_APPRENTICE "apprentice"
#define ROLE_SYNDICATE_MONKEY "Syndicate Monkey Agent"
#define ROLE_CONTRACTOR_SUPPORT "Contractor Support Unit"
#define ROLE_OPERATIVE_OVERWATCH "Operative Overwatch Agent"
#define ROLE_SYNDICATE_SABOBORG "Syndicate Sabotage Cyborg"
#define ROLE_SYNDICATE_MEDBORG "Syndicate Medical Cyborg"
#define ROLE_SYNDICATE_ASSAULTBORG "Syndicate Assault Cyborg"
Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/lists/mapping.dm
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ GLOBAL_LIST_EMPTY(gorilla_start)
GLOBAL_LIST_EMPTY(wizardstart)
GLOBAL_LIST_EMPTY(nukeop_start)
GLOBAL_LIST_EMPTY(nukeop_leader_start)
GLOBAL_LIST_EMPTY(nukeop_overwatch_start)
GLOBAL_LIST_EMPTY(newplayer_start)
GLOBAL_LIST_EMPTY(prisonwarp) //admin prisoners go to these
GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here (ninja energy net)
Expand Down
10 changes: 10 additions & 0 deletions code/game/objects/effects/landmarks.dm
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,16 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
GLOB.nukeop_leader_start += loc
return INITIALIZE_HINT_QDEL

/obj/effect/landmark/start/nukeop_overwatch
name = "nukeop overwatch"
icon = 'icons/effects/landmarks_static.dmi'
icon_state = "snukeop_leader_spawn"

/obj/effect/landmark/start/nukeop_overwatch/Initialize(mapload)
..()
GLOB.nukeop_overwatch_start += loc
return INITIALIZE_HINT_QDEL

// Must be immediate because players will
// join before SSatom initializes everything.
INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
Expand Down
33 changes: 26 additions & 7 deletions code/modules/antagonists/_common/antag_spawner.dm
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,13 @@
/// The applied outfit
var/datum/outfit/syndicate/outfit = /datum/outfit/syndicate/reinforcement
/// The antag datum applied
var/datum/antagonist/nukeop/reinforcement/antag_datum = /datum/antagonist/nukeop/reinforcement
var/antag_datum = /datum/antagonist/nukeop/reinforcement
/// Style used by the droppod
var/pod_style = STYLE_SYNDICATE
/// Do we use a random subtype of the outfit?
var/use_subtypes = TRUE
/// Where do we land our pod?
var/turf/spawn_location

/obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user)
if(used)
Expand Down Expand Up @@ -143,7 +145,6 @@

/obj/item/antag_spawner/nuke_ops/spawn_antag(client/our_client, turf/T, kind, datum/mind/user)
var/mob/living/carbon/human/nukie = new()
var/obj/structure/closet/supplypod/pod = setup_pod()
our_client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE)
nukie.ckey = our_client.key
var/datum/mind/op_mind = nukie.mind
Expand All @@ -152,15 +153,33 @@
else
nukie.forceMove(locate(1,1,1))

antag_datum = new()

antag_datum.nukeop_outfit = use_subtypes ? pick(subtypesof(outfit)) : outfit
var/new_datum = new antag_datum()

var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop, TRUE)
op_mind.add_antag_datum(antag_datum, creator_op ? creator_op.get_team() : null)
op_mind.add_antag_datum(new_datum, creator_op ? creator_op.get_team() : null)
op_mind.special_role = special_role_name

if(outfit)
var/datum/antagonist/nukeop/nukie_datum = op_mind.has_antag_datum(antag_datum)
nukie_datum.nukeop_outfit = use_subtypes ? pick(subtypesof(outfit)) : outfit

var/obj/structure/closet/supplypod/pod = setup_pod()
nukie.forceMove(pod)
new /obj/effect/pod_landingzone(get_turf(src), pod)
new /obj/effect/pod_landingzone(spawn_location ? spawn_location : get_turf(src), pod)

/obj/item/antag_spawner/nuke_ops/overwatch
name = "overwatch support beacon"
desc = "Assigns an Overwatch Intelligence Agent to your operation. Stationed at their own remote outpost, they can view station cameras, alarms, and even move the Infiltrator shuttle! \
Also, all members of your operation will recieve body cameras that they can view your progress from."
special_role_name = ROLE_OPERATIVE_OVERWATCH
outfit = /datum/outfit/syndicate/support
use_subtypes = FALSE
antag_datum = /datum/antagonist/nukeop/support

/obj/item/antag_spawner/nuke_ops/overwatch/Initialize(mapload)
. = ..()
if(length(GLOB.nukeop_overwatch_start)) //Otherwise, it will default to the datum's spawn point anyways
spawn_location = pick(GLOB.nukeop_overwatch_start)

//////CLOWN OP
/obj/item/antag_spawner/nuke_ops/clown
Expand Down
1 change: 0 additions & 1 deletion code/modules/antagonists/nukeop/datums/operative.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
var/datum/component/uplink/uplink = owner.find_syndicate_uplink()
if (uplink)
uplink.uplink_handler.add_telecrystals(extra_tc)

var/datum/component/uplink/uplink = owner.find_syndicate_uplink()
if(uplink)
var/datum/team/nuclear/nuke_team = get_team()
Expand Down
54 changes: 54 additions & 0 deletions code/modules/antagonists/nukeop/datums/operative_support.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/datum/antagonist/nukeop/support
name = ROLE_OPERATIVE_OVERWATCH
show_to_ghosts = TRUE
send_to_spawnpoint = TRUE
nukeop_outfit = /datum/outfit/syndicate/support

/datum/antagonist/nukeop/support/greet()
owner.current.playsound_local(get_turf(owner.current), 'sound/machines/printer.ogg', 100, 0, use_reverb = FALSE)
to_chat(owner, span_big("You are a [name]! You've been temporarily assigned to provide camera overwatch and manage communications for a nuclear operative team!"))
to_chat(owner, span_red("Use your tools to set up your equipment however you like, but do NOT attempt to leave your outpost."))
owner.announce_objectives()

/datum/antagonist/nukeop/support/on_gain()
..()
for(var/datum/mind/teammate_mind in nuke_team.members)
var/mob/living/our_teammate = teammate_mind.current
our_teammate.AddComponent( \
/datum/component/simple_bodycam, \
camera_name = "operative bodycam", \
c_tag = "[our_teammate.real_name]", \
network = OPERATIVE_CAMERA_NET, \
emp_proof = FALSE, \
)
our_teammate.playsound_local(get_turf(owner.current), 'sound/weapons/egloves.ogg', 100, 0)
to_chat(our_teammate, span_notice("A Syndicate Overwatch Intelligence Agent has been assigned to your team. Smile, you're on camera!"))

RegisterSignal(nuke_team, COMSIG_NUKE_TEAM_ADDITION, PROC_REF(late_bodycam))

owner.current.grant_language(/datum/language/codespeak)

/datum/antagonist/nukeop/support/get_spawnpoint()
return pick(GLOB.nukeop_overwatch_start)

/datum/antagonist/nukeop/support/forge_objectives()
var/datum/objective/overwatch/objective = new
objective.owner = owner
objectives += objective

/datum/antagonist/nukeop/support/proc/late_bodycam(datum/source, mob/living/new_teammate)
SIGNAL_HANDLER
new_teammate.AddComponent( \
/datum/component/simple_bodycam, \
camera_name = "operative bodycam", \
c_tag = "[new_teammate.real_name]", \
network = OPERATIVE_CAMERA_NET, \
emp_proof = FALSE, \
)
to_chat(new_teammate, span_notice("You have been equipped with a bodycam, viewable by your Overwatch Intelligence Agent. Make sure to show them a good performance!"))

/datum/objective/overwatch
explanation_text = "Provide intelligence support and overwatch to your operative team!"

/datum/objective/overwatch/check_completion()
return GLOB.station_was_nuked
4 changes: 4 additions & 0 deletions code/modules/antagonists/nukeop/datums/operative_team.dm
Original file line number Diff line number Diff line change
Expand Up @@ -313,5 +313,9 @@
return TRUE
return FALSE

/datum/team/nuclear/add_member(datum/mind/new_member)
..()
SEND_SIGNAL(src, COMSIG_NUKE_TEAM_ADDITION, new_member.current)

#undef SPAWN_AT_BASE
#undef SPAWN_AT_INFILTRATOR
46 changes: 46 additions & 0 deletions code/modules/antagonists/nukeop/equipment/overwatch_tools.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
///One of the special items that spawns in the overwatch agent's room.
/obj/item/paper/fluff/overwatch
name = "OVERWATCH NOTES #1"
color = COLOR_RED
desc = "A note from Syndicate leadership regarding your new job. You should read this!"
default_raw_text = @{"
Congratulations! You have been picked to be the Sole Survivor of an anti-Nanotrasen suicide mission!
We're kidding of course, these types of missions tend to have abnormally high survival rates. I guess that says a lot about who your team will be going up against.
<br>
You've been assigned to provide intelligence support to the ground-pounders carrying out the operation.
Each operative has been equipped with a bodycam that can be accessed via your Overwatch Camera Console.
Additionally, you have been given the boards to access station alerts, cameras, and remotely control the infiltrator shuttle.
<br>
Feel free to set up your workplace however you like. We've provided the tools and boards in your backroom.
<br>
Happy hunting!
"}

/obj/machinery/computer/security/overwatch
name = "overwatch camera console"
desc = "Allows you to view members of your operative team via their bodycam feeds. We call them 'bodycams', but they're actually a swarm of tiny, near-imperceptible camera drones that follow each target. \
It is believed that adversaries either don't notice the drones, or avoid attacking them in hopes that they'll capture footage of their combat prowess against our operatives."
icon_screen = "commsyndie"
icon_keyboard = "syndie_key"
network = list(OPERATIVE_CAMERA_NET)
circuit = /obj/item/circuitboard/computer/overwatch

/obj/item/circuitboard/computer/overwatch
name = "Overwatch Body Cameras"
build_path = /obj/machinery/computer/security/overwatch
greyscale_colors = CIRCUIT_COLOR_SECURITY

/obj/item/circuitboard/computer/syndicate_shuttle_docker
name = "Shuttle Controller"
build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/syndicate
greyscale_colors = CIRCUIT_COLOR_SECURITY

/obj/item/clothing/glasses/overwatch
name = "intelligence glasses"
desc = "A set of incredibly advanced sunglasses, providing you with an array of different sensor scans and visual readouts for pretty much anything you look at. \
It's kind of overwhelming, actually. Wearing this for a few hours will probably give you a migrane."
icon_state = "sunhudmed"
flags_cover = GLASSESCOVERSEYES
flash_protect = FLASH_PROTECTION_WELDER
clothing_traits = list(TRAIT_REAGENT_SCANNER)
var/list/hudlist = list(DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED, DATA_HUD_SECURITY_ADVANCED)
21 changes: 21 additions & 0 deletions code/modules/antagonists/nukeop/outfits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,17 @@
r_hand = /obj/item/tank/internals/plasmaman/belt/full
tc = 0

/datum/outfit/syndicate/support/plasmaman
name = "Nuclear Operative Overwatch Agent (Plasmaman)"
back = /obj/item/storage/backpack/satchel
head = /obj/item/clothing/head/helmet/space/plasmaman/syndie
uniform = /obj/item/clothing/under/plasmaman/syndicate
glasses = /obj/item/clothing/glasses/overwatch
suit = /obj/item/clothing/suit/jacket/letterman_syndie
r_hand = /obj/item/tank/internals/plasmaman/belt/full
command_radio = TRUE
tc = 0

/datum/outfit/syndicate/reinforcement/gorlex
name = "Syndicate Operative - Gorlex Reinforcement"
suit = /obj/item/clothing/suit/armor/vest/alt
Expand Down Expand Up @@ -191,3 +202,13 @@
var/obj/item/shield/energy/shield = locate() in H.held_items
shield.icon_state = "[shield.base_icon_state]1"
H.update_held_items()

/datum/outfit/syndicate/support
name = "Nuclear Operative Overwatch Agent"
back = /obj/item/storage/backpack/satchel
uniform = /obj/item/clothing/under/syndicate/tacticool
glasses = /obj/item/clothing/glasses/overwatch
suit = /obj/item/clothing/suit/jacket/letterman_syndie
shoes = /obj/item/clothing/shoes/sandal
command_radio = TRUE
tc = 0
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
/datum/outfit/syndicate/reinforcement/interdyne = /datum/outfit/syndicate/reinforcement/plasmaman,
/datum/outfit/syndicate/reinforcement/mi13 = /datum/outfit/syndicate/reinforcement/plasmaman,
/datum/outfit/syndicate/reinforcement/waffle = /datum/outfit/syndicate/reinforcement/plasmaman,
/datum/outfit/syndicate/support = /datum/outfit/syndicate/support/plasmaman,
)

/// If the bones themselves are burning clothes won't help you much
Expand Down
3 changes: 3 additions & 0 deletions code/modules/power/cable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
/obj/item/stack/cable_coil/five
amount = 5

/obj/item/stack/cable_coil/thirty
amount = 30

/obj/item/stack/cable_coil/cut
amount = null
icon_state = "coil2"
Expand Down
1 change: 1 addition & 0 deletions code/modules/shuttle/syndicate.dm
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,6 @@
y_offset = -1
whitelist_turfs = list(/turf/open/space, /turf/open/floor/plating, /turf/open/lava, /turf/closed/mineral, /turf/open/openspace, /turf/open/misc)
see_hidden = TRUE
circuit = /obj/item/circuitboard/computer/syndicate_shuttle_docker

#undef SYNDICATE_CHALLENGE_TIMER
8 changes: 8 additions & 0 deletions code/modules/uplink/uplink_items/nukeops.dm
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,14 @@
Its chameleon projector lets it disguise itself as a Nanotrasen cyborg, on top it has thermal vision and a pinpointer."
item = /obj/item/antag_spawner/nuke_ops/borg_tele/saboteur

/datum/uplink_item/reinforcements/overwatch_agent
name = "Overwatch Intelligence Agent"
desc = "An Overwatch Intelligence Agent is assigned to your operation. They can view your progress and help coordinate using your \
operative team's body-cams. They can also pilot the shuttle remotely and view the station's camera net. \
If you're a meathead who's just here to kill people and don't care about strategising or intel, you'll still have someone to bear witness to your murder-spree!"
item = /obj/item/antag_spawner/nuke_ops/overwatch
cost = 12

// ~~ Disposable Sentry Gun ~~
// Technically not a spawn but it is a kind of reinforcement...I guess.

Expand Down
3 changes: 3 additions & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@
#include "code\__DEFINES\dcs\signals\signals_music.dm"
#include "code\__DEFINES\dcs\signals\signals_object.dm"
#include "code\__DEFINES\dcs\signals\signals_operating_computer.dm"
#include "code\__DEFINES\dcs\signals\signals_operatives.dm"
#include "code\__DEFINES\dcs\signals\signals_painting.dm"
#include "code\__DEFINES\dcs\signals\signals_proxmonitor.dm"
#include "code\__DEFINES\dcs\signals\signals_radiation.dm"
Expand Down Expand Up @@ -3251,10 +3252,12 @@
#include "code\modules\antagonists\nukeop\datums\operative_leader.dm"
#include "code\modules\antagonists\nukeop\datums\operative_lone.dm"
#include "code\modules\antagonists\nukeop\datums\operative_reinforcement.dm"
#include "code\modules\antagonists\nukeop\datums\operative_support.dm"
#include "code\modules\antagonists\nukeop\datums\operative_team.dm"
#include "code\modules\antagonists\nukeop\equipment\borgchameleon.dm"
#include "code\modules\antagonists\nukeop\equipment\nuclear_authentication_disk.dm"
#include "code\modules\antagonists\nukeop\equipment\nuclear_challenge.dm"
#include "code\modules\antagonists\nukeop\equipment\overwatch_tools.dm"
#include "code\modules\antagonists\nukeop\equipment\pinpointer.dm"
#include "code\modules\antagonists\nukeop\equipment\nuclear_bomb\_nuclear_bomb.dm"
#include "code\modules\antagonists\nukeop\equipment\nuclear_bomb\beer_nuke.dm"
Expand Down

0 comments on commit 7bf5d43

Please sign in to comment.