From f6ce07289a4e38eb4a865dbf5c70b9e1482899d1 Mon Sep 17 00:00:00 2001
From: deltanedas <39013340+deltanedas@users.noreply.github.com>
Date: Sat, 29 Jun 2024 04:11:31 +0000
Subject: [PATCH] plutonium core steal objective (#26786)
* add textures
* add SealingCabinet system
* add StoreUnlocker/ObjectiveUnlock system
* add plutonium core and nuke core container
* make nuke deconstructable
* add steal core objective
* add core extraction toolbox to new category
* typo ops wrench fuel
* use queries and resolve, have it resolve instead of using Comp
---------
Co-authored-by: deltanedas <@deltanedas:kde.org>
---
.../Components/StoreUnlockerComponent.cs | 14 ++++
.../Objectives/Systems/StoreUnlockerSystem.cs | 34 ++++++++
.../Conditions/ObjectiveUnlockCondition.cs | 21 +++++
Content.Shared/Cabinet/ItemCabinetSystem.cs | 25 ++++--
.../Cabinet/SealingCabinetComponent.cs | 23 +++++
.../Cabinet/SealingCabinetSystem.cs | 45 ++++++++++
.../Locale/en-US/nuke/nuke-core-container.ftl | 2 +
.../en-US/objectives/conditions/steal.ftl | 1 +
Resources/Locale/en-US/store/categories.ftl | 1 +
.../Locale/en-US/store/uplink-catalog.ftl | 4 +
.../Locale/en-US/tools/tool-qualities.ftl | 5 +-
.../Catalog/Fills/Items/toolboxes.yml | 13 +++
.../Prototypes/Catalog/uplink_catalog.yml | 20 +++++
.../Entities/Objects/Misc/plutonium_core.yml | 63 ++++++++++++++
.../Entities/Objects/Tools/syndicate.yml | 10 +++
.../Entities/Structures/Machines/nuke.yml | 42 +++++++---
.../Prototypes/Objectives/objectiveGroups.yml | 3 +-
.../Objectives/stealTargetGroups.yml | 7 ++
Resources/Prototypes/Objectives/traitor.yml | 18 ++++
.../Construction/Graphs/structures/nuke.yml | 79 ++++++++++++++++++
Resources/Prototypes/Store/categories.yml | 5 ++
Resources/Prototypes/Store/presets.yml | 1 +
Resources/Prototypes/tags.yml | 3 +
Resources/Prototypes/tool_qualities.yml | 8 ++
.../Misc/nuke_core_container.rsi/closed.png | Bin 0 -> 248 bytes
.../nuke_core_container.rsi/core_closed.png | Bin 0 -> 461 bytes
.../nuke_core_container.rsi/core_open.png | Bin 0 -> 351 bytes
.../nuke_core_container.rsi/inhand-left.png | Bin 0 -> 285 bytes
.../nuke_core_container.rsi/inhand-right.png | Bin 0 -> 293 bytes
.../Misc/nuke_core_container.rsi/meta.json | 47 +++++++++++
.../Misc/nuke_core_container.rsi/open.png | Bin 0 -> 330 bytes
.../Objects/Misc/plutonium_core.rsi/icon.png | Bin 0 -> 386 bytes
.../Objects/Misc/plutonium_core.rsi/meta.json | 23 +++++
33 files changed, 497 insertions(+), 20 deletions(-)
create mode 100644 Content.Server/Objectives/Components/StoreUnlockerComponent.cs
create mode 100644 Content.Server/Objectives/Systems/StoreUnlockerSystem.cs
create mode 100644 Content.Server/Store/Conditions/ObjectiveUnlockCondition.cs
create mode 100644 Content.Shared/Cabinet/SealingCabinetComponent.cs
create mode 100644 Content.Shared/Cabinet/SealingCabinetSystem.cs
create mode 100644 Resources/Locale/en-US/nuke/nuke-core-container.ftl
create mode 100644 Resources/Prototypes/Entities/Objects/Misc/plutonium_core.yml
create mode 100644 Resources/Prototypes/Entities/Objects/Tools/syndicate.yml
create mode 100644 Resources/Prototypes/Recipes/Construction/Graphs/structures/nuke.yml
create mode 100644 Resources/Textures/Objects/Misc/nuke_core_container.rsi/closed.png
create mode 100644 Resources/Textures/Objects/Misc/nuke_core_container.rsi/core_closed.png
create mode 100644 Resources/Textures/Objects/Misc/nuke_core_container.rsi/core_open.png
create mode 100644 Resources/Textures/Objects/Misc/nuke_core_container.rsi/inhand-left.png
create mode 100644 Resources/Textures/Objects/Misc/nuke_core_container.rsi/inhand-right.png
create mode 100644 Resources/Textures/Objects/Misc/nuke_core_container.rsi/meta.json
create mode 100644 Resources/Textures/Objects/Misc/nuke_core_container.rsi/open.png
create mode 100644 Resources/Textures/Objects/Misc/plutonium_core.rsi/icon.png
create mode 100644 Resources/Textures/Objects/Misc/plutonium_core.rsi/meta.json
diff --git a/Content.Server/Objectives/Components/StoreUnlockerComponent.cs b/Content.Server/Objectives/Components/StoreUnlockerComponent.cs
new file mode 100644
index 000000000000..b53aae945ace
--- /dev/null
+++ b/Content.Server/Objectives/Components/StoreUnlockerComponent.cs
@@ -0,0 +1,14 @@
+using Content.Shared.Store;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Objectives.Components;
+
+///
+/// Unlocks store listings that use .
+///
+[RegisterComponent]
+public sealed partial class StoreUnlockerComponent : Component
+{
+ [DataField(required: true)]
+ public List> Listings = new();
+}
diff --git a/Content.Server/Objectives/Systems/StoreUnlockerSystem.cs b/Content.Server/Objectives/Systems/StoreUnlockerSystem.cs
new file mode 100644
index 000000000000..28cf768d333a
--- /dev/null
+++ b/Content.Server/Objectives/Systems/StoreUnlockerSystem.cs
@@ -0,0 +1,34 @@
+using Content.Server.Objectives.Components;
+using Content.Shared.Mind;
+
+namespace Content.Server.Objectives.Systems;
+
+///
+/// Provides api for listings with ObjectiveUnlockRequirement to use.
+///
+public sealed class StoreUnlockerSystem : EntitySystem
+{
+ private EntityQuery _query;
+
+ public override void Initialize()
+ {
+ _query = GetEntityQuery();
+ }
+
+ ///
+ /// Returns true if a listing id is unlocked by any objectives on a mind.
+ ///
+ public bool IsUnlocked(MindComponent mind, string id)
+ {
+ foreach (var obj in mind.Objectives)
+ {
+ if (!_query.TryComp(obj, out var comp))
+ continue;
+
+ if (comp.Listings.Contains(id))
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/Content.Server/Store/Conditions/ObjectiveUnlockCondition.cs b/Content.Server/Store/Conditions/ObjectiveUnlockCondition.cs
new file mode 100644
index 000000000000..a9dafc28ff88
--- /dev/null
+++ b/Content.Server/Store/Conditions/ObjectiveUnlockCondition.cs
@@ -0,0 +1,21 @@
+using Content.Shared.Mind;
+using Content.Shared.Store;
+using Content.Server.Objectives.Systems;
+
+namespace Content.Server.Store.Conditions;
+
+///
+/// Requires that the buyer have an objective that unlocks this listing.
+///
+public sealed partial class ObjectiveUnlockCondition : ListingCondition
+{
+ public override bool Condition(ListingConditionArgs args)
+ {
+ var minds = args.EntityManager.System();
+ if (!minds.TryGetMind(args.Buyer, out _, out var mind))
+ return false;
+
+ var unlocker = args.EntityManager.System();
+ return unlocker.IsUnlocked(mind, args.Listing.ID);
+ }
+}
diff --git a/Content.Shared/Cabinet/ItemCabinetSystem.cs b/Content.Shared/Cabinet/ItemCabinetSystem.cs
index 749065ac4761..e14e269d4fdd 100644
--- a/Content.Shared/Cabinet/ItemCabinetSystem.cs
+++ b/Content.Shared/Cabinet/ItemCabinetSystem.cs
@@ -16,11 +16,17 @@ public sealed class ItemCabinetSystem : EntitySystem
[Dependency] private readonly OpenableSystem _openable = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+ private EntityQuery _cabinetQuery = default!;
+ private EntityQuery _slotsQuery = default!;
+
///
public override void Initialize()
{
base.Initialize();
+ _cabinetQuery = GetEntityQuery();
+ _slotsQuery = GetEntityQuery();
+
SubscribeLocalEvent(OnStartup);
SubscribeLocalEvent(OnMapInit);
SubscribeLocalEvent(OnContainerModified);
@@ -37,12 +43,12 @@ private void OnStartup(Entity ent, ref ComponentStartup ar
private void OnMapInit(Entity ent, ref MapInitEvent args)
{
// update at mapinit to avoid copy pasting locked: true and locked: false for each closed/open prototype
- SetSlotLock(ent, !_openable.IsOpen(ent));
+ SetSlotLock((ent, ent.Comp), !_openable.IsOpen(ent));
}
private void UpdateAppearance(Entity ent)
{
- _appearance.SetData(ent, ItemCabinetVisuals.ContainsItem, HasItem(ent));
+ _appearance.SetData(ent, ItemCabinetVisuals.ContainsItem, HasItem((ent, ent.Comp)));
}
private void OnContainerModified(EntityUid uid, ItemCabinetComponent component, ContainerModifiedMessage args)
@@ -53,21 +59,24 @@ private void OnContainerModified(EntityUid uid, ItemCabinetComponent component,
private void OnOpened(Entity ent, ref OpenableOpenedEvent args)
{
- SetSlotLock(ent, false);
+ SetSlotLock((ent, ent.Comp), false);
}
private void OnClosed(Entity ent, ref OpenableClosedEvent args)
{
- SetSlotLock(ent, true);
+ SetSlotLock((ent, ent.Comp), true);
}
///
/// Tries to get the cabinet's item slot.
///
- public bool TryGetSlot(Entity ent, [NotNullWhen(true)] out ItemSlot? slot)
+ public bool TryGetSlot(Entity ent, [NotNullWhen(true)] out ItemSlot? slot)
{
slot = null;
- if (!TryComp(ent, out var slots))
+ if (!_cabinetQuery.Resolve(ent, ref ent.Comp))
+ return false;
+
+ if (!_slotsQuery.TryComp(ent, out var slots))
return false;
return _slots.TryGetSlot(ent, ent.Comp.Slot, out slot, slots);
@@ -76,7 +85,7 @@ public bool TryGetSlot(Entity ent, [NotNullWhen(true)] out
///
/// Returns true if the cabinet contains an item.
///
- public bool HasItem(Entity ent)
+ public bool HasItem(Entity ent)
{
return TryGetSlot(ent, out var slot) && slot.HasItem;
}
@@ -86,7 +95,7 @@ public bool HasItem(Entity ent)
///
public void SetSlotLock(Entity ent, bool closed)
{
- if (!TryComp(ent, out var slots))
+ if (!_slotsQuery.TryComp(ent, out var slots))
return;
if (_slots.TryGetSlot(ent, ent.Comp.Slot, out var slot, slots))
diff --git a/Content.Shared/Cabinet/SealingCabinetComponent.cs b/Content.Shared/Cabinet/SealingCabinetComponent.cs
new file mode 100644
index 000000000000..53a4f7f3ff43
--- /dev/null
+++ b/Content.Shared/Cabinet/SealingCabinetComponent.cs
@@ -0,0 +1,23 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Cabinet;
+
+///
+/// Item cabinet that cannot be opened if it has an item inside.
+/// The only way to open it after that is to emag it.
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class SealingCabinetComponent : Component
+{
+ ///
+ /// Popup shown when trying to open the cabinet once sealed.
+ ///
+ [DataField(required: true)]
+ public LocId SealedPopup = string.Empty;
+
+ ///
+ /// Set to false to disable emag unsealing.
+ ///
+ [DataField]
+ public bool Emaggable = true;
+}
diff --git a/Content.Shared/Cabinet/SealingCabinetSystem.cs b/Content.Shared/Cabinet/SealingCabinetSystem.cs
new file mode 100644
index 000000000000..be07b8a61f4a
--- /dev/null
+++ b/Content.Shared/Cabinet/SealingCabinetSystem.cs
@@ -0,0 +1,45 @@
+using Content.Shared.Emag.Systems;
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Nutrition.EntitySystems;
+using Content.Shared.Popups;
+
+namespace Content.Shared.Cabinet;
+
+public sealed class SealingCabinetSystem : EntitySystem
+{
+ [Dependency] private readonly ItemCabinetSystem _cabinet = default!;
+ [Dependency] private readonly OpenableSystem _openable = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnOpenAttempt);
+ SubscribeLocalEvent(OnEmagged);
+ }
+
+ private void OnOpenAttempt(Entity ent, ref OpenableOpenAttemptEvent args)
+ {
+ if (!_cabinet.HasItem(ent.Owner))
+ return;
+
+ args.Cancelled = true;
+ if (args.User is {} user)
+ _popup.PopupClient(Loc.GetString(ent.Comp.SealedPopup, ("container", ent.Owner)), ent, user);
+ }
+
+ private void OnEmagged(Entity ent, ref GotEmaggedEvent args)
+ {
+ if (!ent.Comp.Emaggable)
+ return;
+
+ if (!_cabinet.HasItem(ent.Owner) || _openable.IsOpen(ent))
+ return;
+
+ _openable.SetOpen(ent, true);
+
+ args.Handled = true;
+ args.Repeatable = true;
+ }
+}
diff --git a/Resources/Locale/en-US/nuke/nuke-core-container.ftl b/Resources/Locale/en-US/nuke/nuke-core-container.ftl
new file mode 100644
index 000000000000..47ea15a8316a
--- /dev/null
+++ b/Resources/Locale/en-US/nuke/nuke-core-container.ftl
@@ -0,0 +1,2 @@
+nuke-core-container-whitelist-fail-popup = That doesn't fit into the container.
+nuke-core-container-sealed-popup = The {$container} is sealed shut!
diff --git a/Resources/Locale/en-US/objectives/conditions/steal.ftl b/Resources/Locale/en-US/objectives/conditions/steal.ftl
index 00c8e0fdaf93..1bca71ce90df 100644
--- a/Resources/Locale/en-US/objectives/conditions/steal.ftl
+++ b/Resources/Locale/en-US/objectives/conditions/steal.ftl
@@ -4,6 +4,7 @@ objective-condition-steal-title = Steal the {$owner}'s {$itemName}.
objective-condition-steal-description = We need you to steal {$itemName}. Don't get caught.
objective-condition-steal-station = station
+objective-condition-steal-nuclear-bomb = nuclear bomb
objective-condition-steal-Ian = head of personnel's corgi
objective-condition-thief-description = The {$itemName} would be a great addition to my collection!
diff --git a/Resources/Locale/en-US/store/categories.ftl b/Resources/Locale/en-US/store/categories.ftl
index 4ebeff3b2376..e2804158c6cf 100644
--- a/Resources/Locale/en-US/store/categories.ftl
+++ b/Resources/Locale/en-US/store/categories.ftl
@@ -12,6 +12,7 @@ store-category-allies = Allies
store-category-job = Job
store-category-wearables = Wearables
store-category-pointless = Pointless
+store-category-objectives = Objectives
# Revenant
store-category-abilities = Abilities
diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl
index 2598970cefbe..8a7b0800c0ba 100644
--- a/Resources/Locale/en-US/store/uplink-catalog.ftl
+++ b/Resources/Locale/en-US/store/uplink-catalog.ftl
@@ -433,3 +433,7 @@ uplink-barber-scissors-desc = A good tool to give your fellow agent a nice hairc
uplink-backpack-syndicate-name = Syndicate backpack
uplink-backpack-syndicate-desc = Lightweight explosion-proof а backpack for holding various traitor goods
+
+# Objectives
+uplink-core-extraction-toolbox-name = Core Extraction Toolbox
+uplink-core-extraction-toolbox-desc = A toolbox containing everything you need to remove a nuclear bomb's plutonium core. Instructions not included.
diff --git a/Resources/Locale/en-US/tools/tool-qualities.ftl b/Resources/Locale/en-US/tools/tool-qualities.ftl
index 14e42390a766..a398d458505f 100644
--- a/Resources/Locale/en-US/tools/tool-qualities.ftl
+++ b/Resources/Locale/en-US/tools/tool-qualities.ftl
@@ -32,4 +32,7 @@ tool-quality-rolling-name = Rolling
tool-quality-rolling-tool-name = Rolling Pin
tool-quality-digging-name = Digging
-tool-quality-digging-tool-name = Shovel
\ No newline at end of file
+tool-quality-digging-tool-name = Shovel
+
+tool-quality-fine-screwing-name = Fine Screwing
+tool-quality-fine-screwing-tool-name = Thin-Tipped Screwdriver
diff --git a/Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml b/Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml
index 1091207bba47..1b47a4f46dd7 100644
--- a/Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml
+++ b/Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml
@@ -121,6 +121,19 @@
- id: ClothingHandsGlovesCombat
- id: ClothingMaskGasSyndicate
+- type: entity
+ parent: ToolboxSyndicate
+ id: ToolboxSyndicateFilledCoreExtraction
+ suffix: Filled, Core Extraction
+ components:
+ - type: StorageFill
+ contents:
+ - id: Crowbar
+ - id: Welder
+ - id: Wrench
+ - id: ThinTippedScrewdriver
+ - id: NukeCoreContainer
+
- type: entity
id: ToolboxGoldFilled
name: golden toolbox
diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml
index 0ba83dfe735f..a921b7fbd375 100644
--- a/Resources/Prototypes/Catalog/uplink_catalog.yml
+++ b/Resources/Prototypes/Catalog/uplink_catalog.yml
@@ -1727,3 +1727,23 @@
blacklist:
components:
- SurplusBundle
+
+# Objective-specific
+- type: listing
+ id: UplinkCoreExtractionToolbox
+ name: uplink-core-extraction-toolbox-name
+ description: uplink-core-extraction-toolbox-desc
+ icon:
+ sprite: Objects/Misc/nuke_core_container.rsi
+ state: closed
+ productEntity: ToolboxSyndicateFilledCoreExtraction
+ categories:
+ - UplinkObjectives
+ conditions:
+ - !type:ObjectiveUnlockCondition
+ - !type:ListingLimitedStockCondition
+ stock: 1
+ - !type:BuyerWhitelistCondition
+ blacklist:
+ components:
+ - SurplusBundle
diff --git a/Resources/Prototypes/Entities/Objects/Misc/plutonium_core.yml b/Resources/Prototypes/Entities/Objects/Misc/plutonium_core.yml
new file mode 100644
index 000000000000..67910888871d
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Misc/plutonium_core.yml
@@ -0,0 +1,63 @@
+- type: entity
+ parent: BaseItem
+ id: PlutoniumCore
+ name: plutonium core
+ description: Extremely radioactive, even looking at this with the naked eye is dangerous.
+ components:
+ - type: Sprite
+ sprite: Objects/Misc/plutonium_core.rsi
+ state: icon
+ - type: StealTarget
+ stealGroup: PlutoniumCore
+ - type: RadiationSource
+ intensity: 4
+ slope: 1
+ - type: StaticPrice
+ price: 49000
+ - type: Tag
+ tags:
+ - PlutoniumCore
+
+- type: entity
+ parent: [BaseItem, BaseItemCabinet]
+ id: NukeCoreContainer
+ name: nuke core container
+ description: Solid container for radioactive objects.
+ components:
+ - type: Sprite
+ sprite: Objects/Misc/nuke_core_container.rsi
+ layers:
+ - state: closed
+ map: [ "enum.OpenableVisuals.Layer" ]
+ - state: core_closed
+ map: [ "enum.ItemCabinetVisuals.Layer" ]
+ visible: false
+ shader: unshaded
+ - type: Item
+ size: Normal
+ shape:
+ - 0,0,1,1
+ - type: RadiationBlockingContainer
+ resistance: 4
+ - type: SealingCabinet
+ sealedPopup: nuke-core-container-sealed-popup
+ - type: ItemSlots
+ slots:
+ ItemCabinet:
+ whitelist:
+ tags:
+ - PlutoniumCore
+ whitelistFailPopup: nuke-core-container-whitelist-fail-popup
+ - type: GenericVisualizer
+ visuals:
+ enum.OpenableVisuals.Opened:
+ enum.OpenableVisuals.Layer:
+ True: { state: open }
+ False: { state: closed }
+ enum.ItemCabinetVisuals.Layer:
+ True: { state: core_open }
+ False: { state: core_closed }
+ enum.ItemCabinetVisuals.ContainsItem:
+ enum.ItemCabinetVisuals.Layer:
+ True: { visible: true }
+ False: { visible: false }
diff --git a/Resources/Prototypes/Entities/Objects/Tools/syndicate.yml b/Resources/Prototypes/Entities/Objects/Tools/syndicate.yml
new file mode 100644
index 000000000000..3d42a17761a7
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Tools/syndicate.yml
@@ -0,0 +1,10 @@
+- type: entity
+ parent: Screwdriver
+ id: ThinTippedScrewdriver
+ description: A screwdriver with an ultra thin tip that's carefully designed to boost screwing speed.
+ suffix: DO NOT MAP
+ components:
+ - type: Tool
+ qualities:
+ - Screwing
+ - FineScrewing
diff --git a/Resources/Prototypes/Entities/Structures/Machines/nuke.yml b/Resources/Prototypes/Entities/Structures/Machines/nuke.yml
index 1cf9ceaeab34..c2b6ccdbc0ad 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/nuke.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/nuke.yml
@@ -1,8 +1,8 @@
- type: entity
+ abstract: true
parent: [BaseStructure, StructureWheeled]
- id: NuclearBomb
+ id: BaseNuclearBomb
name: nuclear fission explosive
- description: You probably shouldn't stick around to see if this is armed.
components:
- type: Transform
anchored: true
@@ -61,6 +61,23 @@
- MachineMask
layer:
- HalfWallLayer
+ - type: InteractionOutline
+ - type: CargoSellBlacklist
+ - type: ArrivalsBlacklist
+ - type: WarpPoint
+ follow: true
+ location: nuclear bomb
+ - type: StealTarget
+ stealGroup: NuclearBomb
+ - type: Construction
+ graph: NuclearBomb
+ deconstructionTarget: disarmed
+
+- type: entity
+ parent: BaseNuclearBomb
+ id: NuclearBomb
+ description: You probably shouldn't stick around to see if this is armed.
+ components:
- type: PointLight
enabled: false
radius: 4
@@ -90,7 +107,6 @@
- NukeDisk
alertLevelOnActivate: delta
alertLevelOnDeactivate: green
- - type: InteractionOutline
- type: ActivatableUI
key: enum.NukeUiKey.Key
- type: UserInterface
@@ -99,17 +115,12 @@
type: NukeBoundUserInterface
- type: StaticPrice
price: 50000 # YOU STOLE A NUCLEAR FISSION EXPLOSIVE?!
- - type: CargoSellBlacklist
- - type: ArrivalsBlacklist
- type: ItemSlots
- type: ContainerContainer
containers:
Nuke: !type:ContainerSlot
- - type: StealTarget
- stealGroup: NuclearBomb
- - type: WarpPoint
- follow: true
- location: nuclear bomb
+ - type: Construction
+ node: nuke
- type: entity
parent: NuclearBomb
@@ -121,6 +132,17 @@
- type: Physics
bodyType: Dynamic
+- type: entity
+ parent: BaseNuclearBomb
+ id: NuclearBombDisarmed
+ suffix: Disarmed
+ description: "You can clearly see that this can't be armed, given its lack of nuclear material."
+ components:
+ - type: StaticPrice
+ price: 1000 # fancy paperweight
+ - type: Construction
+ node: disarmed
+
- type: entity
parent: StorageTank
id: NuclearBombKeg
diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml
index bb74c92da3b5..9e73f5a55bc0 100644
--- a/Resources/Prototypes/Objectives/objectiveGroups.yml
+++ b/Resources/Prototypes/Objectives/objectiveGroups.yml
@@ -14,7 +14,6 @@
CMOHyposprayStealObjective: 1
CMOCrewMonitorStealObjective: 1
RDHardsuitStealObjective: 1
- NukeDiskStealObjective: 1
MagbootsStealObjective: 1
CorgiMeatStealObjective: 1
ClipboardStealObjective: 1
@@ -22,6 +21,8 @@
CaptainJetpackStealObjective: 0.5
HandTeleporterStealObjective: 0.5
SecretDocumentsStealObjective: 0.5
+ PlutoniumCoreStealObjective: 0.5
+ NukeDiskStealObjective: 0.25
- type: weightedRandom
id: TraitorObjectiveGroupKill
diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml
index 52117b9ce9ca..aa9722cfbd24 100644
--- a/Resources/Prototypes/Objectives/stealTargetGroups.yml
+++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml
@@ -84,6 +84,13 @@
sprite: Objects/Misc/nukedisk.rsi
state: icon
+- type: stealTargetGroup
+ id: PlutoniumCore
+ name: plutonium core
+ sprite:
+ sprite: Objects/Misc/plutonium_core.rsi
+ state: icon
+
# Thief Collection
- type: stealTargetGroup
diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml
index ad5f56a443ea..1e6795d4d471 100644
--- a/Resources/Prototypes/Objectives/traitor.yml
+++ b/Resources/Prototypes/Objectives/traitor.yml
@@ -293,3 +293,21 @@
- type: StealCondition
stealGroup: NukeDisk
owner: objective-condition-steal-station
+
+# Station
+
+- type: entity
+ noSpawn: true
+ parent: BaseTraitorStealObjective
+ id: PlutoniumCoreStealObjective
+ components:
+ - type: Objective
+ # its hard to steal and leaves evidence, but you can get away with it.
+ difficulty: 3.5
+ - type: NotCommandRequirement
+ - type: StealCondition
+ stealGroup: PlutoniumCore
+ owner: objective-condition-steal-nuclear-bomb
+ - type: StoreUnlocker
+ listings:
+ - UplinkCoreExtractionToolbox
diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/nuke.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/nuke.yml
new file mode 100644
index 000000000000..0c63e82f4026
--- /dev/null
+++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/nuke.yml
@@ -0,0 +1,79 @@
+- type: constructionGraph
+ id: NuclearBomb
+ start: disarmed
+ graph:
+ - node: disarmed
+ entity: NuclearBombDisarmed
+ edges:
+ - to: core_exposed
+ steps:
+ - tag: PlutoniumCore
+ name: "a plutonium core"
+ icon:
+ sprite: Objects/Misc/plutonium_core.rsi
+ state: icon
+ doAfter: 1
+
+ - node: core_exposed
+ edges:
+ - to: disarmed
+ completed:
+ - !type:GivePrototype
+ prototype: PlutoniumCore
+ steps:
+ - tool: Prying
+ doAfter: 2
+ - to: panel_removed
+ steps:
+ - material: Plasteel
+ amount: 8
+ doAfter: 2
+ - tool: Welding
+ doAfter: 4
+
+ - node: panel_removed
+ edges:
+ - to: core_exposed
+ completed:
+ - !type:GivePrototype
+ prototype: SheetPlasteel1
+ amount: 8
+ steps:
+ - tool: Welding
+ doAfter: 6
+ - tool: Anchoring
+ doAfter: 2
+ - tool: Welding
+ doAfter: 8
+ - to: panel_exposed
+ steps:
+ - material: Plasteel
+ amount: 4
+ doAfter: 2
+ - tool: Welding
+ doAfter: 2
+
+ - node: panel_exposed
+ edges:
+ - to: panel_removed
+ completed:
+ - !type:GivePrototype
+ prototype: SheetPlasteel1
+ amount: 4
+ steps:
+ - tool: Welding
+ doAfter: 2
+ - tool: Prying
+ doAfter: 2
+ - to: nuke
+ steps:
+ - tool: FineScrewing
+ doAfter: 2
+
+ - node: nuke
+ entity: NuclearBomb
+ edges:
+ - to: panel_exposed
+ steps:
+ - tool: FineScrewing
+ doAfter: 2
diff --git a/Resources/Prototypes/Store/categories.yml b/Resources/Prototypes/Store/categories.yml
index 6bd9756c3e94..b4aea0bea4f6 100644
--- a/Resources/Prototypes/Store/categories.yml
+++ b/Resources/Prototypes/Store/categories.yml
@@ -89,6 +89,11 @@
name: store-category-pointless
priority: 10
+- type: storeCategory
+ id: UplinkObjectives
+ name: store-category-objectives
+ priority: 11
+
#revenant
- type: storeCategory
id: RevenantAbilities
diff --git a/Resources/Prototypes/Store/presets.yml b/Resources/Prototypes/Store/presets.yml
index 762ed68921aa..5905cb80bab6 100644
--- a/Resources/Prototypes/Store/presets.yml
+++ b/Resources/Prototypes/Store/presets.yml
@@ -16,6 +16,7 @@
- UplinkWearables
- UplinkJob
- UplinkPointless
+ - UplinkObjectives
currencyWhitelist:
- Telecrystal
balance:
diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml
index dee16b7414b5..ede344eeaba2 100644
--- a/Resources/Prototypes/tags.yml
+++ b/Resources/Prototypes/tags.yml
@@ -1020,6 +1020,9 @@
- type: Tag
id: PlushieSharkPink
+- type: Tag
+ id: PlutoniumCore
+
- type: Tag
id: Potato
diff --git a/Resources/Prototypes/tool_qualities.yml b/Resources/Prototypes/tool_qualities.yml
index ff55d9fcf14c..a6c712c6842e 100644
--- a/Resources/Prototypes/tool_qualities.yml
+++ b/Resources/Prototypes/tool_qualities.yml
@@ -67,3 +67,11 @@
toolName: tool-quality-rolling-tool-name
spawn: RollingPin
icon: { sprite: Objects/Tools/rolling_pin.rsi, state: icon }
+
+# do not give this to normal tools, its for nuke deconstruction
+- type: tool
+ id: FineScrewing
+ name: tool-quality-fine-screwing
+ toolName: tool-quality-fine-screwing-tool-name
+ spawn: ThinTippedScrewdriver
+ icon: { sprite: Objects/Tools/screwdriver.rsi, state: screwdriver-map }
diff --git a/Resources/Textures/Objects/Misc/nuke_core_container.rsi/closed.png b/Resources/Textures/Objects/Misc/nuke_core_container.rsi/closed.png
new file mode 100644
index 0000000000000000000000000000000000000000..ba6632404df871abafccbe942212e3adfb963efd
GIT binary patch
literal 248
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D7ebg
z#W5t}aB_kK>*55Fo{|F|Yn*s}@BTlsYH#6Rql?cr31shVo2I8J_uGGsa>NPVT@UU?
z2mHv6tvzAX-WqfIC&GE7q}+TLh5Y@0GkAW`zf5A~CbN{b#9d^@-zCB%~F
z>hzWG8KJr%Ne*=9^~rc%5m)Rp7Sb`A%%0>mj)fb
t%O(xlhLa|FxC=jAkTs#FDbRq6fyK@;^3Lu)R-mgHJYD@<);T3K0RRGMThIUi
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Objects/Misc/nuke_core_container.rsi/core_closed.png b/Resources/Textures/Objects/Misc/nuke_core_container.rsi/core_closed.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb5dbec62e88c0f1e32662e40b9e7d4770ca9fa7
GIT binary patch
literal 461
zcmV;;0W$uHP)YHTbh(MX~H!Oqy&+4}ozjGZ=q{C54Rv3ld8cWJyl<;7(`P*}H^$o`z-E@b13M&3!Og1^@s6ZN*3@b`N^uFMSz4
zt1mQ_zLko14|_oi)-)ldzKvbf#ocY;{q^Ztt*NV}Z)3&l-f$}YCW_FIZCPM`gfYOvZ0XGeA>+
zqwSZ%tvA4irj<*@vJ|U|Yq7ciK69@huiGXc`}pz6SbmQaTm#%D%Z^7sp27&X!Q6;^
zyll`k)Ei=sb({s8&|8qEm$1C;dX
z50FlzKY;##^@RQa$)wJ)opny8i}B!Q%N(6gSN@;(^A8(yFAB_uXTSw+2((Xr!qnsrv_jE4@3X}04n$b^!@YWodJnq00000NkvXXu0mjf
DkSoxn
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Objects/Misc/nuke_core_container.rsi/core_open.png b/Resources/Textures/Objects/Misc/nuke_core_container.rsi/core_open.png
new file mode 100644
index 0000000000000000000000000000000000000000..1bda771a78c67eaae8bcef342ed816661cd43c03
GIT binary patch
literal 351
zcmeAS@N?(olHy`uVBq!ia0vp^3xHUGgAGVdtuOuxq&N#aB8wRq_>O=u<5X=vX$A&H
zK~ERQkcwMxuiNuA8A!AzD##sP>|pSaY2CcTtmcoKy30Q@@vyk{KQs(ka%_@U!o%~|
z8{SWza6!*L%I?-93!te`(6F>{W>e)ZJE!>j`Qed{j6n>SZtlAn8d24D@bUZDhTm7T
zzy4LN>J;B}w#M{l<+SI!WLq2+LK$}bSoP<~340H*g=arr*Z=>`=IZoF9`EzvlkZQ<
zU&j%g79M_QqP(~5;Tey=|Jw8C?z114m){C&q6c+^+ce&Gao#x^oUE_s^d{p^?2n+FmJZ
mckW61|EGU2!u$ZFt@bh=-1(+2=Xel1NYvBS&t;ucLK6V-LY5%_
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Objects/Misc/nuke_core_container.rsi/inhand-left.png b/Resources/Textures/Objects/Misc/nuke_core_container.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..f2c97f4374ed509ecbbdc5165896f62868213c72
GIT binary patch
literal 285
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1HB`
zi(^Q|oVT|Oxegl$uwLYR(qXsk-HIcwJsyHdPgGs%mjyjOYBNFl{oD^M3O0-!{tSnN
z8&H@UbMCf(e#?HoK9uvow%p^Vw_i(pwx{o}<#LvVObdc9+kG!$+0WP#&SX&hUi(?i
zDy9dks-wO=mH*5oFpr@{o#7#;Lj@B~=AZia)y&JkafC5g+%gY7_b)JxDIw;hA&i91JWq`arKSc)I$ztaD0e0szpZWqJSr
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Objects/Misc/nuke_core_container.rsi/inhand-right.png b/Resources/Textures/Objects/Misc/nuke_core_container.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..074c157c51cb4324a8e4625bdb30c1eb07666807
GIT binary patch
literal 293
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1H5^
zi(^Q|oVT|e`I;OAST7oV?2wsky+}vl$cu#Cn^yi0Qxh@@TbBO#&O~p9CqfK6Sse5j
zCm=H$4wj#O__?=kU)28scAv{z_UFudZYDVI^}YH(#di;gTe~DWM4fb{TP^
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Objects/Misc/nuke_core_container.rsi/meta.json b/Resources/Textures/Objects/Misc/nuke_core_container.rsi/meta.json
new file mode 100644
index 000000000000..c72162e2fdb9
--- /dev/null
+++ b/Resources/Textures/Objects/Misc/nuke_core_container.rsi/meta.json
@@ -0,0 +1,47 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/c34d56a45b0461f5e0fad3cc75e81580c3357119/icons/obj/antags/syndicate_tools.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "open"
+ },
+ {
+ "name": "closed"
+ },
+ {
+ "name": "core_open",
+ "delays": [
+ [
+ 2.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "core_closed",
+ "delays": [
+ [
+ 2.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ },
+ {
+ "name": "inhand-left",
+ "directions": 4
+ },
+ {
+ "name": "inhand-right",
+ "directions": 4
+ }
+ ]
+}
diff --git a/Resources/Textures/Objects/Misc/nuke_core_container.rsi/open.png b/Resources/Textures/Objects/Misc/nuke_core_container.rsi/open.png
new file mode 100644
index 0000000000000000000000000000000000000000..3d4b830bf4aab35ed343095b451f1e96a0d82e28
GIT binary patch
literal 330
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DEPa3
zyuLY8`%uBj_J3x_9-I+9xQb!I@02?06&Kco@)-HfWIU_LZ+y;**-$W2`$0$J6847W5}e9jH<^?ZT_V#Ce3d=*
z|KHDuEvd73chBQ*F@Lyx#}57QvF8l4^+qJ$(*89EBt2q#)|^Ofx*+&&t;ucLK6UXD1W2?
literal 0
HcmV?d00001
diff --git a/Resources/Textures/Objects/Misc/plutonium_core.rsi/icon.png b/Resources/Textures/Objects/Misc/plutonium_core.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..92782ce223cb83b31db03c95e1938143e95919dc
GIT binary patch
literal 386
zcmeAS@N?(olHy`uVBq!ia0vp^3xHUGgAGVdtuOuxq&N#aB8wRq_>O=u<5X=vX$A&H
z6Hgb%kcwMxZ#Z%_IY_i63a=L^X*)MTqNH)#+{K~R|D&Gln<9}zLSnvVOh5}|cAIJK)`3HSs_4leQX3%7Kd1vOeIgxMNAKwXM
z-O+b9CN^KZ{A1F#ng8efG4Tv8eb2s6|Kq2xkF-B2>((nrw#4?{&;I-={PTvaj>9pV
zIC7q?K6(9fdAot`t=fg6D|Gfn)h!WEj6Y`o>dDjaxdM@$InU~6)!5#D;`Jly@4c?|
z)8fSzp0q2mtlOUHey;M**Lx