diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 3b8649e26a5..b03a5d10fdf 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -4,6 +4,10 @@
#define NUKE_SEALANT_OPEN 3
#define NUKE_UNWRENCHED 4
#define NUKE_MOBILE 5
+#define NUKE_CORE_EVERYTHING_FINE 6
+#define NUKE_CORE_PANEL_EXPOSED 7
+#define NUKE_CORE_PANEL_UNWELDED 8
+#define NUKE_CORE_FULLY_EXPOSED 9
GLOBAL_VAR(bomb_set)
@@ -25,12 +29,17 @@ GLOBAL_VAR(bomb_set)
var/yes_code = FALSE
var/safety = TRUE
var/obj/item/disk/nuclear/auth = null
- var/removal_stage = NUKE_INTACT
+ var/obj/item/nuke_core/plutonium/core = null
var/lastentered
var/is_syndicate = FALSE
use_power = NO_POWER_USE
var/previous_level = ""
var/datum/wires/nuclearbomb/wires = null
+ var/removal_stage = NUKE_INTACT
+ ///The same state removal stage is, until someone opens the panel of the nuke. This way we can have someone open the front of the nuke, while keeping track of where in the world we are on the anchoring bolts.
+ var/anchor_stage = NUKE_INTACT
+ ///This is so that we can check if the internal components are sealed up properly when the outer hatch is closed.
+ var/core_stage = NUKE_CORE_EVERYTHING_FINE
/obj/machinery/nuclearbomb/syndicate
is_syndicate = TRUE
@@ -39,16 +48,19 @@ GLOBAL_VAR(bomb_set)
extended = FALSE
anchored = FALSE
-/obj/machinery/nuclearbomb/New()
- ..()
- r_code = rand(10000, 99999.0) // Creates a random code upon object spawn.
+/obj/machinery/nuclearbomb/Initialize()
+ . = ..()
+ r_code = rand(10000, 99999) // Creates a random code upon object spawn.
wires = new/datum/wires/nuclearbomb(src)
previous_level = get_security_level()
GLOB.poi_list |= src
+ core = new /obj/item/nuke_core/plutonium(src)
+ STOP_PROCESSING(SSobj, core) //Let us not irradiate the vault by default.
/obj/machinery/nuclearbomb/Destroy()
SStgui.close_uis(wires)
QDEL_NULL(wires)
+ QDEL_NULL(core)
GLOB.poi_list.Remove(src)
return ..()
@@ -73,16 +85,41 @@ GLOBAL_VAR(bomb_set)
else
to_chat(user, "You need to deploy [src] first.")
return
+ if(istype(O, /obj/item/stack/sheet/mineral/titanium) && removal_stage == NUKE_CORE_FULLY_EXPOSED)
+ if(do_after(user, 2 SECONDS, target = src))
+ var/obj/item/stack/S = O
+ if(!loc || !S || S.get_amount() < 5)
+ return
+ S.use(5)
+ user.visible_message("[user] repairs [src]'s inner core plate.", "You repair [src]'s inner core plate. The radiation is contained.")
+ removal_stage = NUKE_CORE_PANEL_UNWELDED
+ if(core)
+ STOP_PROCESSING(SSobj, core)
+ return
+ if(istype(O, /obj/item/stack/sheet/metal) && removal_stage == NUKE_CORE_PANEL_EXPOSED)
+ var/obj/item/stack/S = O
+ if(do_after(user, 2 SECONDS, target = src))
+ if(!loc || !S || S.get_amount() < 5)
+ return
+ S.use(5)
+ user.visible_message("[user] repairs [src]'s outer core plate.", "You repair [src]'s outer core plate.")
+ removal_stage = NUKE_CORE_EVERYTHING_FINE
+ return
+ if(istype(O, /obj/item/nuke_core/plutonium) && removal_stage == NUKE_CORE_FULLY_EXPOSED)
+ if(do_after(user, 2 SECONDS, target = src))
+ if(!user.unEquip(O))
+ to_chat(user, "The [O] is stuck to your hand!")
+ return
+ user.visible_message("[user] puts [O] back in [src].", "You put [O] back in [src].")
+ O.forceMove(src)
+ core = O
+
else if(istype(O, /obj/item/disk/plantgene))
to_chat(user, "You try to plant the disk, but despite rooting around, it won't fit! After you branch out to read the instructions, you find out where the problem stems from. You've been bamboo-zled, this isn't a nuclear disk at all!")
return
return ..()
/obj/machinery/nuclearbomb/crowbar_act(mob/user, obj/item/I)
- if(!anchored)
- return
- if(removal_stage != NUKE_UNWRENCHED && removal_stage != NUKE_COVER_OFF)
- return
. = TRUE
if(!I.tool_use_check(user, 0))
return
@@ -92,9 +129,26 @@ GLOBAL_VAR(bomb_set)
return
user.visible_message("[user] forces open the bolt covers on [src].", "You force open the bolt covers.")
removal_stage = NUKE_COVER_OPEN
- else
+ if(removal_stage == NUKE_CORE_EVERYTHING_FINE)
+ user.visible_message("[user] starts removing [src]'s outer core plate...", "You start removing [src]'s outer core plate...")
+ if(!I.use_tool(src, user, 4 SECONDS, volume = I.tool_volume) || removal_stage != NUKE_CORE_EVERYTHING_FINE)
+ return
+ user.visible_message("[user] finishes removing [src]'s outer core plate.", "You finish removing [src]'s outer core plate.")
+ new /obj/item/stack/sheet/metal(loc, 5)
+ removal_stage = NUKE_CORE_PANEL_EXPOSED
+
+ if(removal_stage == NUKE_CORE_PANEL_UNWELDED)
+ user.visible_message("[user] starts removing [src]'s inner core plate...", "You start removing [src]'s inner core plate...")
+ if(!I.use_tool(src, user, 8 SECONDS, volume = I.tool_volume) || removal_stage != NUKE_CORE_PANEL_UNWELDED)
+ return
+ user.visible_message("[user] finishes removing [src]'s inner core plate.", "You remove [src]'s inner core plate. You can see the core's green glow!")
+ removal_stage = NUKE_CORE_FULLY_EXPOSED
+ new /obj/item/stack/sheet/mineral/titanium(loc, 5)
+ if(core)
+ START_PROCESSING(SSobj, core)
+ if(removal_stage == NUKE_UNWRENCHED)
user.visible_message("[user] begins lifting [src] off of the anchors.", "You begin lifting the device off the anchors...")
- if(!I.use_tool(src, user, 80, volume = I.tool_volume) || removal_stage != NUKE_UNWRENCHED)
+ if(!I.use_tool(src, user, 8 SECONDS, volume = I.tool_volume) || removal_stage != NUKE_UNWRENCHED)
return
user.visible_message("[user] crowbars [src] off of the anchors. It can now be moved.", "You jam the crowbar under the nuclear device and lift it off its anchors. You can now move it!")
anchored = FALSE
@@ -126,15 +180,19 @@ GLOBAL_VAR(bomb_set)
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
- if(auth)
+ if(auth || (istype(I, /obj/item/screwdriver/nuke)))
if(!panel_open)
panel_open = TRUE
overlays += image(icon, "npanel_open")
to_chat(user, "You unscrew the control panel of [src].")
+ anchor_stage = removal_stage
+ removal_stage = core_stage
else
panel_open = FALSE
overlays -= image(icon, "npanel_open")
to_chat(user, "You screw the control panel of [src] back on.")
+ core_stage = removal_stage
+ removal_stage = anchor_stage
else
if(!panel_open)
to_chat(user, "[src] emits a buzzing noise, the panel staying locked in.")
@@ -142,6 +200,8 @@ GLOBAL_VAR(bomb_set)
panel_open = FALSE
overlays -= image(icon, "npanel_open")
to_chat(user, "You screw the control panel of [src] back on.")
+ core_stage = removal_stage
+ removal_stage = anchor_stage
flick("nuclearbombc", src)
/obj/machinery/nuclearbomb/wirecutter_act(mob/user, obj/item/I)
@@ -154,8 +214,6 @@ GLOBAL_VAR(bomb_set)
/obj/machinery/nuclearbomb/welder_act(mob/user, obj/item/I)
. = TRUE
- if(removal_stage != NUKE_INTACT && removal_stage != NUKE_COVER_OPEN)
- return
if(!I.tool_use_check(user, 0))
return
if(removal_stage == NUKE_INTACT)
@@ -167,7 +225,20 @@ GLOBAL_VAR(bomb_set)
visible_message("[user] cuts through the bolt covers on [src].",\
"You cut through the bolt cover.")
removal_stage = NUKE_COVER_OFF
- else if(removal_stage == NUKE_COVER_OPEN)
+ if(removal_stage == NUKE_CORE_PANEL_UNWELDED)
+ user.visible_message("[user] starts welding [src]'s inner core plate...", "You start welding [src]'s inner core plate...")
+ if(!I.use_tool(src, user, 4 SECONDS, 5, volume = I.tool_volume) || removal_stage != NUKE_CORE_PANEL_UNWELDED)
+ return
+ user.visible_message("[user] finishes welding [src]'s inner core plate...", "You finish welding [src]'s inner core plate...")
+ removal_stage = NUKE_CORE_PANEL_EXPOSED
+
+ else if(removal_stage == NUKE_CORE_PANEL_EXPOSED)
+ user.visible_message("[user] starts unwelding [src]'s inner core plate...", "You start unwelding [src]'s inner core plate...")
+ if(!I.use_tool(src, user, 4 SECONDS, 5, volume = I.tool_volume) || removal_stage != NUKE_CORE_PANEL_EXPOSED)
+ return
+ user.visible_message("[user] finishes unwelding [src]'s inner core plate...", "You finish unwelding [src]'s inner core plate...")
+ removal_stage = NUKE_CORE_PANEL_UNWELDED
+ if(removal_stage == NUKE_COVER_OPEN)
visible_message("[user] starts cutting apart the anchoring system sealant on [src].",\
"You start cutting apart the anchoring system's sealant with [I]...",\
"You hear welding.")
@@ -181,10 +252,18 @@ GLOBAL_VAR(bomb_set)
attack_hand(user)
/obj/machinery/nuclearbomb/attack_hand(mob/user as mob)
- if(panel_open)
- wires.Interact(user)
- else
- ui_interact(user)
+ if(!panel_open)
+ return ui_interact(user)
+ if(removal_stage != NUKE_CORE_FULLY_EXPOSED || !core)
+ return wires.Interact(user)
+ if(timing) //removing the core is less risk then cutting wires, and doesnt take long, so we should not let crew do it while the nuke is armed. You can however get to it, without the special screwdriver, if you put the NAD in.
+ to_chat(user, "[core] won't budge, metal clamps keep it in!")
+ return
+ user.visible_message("[user] starts to pull [core] out of [src]!", "You start to pull [core] out of [src]!")
+ if(do_after(user, 5 SECONDS, target = src))
+ user.visible_message("[user] pulls [core] out of [src]!", "You pull [core] out of [src]! Might want to put it somewhere safe.")
+ core.forceMove(loc)
+ core = null
/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
@@ -308,6 +387,9 @@ GLOBAL_VAR(bomb_set)
if(safety)
to_chat(usr, "The safety is still on.")
return
+ if(!core)
+ to_chat(usr, "[src]'s screen blinks red! There is no plutonium core in [src]!")
+ return
timing = !(timing)
if(timing)
if(!lighthack)
@@ -471,3 +553,7 @@ GLOBAL_VAR(bomb_set)
#undef NUKE_SEALANT_OPEN
#undef NUKE_UNWRENCHED
#undef NUKE_MOBILE
+#undef NUKE_CORE_EVERYTHING_FINE
+#undef NUKE_CORE_PANEL_EXPOSED
+#undef NUKE_CORE_PANEL_UNWELDED
+#undef NUKE_CORE_FULLY_EXPOSED
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index b7ff2d7992e..b5bb07ff234 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -391,6 +391,8 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
explanation_text = "Steal [steal_target]. One was last seen in [get_location()]. "
if(length(O.protected_jobs))
explanation_text += "It may also be in the possession of the [english_list(O.protected_jobs, and_text = " or ")]."
+ if(steal_target.special_equipment)
+ give_kit(steal_target.special_equipment)
return
explanation_text = "Free Objective."
@@ -412,6 +414,8 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
else
steal_target = new new_target
explanation_text = "Steal [steal_target.name]."
+ if(steal_target.special_equipment)
+ give_kit(steal_target.special_equipment)
return steal_target
/datum/objective/steal/check_completion()
@@ -429,6 +433,23 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
if(I.type in steal_target.altitems)
return steal_target.check_special_completion(I)
+/datum/objective/steal/proc/give_kit(obj/item/item_path)
+ var/mob/living/carbon/human/mob = owner.current
+ var/I = new item_path
+ var/list/slots = list(
+ "backpack" = slot_in_backpack,
+ "left pocket" = slot_l_store,
+ "right pocket" = slot_r_store,
+ "left hand" = slot_l_hand,
+ "right hand" = slot_r_hand,
+ )
+ var/where = mob.equip_in_one_of_slots(I, slots)
+ if(where)
+ to_chat(mob, "
In your [where] is a box containing items and instructions to help you with your steal objective.
")
+ else
+ to_chat(mob, "Unfortunately, you weren't able to get a stealing kit. This is very bad and you should adminhelp immediately (press F1).")
+ message_admins("[ADMIN_LOOKUPFLW(mob)] Failed to spawn with their [item_path] theft kit.")
+ qdel(I)
/datum/objective/steal/exchange
martyr_compatible = 0
diff --git a/code/game/gamemodes/steal_items.dm b/code/game/gamemodes/steal_items.dm
index 780962045be..24ea05d786c 100644
--- a/code/game/gamemodes/steal_items.dm
+++ b/code/game/gamemodes/steal_items.dm
@@ -12,6 +12,8 @@
var/list/altitems = list()
var/flags = 0
var/location_override
+ /// Do we have a special item we give to somewhen when they get this objective?
+ var/special_equipment = null
/datum/theft_objective/proc/check_completion(datum/mind/owner)
if(!owner.current)
@@ -138,6 +140,19 @@
protected_jobs = list("Head Of Security", "Warden")
location_override = "the Warden's Office"
+/datum/theft_objective/supermatter_sliver
+ name = "a supermatter sliver"
+ typepath = /obj/item/nuke_core/supermatter_sliver
+ protected_jobs = list("Chief Engineer", "Engineer", "Atmospheric Technician") //Unlike other steal objectives, all jobs in the department have easy access, and would not be noticed at all stealing this
+ location_override = "Engineering. You can use the box and instructions provided to harvest the sliver."
+ special_equipment = /obj/item/storage/box/syndie_kit/supermatter
+
+/datum/theft_objective/plutonium_core
+ name = "the plutonium core from the stations nuclear device"
+ typepath = /obj/item/nuke_core/plutonium
+ location_override = "the Vault. You can use the box and instructions provided to remove the core, with some extra tools."
+ special_equipment = /obj/item/storage/box/syndie_kit/nuke
+
/datum/theft_objective/number
var/min=0
var/max=0
diff --git a/code/game/objects/items/theft_items.dm b/code/game/objects/items/theft_items.dm
new file mode 100644
index 00000000000..0a32cf90df7
--- /dev/null
+++ b/code/game/objects/items/theft_items.dm
@@ -0,0 +1,282 @@
+//Items for nuke theft, supermatter theft traitor objective
+
+
+// STEALING THE NUKE
+
+//the nuke core, base item
+/obj/item/nuke_core
+ name = "plutonium core"
+ desc = "Extremely radioactive. Wear goggles."
+ icon = 'icons/obj/nuke_tools.dmi'
+ icon_state = "plutonium_core"
+ item_state = "plutoniumcore"
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ flags_2 = RAD_NO_CONTAMINATE_2 //Don't have the item itself become irradiated when it makes radiation.
+ var/pulse = 0
+ var/cooldown = 0
+ var/pulseicon = "plutonium_core_pulse"
+
+/obj/item/nuke_core/Initialize()
+ . = ..()
+ START_PROCESSING(SSobj, src)
+
+/obj/item/nuke_core/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/item/nuke_core/attackby(obj/item/nuke_core_container/container, mob/user)
+ if(istype(container))
+ container.load(src, user)
+ else
+ return ..()
+
+/obj/item/nuke_core/process()
+ if(cooldown < world.time - 6 SECONDS)
+ cooldown = world.time
+ flick(pulseicon, src)
+ radiation_pulse(src, 400, 2)
+
+/obj/item/nuke_core/suicide_act(mob/user)
+ user.visible_message("[user] is rubbing [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to commit suicide!")
+ return TOXLOSS
+
+/obj/item/nuke_core/plutonium //The steal objective, so it doesnt mess with the SM sliver on pinpointers and objectives
+
+//nuke core box, for carrying the core
+/obj/item/nuke_core_container
+ name = "nuke core container"
+ desc = "A solid container for radioactive objects."
+ icon = 'icons/obj/nuke_tools.dmi'
+ icon_state = "core_container_empty"
+ item_state = "metal"
+ var/obj/item/nuke_core/plutonium/core
+
+/obj/item/nuke_core_container/Destroy()
+ QDEL_NULL(core)
+ return ..()
+
+/obj/item/nuke_core_container/proc/load(obj/item/nuke_core/plutonium/new_core, mob/user)
+ if(core || !istype(new_core))
+ return
+ new_core.forceMove(src)
+ core = new_core
+ icon_state = "core_container_loaded"
+ to_chat(user, "Container is sealing...")
+ addtimer(CALLBACK(src, .proc/seal), 10 SECONDS)
+
+/obj/item/nuke_core_container/proc/seal()
+ if(!QDELETED(core))
+ STOP_PROCESSING(SSobj, core)
+ icon_state = "core_container_sealed"
+ playsound(src, 'sound/items/deconstruct.ogg', 60, TRUE)
+ if(ismob(loc))
+ to_chat(loc, "[src] is permanently sealed, [core]'s radiation is contained.")
+
+/obj/item/nuke_core_container/attackby(obj/item/nuke_core/plutonium/core, mob/user)
+ if(!istype(core))
+ return ..()
+
+ if(!user.drop_item())
+ to_chat(user, "[core] is stuck to your hand!")
+ return
+ else
+ load(core, user)
+
+/obj/item/paper/guides/antag/nuke_instructions
+ info = "How to break into a Nanotrasen nuclear device and remove its plutonium core:
\
+