GreytideVirusRule.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. using Content.Server.StationEvents.Components;
  2. using Content.Shared.Access;
  3. using Content.Shared.Access.Systems;
  4. using Content.Shared.Access.Components;
  5. using Content.Shared.Doors.Components;
  6. using Content.Shared.Doors.Systems;
  7. using Content.Shared.Lock;
  8. using Content.Shared.GameTicking.Components;
  9. using Content.Shared.Station.Components;
  10. using Robust.Shared.Prototypes;
  11. using Robust.Shared.Random;
  12. namespace Content.Server.StationEvents.Events;
  13. /// <summary>
  14. /// Greytide Virus event
  15. /// This will open and bolt airlocks and unlock lockers from randomly selected access groups.
  16. /// </summary>
  17. public sealed class GreytideVirusRule : StationEventSystem<GreytideVirusRuleComponent>
  18. {
  19. [Dependency] private readonly AccessReaderSystem _access = default!;
  20. [Dependency] private readonly SharedDoorSystem _door = default!;
  21. [Dependency] private readonly LockSystem _lock = default!;
  22. [Dependency] private readonly IPrototypeManager _prototype = default!;
  23. [Dependency] private readonly IRobustRandom _random = default!;
  24. protected override void Added(EntityUid uid, GreytideVirusRuleComponent virusComp, GameRuleComponent gameRule, GameRuleAddedEvent args)
  25. {
  26. if (!TryComp<StationEventComponent>(uid, out var stationEvent))
  27. return;
  28. // pick severity randomly from range if not specified otherwise
  29. virusComp.Severity ??= virusComp.SeverityRange.Next(_random);
  30. virusComp.Severity = Math.Min(virusComp.Severity.Value, virusComp.AccessGroups.Count);
  31. stationEvent.StartAnnouncement = Loc.GetString("station-event-greytide-virus-start-announcement", ("severity", virusComp.Severity.Value));
  32. base.Added(uid, virusComp, gameRule, args);
  33. }
  34. protected override void Started(EntityUid uid, GreytideVirusRuleComponent virusComp, GameRuleComponent gameRule, GameRuleStartedEvent args)
  35. {
  36. base.Started(uid, virusComp, gameRule, args);
  37. if (virusComp.Severity == null)
  38. return;
  39. if (!TryGetRandomStation(out var chosenStation))
  40. return;
  41. // pick random access groups
  42. var chosen = _random.GetItems(virusComp.AccessGroups, virusComp.Severity.Value, allowDuplicates: false);
  43. // combine all the selected access groups
  44. var accessIds = new HashSet<ProtoId<AccessLevelPrototype>>();
  45. foreach (var group in chosen)
  46. {
  47. if (_prototype.TryIndex(group, out var proto))
  48. accessIds.UnionWith(proto.Tags);
  49. }
  50. var firelockQuery = GetEntityQuery<FirelockComponent>();
  51. var accessQuery = GetEntityQuery<AccessReaderComponent>();
  52. var lockQuery = AllEntityQuery<LockComponent, TransformComponent>();
  53. while (lockQuery.MoveNext(out var lockUid, out var lockComp, out var xform))
  54. {
  55. if (!accessQuery.TryComp(lockUid, out var accessComp))
  56. continue;
  57. // make sure not to hit CentCom or other maps
  58. if (CompOrNull<StationMemberComponent>(xform.GridUid)?.Station != chosenStation)
  59. continue;
  60. // check access
  61. // the AreAccessTagsAllowed function is a little weird because it technically has support for certain tags to be locked out of opening something
  62. // which might have unintened side effects (see the comments in the function itself)
  63. // but no one uses that yet, so it is fine for now
  64. if (!_access.AreAccessTagsAllowed(accessIds, accessComp) || _access.AreAccessTagsAllowed(virusComp.Blacklist, accessComp))
  65. continue;
  66. // open lockers
  67. _lock.Unlock(lockUid, null, lockComp);
  68. }
  69. var airlockQuery = AllEntityQuery<AirlockComponent, DoorComponent, TransformComponent>();
  70. while (airlockQuery.MoveNext(out var airlockUid, out var airlockComp, out var doorComp, out var xform))
  71. {
  72. // don't space everything
  73. if (firelockQuery.HasComp(airlockUid))
  74. continue;
  75. // make sure not to hit CentCom or other maps
  76. if (CompOrNull<StationMemberComponent>(xform.GridUid)?.Station != chosenStation)
  77. continue;
  78. // use the access reader from the door electronics if they exist
  79. if (!_access.GetMainAccessReader(airlockUid, out var accessEnt))
  80. continue;
  81. // check access
  82. if (!_access.AreAccessTagsAllowed(accessIds, accessEnt.Value.Comp) || _access.AreAccessTagsAllowed(virusComp.Blacklist, accessEnt.Value.Comp))
  83. continue;
  84. // open and bolt airlocks
  85. _door.TryOpenAndBolt(airlockUid, doorComp, airlockComp);
  86. }
  87. }
  88. }