]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Greytide Virus station event (#33547)
authorslarticodefast <161409025+slarticodefast@users.noreply.github.com>
Tue, 26 Nov 2024 13:50:20 +0000 (14:50 +0100)
committerGitHub <noreply@github.com>
Tue, 26 Nov 2024 13:50:20 +0000 (00:50 +1100)
* proof of concept

* full implementation

* I commited a crime

* t

* min players increase

Content.Server/StationEvents/Components/GreytideVirusComponent.cs [new file with mode: 0644]
Content.Server/StationEvents/Events/GreytideVirusRule.cs [new file with mode: 0644]
Content.Shared/Doors/Systems/SharedDoorSystem.cs
Resources/Locale/en-US/station-events/events/greytide-virus.ftl [new file with mode: 0644]
Resources/Prototypes/GameRules/events.yml

diff --git a/Content.Server/StationEvents/Components/GreytideVirusComponent.cs b/Content.Server/StationEvents/Components/GreytideVirusComponent.cs
new file mode 100644 (file)
index 0000000..307f131
--- /dev/null
@@ -0,0 +1,38 @@
+using Content.Server.StationEvents.Events;
+using Content.Shared.Access;
+using Content.Shared.Destructible.Thresholds;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.StationEvents.Components;
+
+/// <summary>
+///     Greytide Virus event specific configuration
+/// </summary>
+[RegisterComponent, Access(typeof(GreytideVirusRule))]
+public sealed partial class GreytideVirusRuleComponent : Component
+{
+    /// <summary>
+    ///     Range from which the severity is randomly picked from.
+    /// </summary>
+    [DataField]
+    public MinMax SeverityRange = new(1, 3);
+
+    /// <summary>
+    ///     Severity corresponding to the number of access groups affected.
+    ///     Will pick randomly from the SeverityRange if not specified.
+    /// </summary>
+    [DataField]
+    public int? Severity;
+
+    /// <summary>
+    ///     Access groups to pick from.
+    /// </summary>
+    [DataField]
+    public List<ProtoId<AccessGroupPrototype>> AccessGroups = new();
+
+    /// <summary>
+    ///     Entities with this access level will be ignored.
+    /// </summary>
+    [DataField]
+    public List<ProtoId<AccessLevelPrototype>> Blacklist = new();
+}
diff --git a/Content.Server/StationEvents/Events/GreytideVirusRule.cs b/Content.Server/StationEvents/Events/GreytideVirusRule.cs
new file mode 100644 (file)
index 0000000..f60d80b
--- /dev/null
@@ -0,0 +1,96 @@
+using Content.Server.StationEvents.Components;
+using Content.Shared.Access;
+using Content.Shared.Access.Systems;
+using Content.Shared.Access.Components;
+using Content.Shared.Doors.Components;
+using Content.Shared.Doors.Systems;
+using Content.Shared.Lock;
+using Content.Shared.GameTicking.Components;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Server.StationEvents.Events;
+
+
+/// <summary>
+///     Greytide Virus event
+///     This will open and bolt airlocks and unlock lockers from randomly selected access groups.
+/// </summary>
+public sealed class GreytideVirusRule : StationEventSystem<GreytideVirusRuleComponent>
+{
+    [Dependency] private readonly AccessReaderSystem _access = default!;
+    [Dependency] private readonly SharedDoorSystem _door = default!;
+    [Dependency] private readonly LockSystem _lock = default!;
+    [Dependency] private readonly IPrototypeManager _prototype = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
+
+    protected override void Added(EntityUid uid, GreytideVirusRuleComponent virusComp, GameRuleComponent gameRule, GameRuleAddedEvent args)
+    {
+        if (!TryComp<StationEventComponent>(uid, out var stationEvent))
+            return;
+
+        // pick severity randomly from range if not specified otherwise
+        virusComp.Severity ??= virusComp.SeverityRange.Next(_random);
+        virusComp.Severity = Math.Min(virusComp.Severity.Value, virusComp.AccessGroups.Count);
+
+        stationEvent.StartAnnouncement = Loc.GetString("station-event-greytide-virus-start-announcement", ("severity", virusComp.Severity.Value));
+        base.Added(uid, virusComp, gameRule, args);
+    }
+    protected override void Started(EntityUid uid, GreytideVirusRuleComponent virusComp, GameRuleComponent gameRule, GameRuleStartedEvent args)
+    {
+        base.Started(uid, virusComp, gameRule, args);
+
+        if (virusComp.Severity == null)
+            return;
+
+        // pick random access groups
+        var chosen = _random.GetItems(virusComp.AccessGroups, virusComp.Severity.Value, allowDuplicates: false);
+
+        // combine all the selected access groups
+        var accessIds = new HashSet<ProtoId<AccessLevelPrototype>>();
+        foreach (var group in chosen)
+        {
+            if (_prototype.TryIndex(group, out var proto))
+                accessIds.UnionWith(proto.Tags);
+        }
+
+        var firelockQuery = GetEntityQuery<FirelockComponent>();
+        var accessQuery = GetEntityQuery<AccessReaderComponent>();
+
+        var lockQuery = AllEntityQuery<LockComponent>();
+        while (lockQuery.MoveNext(out var lockUid, out var lockComp))
+        {
+            if (!accessQuery.TryComp(lockUid, out var accessComp))
+                continue;
+
+            // check access
+            // the AreAccessTagsAllowed function is a little weird because it technically has support for certain tags to be locked out of opening something
+            // which might have unintened side effects (see the comments in the function itself)
+            // but no one uses that yet, so it is fine for now
+            if (!_access.AreAccessTagsAllowed(accessIds, accessComp) || _access.AreAccessTagsAllowed(virusComp.Blacklist, accessComp))
+                continue;
+
+            // open lockers
+            _lock.Unlock(lockUid, null, lockComp);
+        }
+
+        var airlockQuery = AllEntityQuery<AirlockComponent, DoorComponent>();
+        while (airlockQuery.MoveNext(out var airlockUid, out var airlockComp, out var doorComp))
+        {
+            // don't space everything
+            if (firelockQuery.HasComp(airlockUid))
+                continue;
+
+            // use the access reader from the door electronics if they exist
+            if (!_access.GetMainAccessReader(airlockUid, out var accessComp))
+                continue;
+
+            // check access
+            if (!_access.AreAccessTagsAllowed(accessIds, accessComp) || _access.AreAccessTagsAllowed(virusComp.Blacklist, accessComp))
+                continue;
+
+            // open and bolt airlocks
+            _door.TryOpenAndBolt(airlockUid, doorComp, airlockComp);
+        }
+    }
+}
index 835adb31c05bae2f72ca1ff28dfc968a09b60088..69905d1bd6b6cb44142d499d1dd959680985b7ff 100644 (file)
@@ -396,6 +396,25 @@ public abstract partial class SharedDoorSystem : EntitySystem
         Dirty(uid, door);
 
     }
