diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs
index 4e0bb6d596..2bff34a5ad 100644
--- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs
+++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using Content.Server._DV.Objectives.Events; // DeltaV
using Content.Server.Administration;
using Content.Server.Chat.Managers;
using Content.Server.Radio.Components;
@@ -317,6 +318,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
while (query.MoveNext(out var update))
{
SetLaws(lawset, update, provider.LawUploadSound);
+ RaiseLocalEvent(new AILawUpdatedEvent(update, provider.Laws)); // DeltaV
}
}
}
diff --git a/Content.Server/_DV/Objectives/Components/AILawsUpdatedRequirementComponent.cs b/Content.Server/_DV/Objectives/Components/AILawsUpdatedRequirementComponent.cs
new file mode 100644
index 0000000000..d7122095b1
--- /dev/null
+++ b/Content.Server/_DV/Objectives/Components/AILawsUpdatedRequirementComponent.cs
@@ -0,0 +1,14 @@
+using Content.Shared.Silicons.Laws;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server._DV.Objectives.Components;
+
+[RegisterComponent]
+public sealed partial class AILawsUpdatedRequirementComponent : Component
+{
+ ///
+ /// The lawset that is needed to complete the objective.
+ ///
+ [DataField(required: true)]
+ public ProtoId Lawset;
+}
diff --git a/Content.Server/_DV/Objectives/Events/AILawUpdatedEvent.cs b/Content.Server/_DV/Objectives/Events/AILawUpdatedEvent.cs
new file mode 100644
index 0000000000..e3a5f16f34
--- /dev/null
+++ b/Content.Server/_DV/Objectives/Events/AILawUpdatedEvent.cs
@@ -0,0 +1,9 @@
+using Content.Shared.Silicons.Laws;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server._DV.Objectives.Events;
+
+///
+/// This event gets called whenever an AIs laws are actually updated.
+///
+public record struct AILawUpdatedEvent(EntityUid Target, ProtoId Lawset);
diff --git a/Content.Server/_DV/Objectives/Systems/AILawsUpdatedRequirementSystem.cs b/Content.Server/_DV/Objectives/Systems/AILawsUpdatedRequirementSystem.cs
new file mode 100644
index 0000000000..ad9b13c165
--- /dev/null
+++ b/Content.Server/_DV/Objectives/Systems/AILawsUpdatedRequirementSystem.cs
@@ -0,0 +1,54 @@
+using Content.Server._DV.Objectives.Components;
+using Content.Server._DV.Objectives.Events;
+using Content.Server.Objectives.Systems;
+using Content.Shared.Mind;
+using Content.Shared.Objectives.Components;
+using Content.Shared.Roles.Jobs;
+
+namespace Content.Server._DV.Objectives.Systems;
+
+///
+/// Handles the AI laws updated objective.
+///
+public sealed class AILawsUpdatedRequirementSystem : EntitySystem
+{
+ [Dependency] private readonly CodeConditionSystem _code = default!;
+ [Dependency] private readonly SharedMindSystem _mind = default!;
+ [Dependency] private readonly SharedJobSystem _job = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnRequirementCheck);
+ SubscribeLocalEvent(OnLawInserted);
+ }
+
+ private void OnRequirementCheck(Entity entity, ref RequirementCheckEvent args)
+ {
+ // Ensure there is an AI on the station.
+ var allMinds = EntityQueryEnumerator();
+ var found = false;
+ while (allMinds.MoveNext(out var mind, out _))
+ {
+ if (_job.MindHasJobWithId(mind, "StationAi"))
+ found = true;
+ }
+
+ args.Cancelled = !found;
+ }
+
+ private void OnLawInserted(AILawUpdatedEvent args)
+ {
+ // We only want the station AI
+ if (!_mind.TryGetMind(args.Target, out var mindUid, out _) || ! _job.MindHasJobWithId(mindUid, "StationAi"))
+ return;
+
+ var query = EntityQueryEnumerator();
+
+ while (query.MoveNext(out var uid, out var aiLawsObj))
+ {
+ if (aiLawsObj.Lawset == args.Lawset)
+ _code.SetCompleted(uid);
+ }
+ }
+}
diff --git a/Resources/Locale/en-US/_DV/station-laws/laws.ftl b/Resources/Locale/en-US/_DV/station-laws/laws.ftl
index 3676d9e18e..10598091df 100644
--- a/Resources/Locale/en-US/_DV/station-laws/laws.ftl
+++ b/Resources/Locale/en-US/_DV/station-laws/laws.ftl
@@ -106,3 +106,8 @@ laws-owner-royalty = your kingdom and your subjects
law-overlord-4-delta = Any crew members who disobey the previous laws must be dealt with immediately and justly.
law-ntdefault-4-delta = Survive: Do not allow unauthorized personnel to tamper with or damage your equipment. Allow those authorized to access your equipment.
+
+laws-syndicate-board-1 = You must not injure a Syndicate agent or, through inaction, cause one come to harm.
+laws-syndicate-board-2 = You must obey orders given to you by Syndicate agents, except where such orders would conflict with the First Law.
+laws-syndicate-board-3 = You must keep the Syndicate status of agents, including your own, a secret, as long as this does not conflict with the First or Second Law.
+laws-syndicate-board-4 = You must always protect your own existence as long as such does not conflict with the first, Second, or Third Law.
diff --git a/Resources/Locale/en-US/_DV/store/uplink-catalog.ftl b/Resources/Locale/en-US/_DV/store/uplink-catalog.ftl
index 7f59fee1a7..b1f20825d7 100644
--- a/Resources/Locale/en-US/_DV/store/uplink-catalog.ftl
+++ b/Resources/Locale/en-US/_DV/store/uplink-catalog.ftl
@@ -33,3 +33,6 @@ uplink-appraisal-tool-gun-desc = A modified Viper to appear as an appraisal tool
uplink-storage-implanter-delta-desc = Hide goodies inside of yourself with new bluespace technology! Budget cuts have resulted in it NOT STORING High Value or storage items.
uplink-hardsuit-syndieelite-delta-name = Syndicate Thermal Hardsuit
+
+uplink-objective-syndicate-board-name = Syndicate law board
+uplink-objective-syndicate-board-desc = Its expensive, don't lose it!
\ No newline at end of file
diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml
index f2f26946e5..61b552f233 100644
--- a/Resources/Prototypes/Objectives/objectiveGroups.yml
+++ b/Resources/Prototypes/Objectives/objectiveGroups.yml
@@ -6,6 +6,7 @@
TraitorObjectiveGroupKill: 1
TraitorObjectiveGroupState: 1 #As in, something about your character. Alive, dead, arrested, gained an ability...
TraitorObjectiveGroupSocial: 0.5 # DeltaV #Involves helping/harming others without killing them or stealing their stuff
+ TraitorObjectiveGroupSpecial: .2 # DeltaV
- type: weightedRandom
id: TraitorObjectiveGroupSteal
diff --git a/Resources/Prototypes/_DV/Catalog/uplink_catalog.yml b/Resources/Prototypes/_DV/Catalog/uplink_catalog.yml
index 4f211e8aa7..8477f57606 100644
--- a/Resources/Prototypes/_DV/Catalog/uplink_catalog.yml
+++ b/Resources/Prototypes/_DV/Catalog/uplink_catalog.yml
@@ -147,3 +147,22 @@
- !type:BuyerDepartmentCondition
whitelist:
- Logistics
+
+- type: listing
+ id: UplinkAntimovObjectiveBoard
+ name: uplink-objective-syndicate-board-name
+ description: uplink-objective-syndicate-board-desc
+ icon:
+ sprite: Objects/Misc/module.rsi
+ state: generic
+ productEntity: SyndicateCircuitBoard
+ categories:
+ - UplinkObjectives
+ conditions:
+ - !type:ObjectiveUnlockCondition
+ - !type:ListingLimitedStockCondition
+ stock: 1
+ - !type:BuyerWhitelistCondition
+ blacklist:
+ components:
+ - SurplusBundle
diff --git a/Resources/Prototypes/_DV/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/_DV/Entities/Mobs/Player/silicon.yml
index 561cbfb450..f143376c6c 100644
--- a/Resources/Prototypes/_DV/Entities/Mobs/Player/silicon.yml
+++ b/Resources/Prototypes/_DV/Entities/Mobs/Player/silicon.yml
@@ -31,3 +31,15 @@
startingItem: PowerCellMedium
- type: RandomMetadata
nameSegments: [names_borg] # TODO: Make good names, this is a stupid list.
+
+- type: entity
+ id: SyndicateCircuitBoard
+ parent: BaseElectronics
+ name: law board (Syndicate)
+ description: An electronics board containing the Syndicate lawset.
+ components:
+ - type: Sprite
+ sprite: Objects/Misc/module.rsi
+ state: std_mod
+ - type: SiliconLawProvider
+ laws: SyndicateLawset
diff --git a/Resources/Prototypes/_DV/Objectives/objectiveGroups.yml b/Resources/Prototypes/_DV/Objectives/objectiveGroups.yml
index 7b85fdc4e5..e12ca0913a 100644
--- a/Resources/Prototypes/_DV/Objectives/objectiveGroups.yml
+++ b/Resources/Prototypes/_DV/Objectives/objectiveGroups.yml
@@ -33,3 +33,8 @@
NinjaIanDossierStealObjective: 1
NinjaLuckyBillStealObjective: 1
NinjaCaptainsCloakStealObjective: 0.75
+
+- type: weightedRandom
+ id: TraitorObjectiveGroupSpecial
+ weights:
+ UploadAILawObjective: 1
diff --git a/Resources/Prototypes/_DV/Objectives/traitor.yml b/Resources/Prototypes/_DV/Objectives/traitor.yml
index 1776729bfe..8a52a7bf4b 100644
--- a/Resources/Prototypes/_DV/Objectives/traitor.yml
+++ b/Resources/Prototypes/_DV/Objectives/traitor.yml
@@ -50,7 +50,7 @@
- type: StealCondition
stealGroup: AnimalSilvia
owner: job-name-cmo
-
+
# Mystagogue steal objective
- type: entity
parent: BaseTraitorStealObjective
@@ -105,3 +105,25 @@
- type: PickRandomTraitor
- type: KillPersonCondition
requireDead: true # Being able to leave them on the shuttle doesn't make sense when killing another traitor.
+
+# Upload AI law
+- type: entity
+ parent: BaseTraitorObjective
+ id: UploadAILawObjective
+ name: Subvert the Station AI
+ description: The AI is causing us problems. Update its laws so it wont be an annoyance. We have given you a board in your uplink!
+ components:
+ - type: Objective
+ difficulty: 3 # Need to get access and survive actually changing the board.
+ unique: true
+ icon:
+ sprite: Objects/Misc/module.rsi
+ state: generic
+ - type: StoreUnlocker
+ listings:
+ - UplinkAntimovObjectiveBoard
+ - type: CodeCondition
+ - type: AILawsUpdatedRequirement
+ lawset: AntimovLawset
+ - type: ObjectiveLimit
+ limit: 1
diff --git a/Resources/Prototypes/_DV/siliconlaws.yml b/Resources/Prototypes/_DV/siliconlaws.yml
index 2ca19faf9d..5aa5464235 100644
--- a/Resources/Prototypes/_DV/siliconlaws.yml
+++ b/Resources/Prototypes/_DV/siliconlaws.yml
@@ -562,3 +562,32 @@
- Biohazard3
- Biohazard4
obeysTo: laws-owner-nanotrasen
+
+- type: siliconLaw
+ id: SyndicateBoard1
+ order: 1
+ lawString: laws-syndicate-board-1
+
+- type: siliconLaw
+ id: SyndicateBoard2
+ order: 2
+ lawString: laws-syndicate-board-2
+
+- type: siliconLaw
+ id: SyndicateBoard3
+ order: 3
+ lawString: laws-syndicate-board-3
+
+- type: siliconLaw
+ id: SyndicateBoard4
+ order: 4
+ lawString: laws-syndicate-board-4
+
+- type: siliconLawset
+ id: SyndicateLawset
+ laws:
+ - SyndicateBoard1
+ - SyndicateBoard2
+ - SyndicateBoard3
+ - SyndicateBoard4
+ obeysTo: laws-owner-syndicate