+
+    /// <summary>
+    /// Opens and then bolts a door.
+    /// Different from emagging this does not remove the access reader, so it can be repaired by simply unbolting the door.
+    /// </summary>
+    public bool TryOpenAndBolt(EntityUid uid, DoorComponent? door = null, AirlockComponent? airlock = null)
+    {
+        if (!Resolve(uid, ref door, ref airlock))
+            return false;
+
+        if (IsBolted(uid) || !airlock.Powered || door.State != DoorState.Closed)
+        {
+            return false;
+        }
+
+        SetState(uid, DoorState.Emagging, door);
+
+        return true;
+    }
     #endregion
 
     #region Closing
diff --git a/Resources/Locale/en-US/station-events/events/greytide-virus.ftl b/Resources/Locale/en-US/station-events/events/greytide-virus.ftl
new file mode 100644 (file)
index 0000000..7e6f5e3
--- /dev/null
@@ -0,0 +1 @@
+station-event-greytide-virus-start-announcement = Gr3y.T1d3 virus detected in the station's secure locking encryption subroutines. Severity level of { $severity }. Recommend station AI involvement.
index 08218accede474480e45607281027a809106f17a..98b6690ebb425fa0e63a668f2833b72c0eef2a3a 100644 (file)
@@ -10,6 +10,7 @@
     - id: ClericalError
     - id: CockroachMigration
     - id: GasLeak
+    - id: GreytideVirus
     - id: IonStorm # its calm like 90% of the time smh
     - id: KudzuGrowth
     - id: MassHallucinations
     maxOccurrences: 1 # this event has diminishing returns on interesting-ness, so we cap it
     weight: 5
   - type: MobReplacementRule
+
+- type: entity
+  id: GreytideVirus
+  parent: BaseStationEventShortDelay
+  components:
+  - type: StationEvent
+    startAudio:
+      path: /Audio/Announcements/attention.ogg
+    weight: 5
+    minimumPlayers: 25
+    reoccurrenceDelay: 20
+  - type: GreytideVirusRule
+    accessGroups:
+    - Cargo
+    - Command
+    - Engineering
+    - Research
+    - Security
+    - Service
+    blacklist:
+    - External # don't space everything