]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
refactor event schedulers to use explicit game rules (#29320)
authorIProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com>
Wed, 14 Aug 2024 05:21:01 +0000 (01:21 -0400)
committerGitHub <noreply@github.com>
Wed, 14 Aug 2024 05:21:01 +0000 (15:21 +1000)
* works, still has testing values, im sure I did stupid shit.

* shitvent crapfactor

* snap extra word out of existence

* shit I died of old

* remove useless inaccurate design comments

* Oopsie, handle requirement params in RandomRuleSystem too

* I'm a slash slinging hasher

* Address reviews, add admin alerts I forgor

* EntityMan saves the day

* address reviews 1

* eh, I actually don't care about the cargo gifts thing.

* started

* Do reviews

* you actually meant 1.2 lmao

* dependency inheritance is a fickle bitch

* I have no idea.

* Threads are for sheets not computers.

* fix traitor rule test

* fix round type tattling

* break things

* It worky

* Toolshed makes we want to drink depresso.

* Finished?

* remove debug values

* timings

* use defaults

* alphabetize

* bobby drop tables

* Float required fr fr

* continue

* more continence

* uno mas

* obsolution

* cleanup and documentations

* Yell at self

* use the right value defaults

* housekeeping

21 files changed:
Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs
Content.IntegrationTests/Tests/GameRules/TraitorRuleTest.cs
Content.Server/GameTicking/GameTicker.GameRule.cs
Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs
Content.Server/StationEvents/Components/BasicStationEventSchedulerComponent.cs
Content.Server/StationEvents/Components/MeteorSchedulerComponent.cs [deleted file]
Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs
Content.Server/StationEvents/EventManagerSystem.cs
Content.Server/StationEvents/MeteorSchedulerSystem.cs [deleted file]
Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs
Content.Shared/CCVar/CCVars.cs
Resources/Locale/en-US/game-ticking/game-presets/preset-allatonce.ftl
Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl
Resources/Locale/en-US/game-ticking/game-presets/preset-zombies.ftl
Resources/Prototypes/GameRules/cargo_gifts.yml
Resources/Prototypes/GameRules/events.yml
Resources/Prototypes/GameRules/meteorswarms.yml
Resources/Prototypes/GameRules/roundstart.yml
Resources/Prototypes/GameRules/unknown_shuttles.yml
Resources/Prototypes/game_presets.yml
Resources/Prototypes/secret_weights.yml

index 4708bd10c08a86b08d3ee3127e58222e53486705..c805d04a7124627adfd393836b16221e10acf1db 100644 (file)
@@ -1,10 +1,7 @@
-using Content.Server.GameTicking;
-using Content.Server.GameTicking.Commands;
+using Content.Server.GameTicking;
 using Content.Server.GameTicking.Rules;
 using Content.Server.GameTicking.Rules.Components;
-using Content.Shared.CCVar;
 using Content.Shared.GameTicking.Components;
-using Robust.Shared.Configuration;
 using Robust.Shared.GameObjects;
 using Robust.Shared.Timing;
 
@@ -27,8 +24,12 @@ namespace Content.IntegrationTests.Tests.GameRules
             var sGameTicker = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<GameTicker>();
             var sGameTiming = server.ResolveDependency<IGameTiming>();
 
-            sGameTicker.StartGameRule("MaxTimeRestart", out var ruleEntity);
-            Assert.That(entityManager.TryGetComponent<MaxTimeRestartRuleComponent>(ruleEntity, out var maxTime));
+            MaxTimeRestartRuleComponent maxTime = null;
+            await server.WaitPost(() =>
+            {
+                sGameTicker.StartGameRule("MaxTimeRestart", out var ruleEntity);
+                Assert.That(entityManager.TryGetComponent<MaxTimeRestartRuleComponent>(ruleEntity, out maxTime));
+            });
 
             Assert.That(server.EntMan.Count<GameRuleComponent>(), Is.EqualTo(1));
             Assert.That(server.EntMan.Count<ActiveGameRuleComponent>(), Is.EqualTo(1));
index 31d33ba617467f021e8ec4048c98572020030ab4..d2717521b235fbb54c0436dbd16795295ca7467f 100644 (file)
@@ -77,16 +77,17 @@ public sealed class TraitorRuleTest
         await pair.SetAntagPreference(TraitorAntagRoleName, true);
 
         // Add the game rule
-        var gameRuleEnt = ticker.AddGameRule(TraitorGameRuleProtoId);
-        Assert.That(entMan.TryGetComponent<TraitorRuleComponent>(gameRuleEnt, out var traitorRule));
-
-        // Ready up
-        ticker.ToggleReadyAll(true);
-        Assert.That(ticker.PlayerGameStatuses.Values.All(x => x == PlayerGameStatus.ReadyToPlay));
-
-        // Start the round
+        TraitorRuleComponent traitorRule = null;
         await server.WaitPost(() =>
         {
+            var gameRuleEnt = ticker.AddGameRule(TraitorGameRuleProtoId);
+            Assert.That(entMan.TryGetComponent<TraitorRuleComponent>(gameRuleEnt, out traitorRule));
+
+            // Ready up
+            ticker.ToggleReadyAll(true);
+            Assert.That(ticker.PlayerGameStatuses.Values.All(x => x == PlayerGameStatus.ReadyToPlay));
+
+            // Start the round
             ticker.StartRound();
             // Force traitor mode to start (skip the delay)
             ticker.StartGameRule(gameRuleEnt);
index c10f3023471e8a8ec455517385434489eb600338..cf0b0eceb11aa5d5584434d2fc7368c3ff50f65f 100644 (file)
@@ -9,6 +9,7 @@ using JetBrains.Annotations;
 using Robust.Shared.Console;
 using Robust.Shared.Map;
 using Robust.Shared.Prototypes;
+using Robust.Shared.Localization;
 
 namespace Content.Server.GameTicking;
 
@@ -71,6 +72,16 @@ public sealed partial class GameTicker
         var ruleEntity = Spawn(ruleId, MapCoordinates.Nullspace);
         _sawmill.Info($"Added game rule {ToPrettyString(ruleEntity)}");
         _adminLogger.Add(LogType.EventStarted, $"Added game rule {ToPrettyString(ruleEntity)}");
+        var str = Loc.GetString("station-event-system-run-event", ("eventName", ToPrettyString(ruleEntity)));
+#if DEBUG
+        _chatManager.SendAdminAlert(str);
+#else
+        if (RunLevel == GameRunLevel.InRound) // avoids telling admins the round type before it starts so that can be handled elsewhere.
+        {
+            _chatManager.SendAdminAlert(str);
+        }
+#endif
+        Log.Info(str);
 
         var ev = new GameRuleAddedEvent(ruleEntity, ruleId);
         RaiseLocalEvent(ruleEntity, ref ev, true);
index 501d9033b9c0e1a9400002249e34eac120e834f7..bdc9a47e1867222b55d4227ac4d9413f939f366a 100644 (file)
@@ -2,11 +2,12 @@ using System.Linq;
 using Content.Server.Administration;
 using Content.Server.GameTicking;
 using Content.Server.GameTicking.Rules;
-using Content.Server.GameTicking.Rules.Components;
 using Content.Server.StationEvents.Components;
 using Content.Shared.Administration;
+using Content.Shared.EntityTable;
 using Content.Shared.GameTicking.Components;
 using JetBrains.Annotations;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 using Robust.Shared.Toolshed;
 using Robust.Shared.Utility;
@@ -23,13 +24,17 @@ namespace Content.Server.StationEvents
         [Dependency] private readonly IRobustRandom _random = default!;
         [Dependency] private readonly EventManagerSystem _event = default!;
 
-        public const float MinEventTime = 60 * 3;
-        public const float MaxEventTime = 60 * 10;
+        protected override void Started(EntityUid uid, BasicStationEventSchedulerComponent component, GameRuleComponent gameRule,
+            GameRuleStartedEvent args)
+        {
+            // A little starting variance so schedulers dont all proc at once.
+            component.TimeUntilNextEvent = RobustRandom.NextFloat(component.MinimumTimeUntilFirstEvent, component.MinimumTimeUntilFirstEvent + 120);
+        }
 
         protected override void Ended(EntityUid uid, BasicStationEventSchedulerComponent component, GameRuleComponent gameRule,
             GameRuleEndedEvent args)
         {
-            component.TimeUntilNextEvent = BasicStationEventSchedulerComponent.MinimumTimeUntilFirstEvent;
+            component.TimeUntilNextEvent = component.MinimumTimeUntilFirstEvent;
         }
 
 
@@ -49,10 +54,10 @@ namespace Content.Server.StationEvents
                 if (eventScheduler.TimeUntilNextEvent > 0)
                 {
                     eventScheduler.TimeUntilNextEvent -= frameTime;
-                    return;
+                    continue;
                 }
 
-                _event.RunRandomEvent();
+                _event.RunRandomEvent(eventScheduler.ScheduledGameRules);
                 ResetTimer(eventScheduler);
             }
         }
@@ -62,7 +67,7 @@ namespace Content.Server.StationEvents
         /// </summary>
         private void ResetTimer(BasicStationEventSchedulerComponent component)
         {
-            component.TimeUntilNextEvent = _random.NextFloat(MinEventTime, MaxEventTime);
+            component.TimeUntilNextEvent = component.MinMaxEventTiming.Next(_random);
         }
     }
 
@@ -70,7 +75,8 @@ namespace Content.Server.StationEvents
     public sealed class StationEventCommand : ToolshedCommand
     {
         private EventManagerSystem? _stationEvent;
-        private BasicStationEventSchedulerSystem? _basicScheduler;
+        private EntityTableSystem? _entityTable;
+        private IComponentFactory? _compFac;
         private IRobustRandom? _random;
 
         /// <summary>
@@ -88,10 +94,11 @@ namespace Content.Server.StationEvents
         ///     to even exist) so I think it's fine.
         /// </remarks>
         [CommandImplementation("simulate")]
-        public IEnumerable<(string, float)> Simulate([CommandArgument] int rounds, [CommandArgument] int playerCount, [CommandArgument] float roundEndMean, [CommandArgument] float roundEndStdDev)
+        public IEnumerable<(string, float)> Simulate([CommandArgument] EntityPrototype eventScheduler, [CommandArgument] int rounds, [CommandArgument] int playerCount, [CommandArgument] float roundEndMean, [CommandArgument] float roundEndStdDev)
         {
             _stationEvent ??= GetSys<EventManagerSystem>();
-            _basicScheduler ??= GetSys<BasicStationEventSchedulerSystem>();
+            _entityTable ??= GetSys<EntityTableSystem>();
+            _compFac ??= IoCManager.Resolve<IComponentFactory>();
             _random ??= IoCManager.Resolve<IRobustRandom>();
 
             var occurrences = new Dictionary<string, int>();
@@ -101,6 +108,13 @@ namespace Content.Server.StationEvents
                 occurrences.Add(ev.Key.ID, 0);
             }
 
+            if (!eventScheduler.TryGetComponent<BasicStationEventSchedulerComponent>(out var basicScheduler, _compFac))
+            {
+                return occurrences.Select(p => (p.Key, (float)p.Value)).OrderByDescending(p => p.Item2);
+            }
+
+            var compMinMax = basicScheduler.MinMaxEventTiming; // we gotta do this since we cant execute on comp w/o an ent.
+
             for (var i = 0; i < rounds; i++)
             {
                 var curTime = TimeSpan.Zero;
@@ -111,9 +125,16 @@ namespace Content.Server.StationEvents
                 while (curTime.TotalSeconds < randomEndTime)
                 {
                     // sim an event
-                    curTime += TimeSpan.FromSeconds(_random.NextFloat(BasicStationEventSchedulerSystem.MinEventTime, BasicStationEventSchedulerSystem.MaxEventTime));
+                    curTime += TimeSpan.FromSeconds(compMinMax.Next(_random));
+
+                    if (!_stationEvent.TryBuildLimitedEvents(basicScheduler.ScheduledGameRules, out var selectedEvents))
+                    {
+                        continue; // doesnt break because maybe the time is preventing events being available.
+                    }
                     var available = _stationEvent.AvailableEvents(false, playerCount, curTime);
-                    var ev = _stationEvent.FindEvent(available);
+                    var plausibleEvents = new Dictionary<EntityPrototype, StationEventComponent>(available.Intersect(selectedEvents)); // C# makes me sad
+
+                    var ev = _stationEvent.FindEvent(plausibleEvents);
                     if (ev == null)
                         continue;
 
@@ -125,26 +146,40 @@ namespace Content.Server.StationEvents
         }
 
         [CommandImplementation("lsprob")]
-        public IEnumerable<(string, float)> LsProb()
+        public IEnumerable<(string, float)> LsProb([CommandArgument] EntityPrototype eventScheduler)
         {
+            _compFac ??= IoCManager.Resolve<IComponentFactory>();
             _stationEvent ??= GetSys<EventManagerSystem>();
-            var events = _stationEvent.AllEvents();
 
-            var totalWeight = events.Sum(x => x.Value.Weight);
+            if (!eventScheduler.TryGetComponent<BasicStationEventSchedulerComponent>(out var basicScheduler, _compFac))
+                yield break;
 
-            foreach (var (proto, comp) in events)
+            if (!_stationEvent.TryBuildLimitedEvents(basicScheduler.ScheduledGameRules, out var events))
+                yield break;
+
+            var totalWeight = events.Sum(x => x.Value.Weight); // Well this shit definitely isnt correct now, and I see no way to make it correct.
+                                                               // Its probably *fine* but it wont be accurate if the EntityTableSelector does any subsetting.
+            foreach (var (proto, comp) in events)              // The only solution I see is to do a simulation, and we already have that, so...!
             {
                 yield return (proto.ID, comp.Weight / totalWeight);
             }
         }
 
         [CommandImplementation("lsprobtime")]
-        public IEnumerable<(string, float)> LsProbTime([CommandArgument] float time)
+        public IEnumerable<(string, float)> LsProbTime([CommandArgument] EntityPrototype eventScheduler, [CommandArgument] float time)
         {
+            _compFac ??= IoCManager.Resolve<IComponentFactory>();
             _stationEvent ??= GetSys<EventManagerSystem>();
-            var events = _stationEvent.AllEvents().Where(pair => pair.Value.EarliestStart <= time).ToList();
 
-            var totalWeight = events.Sum(x => x.Value.Weight);
+            if (!eventScheduler.TryGetComponent<BasicStationEventSchedulerComponent>(out var basicScheduler, _compFac))
+                yield break;
+
+            if (!_stationEvent.TryBuildLimitedEvents(basicScheduler.ScheduledGameRules, out var untimedEvents))
+                yield break;
+
+            var events = untimedEvents.Where(pair => pair.Value.EarliestStart <= time).ToList();
+
+            var totalWeight = events.Sum(x => x.Value.Weight); // same subsetting issue as lsprob.
 
             foreach (var (proto, comp) in events)
             {
@@ -153,12 +188,18 @@ namespace Content.Server.StationEvents
         }
 
         [CommandImplementation("prob")]
-        public float Prob([CommandArgument] string eventId)
+        public float Prob([CommandArgument] EntityPrototype eventScheduler, [CommandArgument] string eventId)
         {
+            _compFac ??= IoCManager.Resolve<IComponentFactory>();
             _stationEvent ??= GetSys<EventManagerSystem>();
-            var events = _stationEvent.AllEvents();
 
-            var totalWeight = events.Sum(x => x.Value.Weight);
+            if (!eventScheduler.TryGetComponent<BasicStationEventSchedulerComponent>(out var basicScheduler, _compFac))
+                return 0f;
+
+            if (!_stationEvent.TryBuildLimitedEvents(basicScheduler.ScheduledGameRules, out var events))
+                return 0f;
+
+            var totalWeight = events.Sum(x => x.Value.Weight); // same subsetting issue as lsprob.
             var weight = 0f;
             if (events.TryFirstOrNull(p => p.Key.ID == eventId, out var pair))
             {
index a6ea139f04e7d27c235fc173ed162c8ee6165697..b777831856b2bd5eaaa9a4e01a5b29b388ac83b7 100644 (file)
@@ -1,14 +1,35 @@
-namespace Content.Server.StationEvents.Components;
+using Content.Shared.Destructible.Thresholds;
+using Content.Shared.EntityTable.EntitySelectors;
+
+
+namespace Content.Server.StationEvents.Components;
 
 [RegisterComponent, Access(typeof(BasicStationEventSchedulerSystem))]
 public sealed partial class BasicStationEventSchedulerComponent : Component
 {
-    public const float MinimumTimeUntilFirstEvent = 300;
+    /// <summary>
+    /// How long the the scheduler waits to begin starting rules.
+    /// </summary>
+    [DataField]
+    public float MinimumTimeUntilFirstEvent = 200;
+
+    /// <summary>
+    /// The minimum and maximum time between rule starts in seconds.
+    /// </summary>
+    [DataField]
+    public MinMax MinMaxEventTiming = new(3 * 60, 10 * 60);
+
+    /// <summary>
+    /// How long until the next check for an event runs, is initially set based on MinimumTimeUntilFirstEvent & MinMaxEventTiming.
+    /// </summary>
+    [DataField]
+    public float TimeUntilNextEvent;
 
     /// <summary>
-    /// How long until the next check for an event runs
+    /// The gamerules that the scheduler can choose from
     /// </summary>
-    /// Default value is how long until first event is allowed
-    [ViewVariables(VVAccess.ReadWrite)]
-    public float TimeUntilNextEvent = MinimumTimeUntilFirstEvent;
+    /// Reminder that though we could do all selection via the EntityTableSelector, we also need to consider various <see cref="StationEventComponent"/> restrictions.
+    /// As such, we want to pass a list of acceptable game rules, which are then parsed for restrictions by the <see cref="EventManagerSystem"/>.
+    [DataField(required: true)]
+    public EntityTableSelector ScheduledGameRules = default!;
 }
diff --git a/Content.Server/StationEvents/Components/MeteorSchedulerComponent.cs b/Content.Server/StationEvents/Components/MeteorSchedulerComponent.cs
deleted file mode 100644 (file)
index 23337f9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-using Content.Shared.Random;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.StationEvents.Components;
-
-/// <summary>
-/// This is used for running meteor swarm events at regular intervals.
-/// </summary>
-[RegisterComponent, Access(typeof(MeteorSchedulerSystem)), AutoGenerateComponentPause]
-public sealed partial class MeteorSchedulerComponent : Component
-{
-    /// <summary>
-    /// The weights for which swarms will be selected.
-    /// </summary>
-    [DataField]
-    public ProtoId<WeightedRandomEntityPrototype> Config = "DefaultConfig";
-
-    /// <summary>
-    /// The time at which the next swarm occurs.
-    /// </summary>
-    [DataField, AutoPausedField]
-    public TimeSpan NextSwarmTime = TimeSpan.Zero;
-
-}
index 53bc8b62a43849606477e7b4d9412a59325eeda2..8bf433144c7f9cc243962078954aea545da672d7 100644 (file)
@@ -1,17 +1,41 @@
-namespace Content.Server.StationEvents.Components;
+using Content.Shared.EntityTable.EntitySelectors;
+
+namespace Content.Server.StationEvents.Components;
 
 [RegisterComponent, Access(typeof(RampingStationEventSchedulerSystem))]
 public sealed partial class RampingStationEventSchedulerComponent : Component
 {
-    [DataField("endTime"), ViewVariables(VVAccess.ReadWrite)]
+    /// <summary>
+    ///     Average ending chaos modifier for the ramping event scheduler. Higher means faster.
+    ///     Max chaos chosen for a round will deviate from this
+    /// </summary>
+    [DataField]
+    public float AverageChaos = 6f;
+
+    /// <summary>
+    ///     Average time (in minutes) for when the ramping event scheduler should stop increasing the chaos modifier.
+    ///     Close to how long you expect a round to last, so you'll probably have to tweak this on downstreams.
+    /// </summary>
+    [DataField]
+    public float AverageEndTime = 40f;
+
+    [DataField]
     public float EndTime;
 
-    [DataField("maxChaos"), ViewVariables(VVAccess.ReadWrite)]
+    [DataField]
     public float MaxChaos;
 
-    [DataField("startingChaos"), ViewVariables(VVAccess.ReadWrite)]
+    [DataField]
     public float StartingChaos;
 
-    [DataField("timeUntilNextEvent"), ViewVariables(VVAccess.ReadWrite)]
+    [DataField]
     public float TimeUntilNextEvent;
+
+    /// <summary>
+    /// The gamerules that the scheduler can choose from
+    /// </summary>
+    /// Reminder that though we could do all selection via the EntityTableSelector, we also need to consider various <see cref="StationEventComponent"/> restrictions.
+    /// As such, we want to pass a list of acceptable game rules, which are then parsed for restrictions by the <see cref="EventManagerSystem"/>.
+    [DataField(required: true)]
+    public EntityTableSelector ScheduledGameRules = default!;
 }
index 2e44040fcc8bf7b7b447aad399e5afcdf72f9ea5..bc6b1834002dd44031316615d1c54aed68e5c40d 100644 (file)
@@ -1,5 +1,4 @@
 using System.Linq;
-using Content.Server.Chat.Managers;
 using Content.Server.GameTicking;
 using Content.Server.RoundEnd;
 using Content.Server.StationEvents.Components;
@@ -8,6 +7,8 @@ using Robust.Server.Player;
 using Robust.Shared.Configuration;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
+using Content.Shared.EntityTable.EntitySelectors;
+using Content.Shared.EntityTable;
 
 namespace Content.Server.StationEvents;
 
@@ -17,7 +18,7 @@ public sealed class EventManagerSystem : EntitySystem
     [Dependency] private readonly IPlayerManager _playerManager = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly IPrototypeManager _prototype = default!;
-    [Dependency] private readonly IChatManager _chat = default!;
+    [Dependency] private readonly EntityTableSystem _entityTable = default!;
     [Dependency] public readonly GameTicker GameTicker = default!;
     [Dependency] private readonly RoundEndSystem _roundEnd = default!;
 
@@ -34,7 +35,8 @@ public sealed class EventManagerSystem : EntitySystem
     /// <summary>
     /// Randomly runs a valid event.
     /// </summary>
-    public string RunRandomEvent()
+    [Obsolete("use overload taking EnityTableSelector instead or risk unexpected results")]
+    public void RunRandomEvent()
     {
         var randomEvent = PickRandomEvent();
 
@@ -42,14 +44,86 @@ public sealed class EventManagerSystem : EntitySystem
         {
             var errStr = Loc.GetString("station-event-system-run-random-event-no-valid-events");
             Log.Error(errStr);
-            return errStr;
+            return;
         }
 
-        var ent = GameTicker.AddGameRule(randomEvent);
-        var str = Loc.GetString("station-event-system-run-event",("eventName", ToPrettyString(ent)));
-        _chat.SendAdminAlert(str);
-        Log.Info(str);
-        return str;
+        GameTicker.AddGameRule(randomEvent);
+    }
+
+    /// <summary>
+    /// Randomly runs an event from provided EntityTableSelector.
+    /// </summary>
+    public void RunRandomEvent(EntityTableSelector limitedEventsTable)
+    {
+        if (!TryBuildLimitedEvents(limitedEventsTable, out var limitedEvents))
+        {
+            Log.Warning("Provided event table could not build dict!");
+            return;
+        }
+
+        var randomLimitedEvent = FindEvent(limitedEvents); // this picks the event, It might be better to use the GetSpawns to do it, but that will be a major rebalancing fuck.
+        if (randomLimitedEvent == null)
+        {
+            Log.Warning("The selected random event is null!");
+            return;
+        }
+
+        if (!_prototype.TryIndex(randomLimitedEvent, out _))
+        {
+            Log.Warning("A requested event is not available!");
+            return;
+        }
+
+        GameTicker.AddGameRule(randomLimitedEvent);
+    }
+
+    /// <summary>
+    /// Returns true if the provided EntityTableSelector gives at least one prototype with a StationEvent comp.
+    /// </summary>
+    public bool TryBuildLimitedEvents(EntityTableSelector limitedEventsTable, out Dictionary<EntityPrototype, StationEventComponent> limitedEvents)
+    {
+        limitedEvents = new Dictionary<EntityPrototype, StationEventComponent>();
+
+        var availableEvents = AvailableEvents(); // handles the player counts and individual event restrictions
+
+        if (availableEvents.Count == 0)
+        {
+            Log.Warning("No events were available to run!");
+            return false;
+        }
+
+        var selectedEvents = _entityTable.GetSpawns(limitedEventsTable);
+
+        if (selectedEvents.Any() != true) // This is here so if you fuck up the table it wont die.
+            return false;
+
+        foreach (var eventid in selectedEvents)
+        {
+            if (!_prototype.TryIndex(eventid, out var eventproto))
+            {
+                Log.Warning("An event ID has no prototype index!");
+                continue;
+            }
+
+            if (limitedEvents.ContainsKey(eventproto)) // This stops it from dying if you add duplicate entries in a fucked table
+                continue;
+
+            if (eventproto.Abstract)
+                continue;
+
+            if (!eventproto.TryGetComponent<StationEventComponent>(out var stationEvent, EntityManager.ComponentFactory))
+                continue;
+
+            if (!availableEvents.ContainsKey(eventproto))
+                continue;
+
+            limitedEvents.Add(eventproto, stationEvent);
+        }
+
+        if (!limitedEvents.Any())
+            return false;
+
+        return true;
     }
 
     /// <summary>
diff --git a/Content.Server/StationEvents/MeteorSchedulerSystem.cs b/Content.Server/StationEvents/MeteorSchedulerSystem.cs
deleted file mode 100644 (file)
index c516229..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-using Content.Server.GameTicking.Rules;
-using Content.Server.StationEvents.Components;
-using Content.Shared.CCVar;
-using Content.Shared.GameTicking.Components;
-using Content.Shared.Random.Helpers;
-using Robust.Shared.Configuration;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.StationEvents;
-
-/// <summary>
-/// This handles scheduling and launching meteors at a station at regular intervals.
-/// TODO: there is 100% a world in which this is genericized and can be used for lots of basic event scheduling
-/// </summary>
-public sealed class MeteorSchedulerSystem : GameRuleSystem<MeteorSchedulerComponent>
-{
-    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
-    [Dependency] private readonly IConfigurationManager _cfg = default!;
-
-    private TimeSpan _meteorMinDelay;
-    private TimeSpan _meteorMaxDelay;
-
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        _cfg.OnValueChanged(CCVars.MeteorSwarmMinTime, f => { _meteorMinDelay = TimeSpan.FromMinutes(f); }, true);
-        _cfg.OnValueChanged(CCVars.MeteorSwarmMaxTime, f => { _meteorMaxDelay = TimeSpan.FromMinutes(f); }, true);
-    }
-
-    protected override void Started(EntityUid uid, MeteorSchedulerComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
-    {
-        base.Started(uid, component, gameRule, args);
-
-        component.NextSwarmTime = Timing.CurTime + RobustRandom.Next(_meteorMinDelay, _meteorMaxDelay);
-    }
-
-    protected override void ActiveTick(EntityUid uid, MeteorSchedulerComponent component, GameRuleComponent gameRule, float frameTime)
-    {
-        base.ActiveTick(uid, component, gameRule, frameTime);
-
-        if (Timing.CurTime < component.NextSwarmTime)
-            return;
-        RunSwarm((uid, component));
-
-        component.NextSwarmTime += RobustRandom.Next(_meteorMinDelay, _meteorMaxDelay);
-    }
-
-    private void RunSwarm(Entity<MeteorSchedulerComponent> ent)
-    {
-        var swarmWeights = _prototypeManager.Index(ent.Comp.Config);
-        GameTicker.StartGameRule(swarmWeights.Pick(RobustRandom));
-    }
-}
index f65105de0669c8305a1c72af67c79cbf36c8d0f3..a5dbe102ca133ffa1dba88b61d970f800f3e897d 100644 (file)
@@ -1,22 +1,20 @@
-using Content.Server.GameTicking;
+using Content.Server.GameTicking;
 using Content.Server.GameTicking.Rules;
-using Content.Server.GameTicking.Rules.Components;
 using Content.Server.StationEvents.Components;
-using Content.Server.StationEvents.Events;
-using Content.Shared.CCVar;
 using Content.Shared.GameTicking.Components;
-using Robust.Shared.Configuration;
 using Robust.Shared.Random;
 
 namespace Content.Server.StationEvents;
 
 public sealed class RampingStationEventSchedulerSystem : GameRuleSystem<RampingStationEventSchedulerComponent>
 {
-    [Dependency] private readonly IConfigurationManager _cfg = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly EventManagerSystem _event = default!;
     [Dependency] private readonly GameTicker _gameTicker = default!;
 
+    /// <summary>
+    /// Returns the ChaosModifier which increases as round time increases to a point.
+    /// </summary>
     public float GetChaosModifier(EntityUid uid, RampingStationEventSchedulerComponent component)
     {
         var roundTime = (float) _gameTicker.RoundDuration().TotalSeconds;
@@ -30,14 +28,11 @@ public sealed class RampingStationEventSchedulerSystem : GameRuleSystem<RampingS
     {
         base.Started(uid, component, gameRule, args);
 
-        var avgChaos = _cfg.GetCVar(CCVars.EventsRampingAverageChaos);
-        var avgTime = _cfg.GetCVar(CCVars.EventsRampingAverageEndTime);
-
         // Worlds shittiest probability distribution
         // Got a complaint? Send them to
-        component.MaxChaos = _random.NextFloat(avgChaos - avgChaos / 4, avgChaos + avgChaos / 4);
+        component.MaxChaos = _random.NextFloat(component.AverageChaos - component.AverageChaos / 4, component.AverageChaos + component.AverageChaos / 4);
         // This is in minutes, so *60 for seconds (for the chaos calc)
-        component.EndTime = _random.NextFloat(avgTime - avgTime / 4, avgTime + avgTime / 4) * 60f;
+        component.EndTime = _random.NextFloat(component.AverageEndTime - component.AverageEndTime / 4, component.AverageEndTime + component.AverageEndTime / 4) * 60f;
         component.StartingChaos = component.MaxChaos / 10;
 
         PickNextEventTime(uid, component);
@@ -54,19 +49,22 @@ public sealed class RampingStationEventSchedulerSystem : GameRuleSystem<RampingS
         while (query.MoveNext(out var uid, out var scheduler, out var gameRule))
         {
             if (!GameTicker.IsGameRuleActive(uid, gameRule))
-                return;
+                continue;
 
             if (scheduler.TimeUntilNextEvent > 0f)
             {
                 scheduler.TimeUntilNextEvent -= frameTime;
-                return;
+                continue;
             }
 
             PickNextEventTime(uid, scheduler);
-            _event.RunRandomEvent();
+            _event.RunRandomEvent(scheduler.ScheduledGameRules);
         }
     }
 
+    /// <summary>
+    /// Sets the timing of the next event addition.
+    /// </summary>
     private void PickNextEventTime(EntityUid uid, RampingStationEventSchedulerComponent component)
     {
         var mod = GetChaosModifier(uid, component);
index 5ed13baf364805664d2d7e6d214e8c81b14bd48a..3e9963c833f893d36d5517a2998ef80cf4e5887a 100644 (file)
@@ -110,32 +110,6 @@ namespace Content.Shared.CCVar
         public static readonly CVarDef<bool>
             EventsEnabled = CVarDef.Create("events.enabled", true, CVar.ARCHIVE | CVar.SERVERONLY);
 
-        /// <summary>
-        ///     Average time (in minutes) for when the ramping event scheduler should stop increasing the chaos modifier.
-        ///     Close to how long you expect a round to last, so you'll probably have to tweak this on downstreams.
-        /// </summary>
-        public static readonly CVarDef<float>
-            EventsRampingAverageEndTime = CVarDef.Create("events.ramping_average_end_time", 40f, CVar.ARCHIVE | CVar.SERVERONLY);
-
-        /// <summary>
-        ///     Average ending chaos modifier for the ramping event scheduler.
-        ///     Max chaos chosen for a round will deviate from this
-        /// </summary>
-        public static readonly CVarDef<float>
-            EventsRampingAverageChaos = CVarDef.Create("events.ramping_average_chaos", 6f, CVar.ARCHIVE | CVar.SERVERONLY);
-
-        /// <summary>
-        ///     Minimum time between meteor swarms in minutes.
-        /// </summary>
-        public static readonly CVarDef<float>
-            MeteorSwarmMinTime = CVarDef.Create("events.meteor_swarm_min_time", 12.5f, CVar.ARCHIVE | CVar.SERVERONLY);
-
-        /// <summary>
-        ///     Maximum time between meteor swarms in minutes.
-        /// </summary>
-        public static readonly CVarDef<float>
-            MeteorSwarmMaxTime = CVarDef.Create("events.meteor_swarm_max_time", 17.5f, CVar.ARCHIVE | CVar.SERVERONLY);
-
         /*
          * Game
          */
index 3452b2faa96925e50a670710116466f19bd6db1e..ba4f62c4ca0a133f247041c4c27a1423f201a69c 100644 (file)
@@ -1,2 +1,5 @@
 all-at-once-title = All at once
 all-at-once-description = It's just not your day...
+
+aller-at-once-title = Aller at once
+aller-at-once-description = You have fucked up now. You *have* fucked up now.
\ No newline at end of file
index 231733eabfb433a1990125b88fbd44c32842fa98..492bb9e34105c6540e1d1474f243ea8dedec7cec 100644 (file)
@@ -1,2 +1,5 @@
 survival-title = Survival
 survival-description = No internal threats, but how long can the station survive increasingly chaotic and frequent events?
+
+kessler-syndrome-title = Kessler Syndrome
+kessler-syndrome-description = No internal threats, but the station is quickly falling into a belt of meteors!
\ No newline at end of file
index efb5c6ef1e198fd81eedae01578b9ddbdceda31d..4d127d9fa535195328b8e1ce7d46adf25af7f113 100644 (file)
@@ -1,6 +1,9 @@
 zombie-title = Zombies
 zombie-description = The undead have been unleashed on the station! Work with the crew to survive the outbreak and secure the station.
 
+zombieteors-title = Zombieteors
+zombieteors-description = The undead have been unleashed on the station amid a cataclysmic meteor shower! Work with your fellow crew and do your best to survive!
+
 zombie-not-enough-ready-players = Not enough players readied up for the game! There were {$readyPlayersCount} players readied up out of {$minimumPlayers} needed. Can't start Zombies.
 zombie-no-one-ready = No players readied up! Can't start Zombies.
 
index ffc2ed404b703e4f3800603f1e10bb57af515b2a..f4e4a5bf8fc603280c64519a490aa2aa702a89fb 100644 (file)
@@ -1,3 +1,22 @@
+# Tables --  Add your new event to this Table if you want it to happen via the basic/ramping schedulers.
+
+- type: entityTable
+  id: CargoGiftsTable
+  table: !type:GroupSelector # ~~we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp~~ But we arent doing that shit yet, it picks a random one StationEventComp be damned.
+    children:
+    - id: GiftsEngineering
+    - id: GiftsFireProtection
+    - id: GiftsJanitor
+    - id: GiftsMedical
+    - id: GiftsPizzaPartyLarge
+    - id: GiftsPizzaPartySmall
+    - id: GiftsSecurityGuns
+    - id: GiftsSecurityRiot
+    - id: GiftsSpacingSupplies
+    - id: GiftsVendingRestock
+
+# Game Rules
+    
 - type: entity
   id: CargoGiftsBase
   parent: BaseGameRule
index fe9d6410d042c6776ce384888c7c470649a8ee27..56ffeda7f035c3c8b546bfd374c0567ed2010f1b 100644 (file)
@@ -1,3 +1,40 @@
+- type: entityTable
+  id: BasicCalmEventsTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - id: AnomalySpawn
+    - id: BluespaceArtifact
+    - id: BluespaceLocker
+    - id: BreakerFlip
+    - id: BureaucraticError
+    - id: ClericalError
+    - id: CockroachMigration
+    - id: GasLeak
+    - id: IonStorm # its calm like 90% of the time smh
+    - id: KudzuGrowth
+    - id: MassHallucinations
+    - id: MimicVendorRule
+    - id: MouseMigration
+    - id: PowerGridCheck
+    - id: SlimesSpawn
+    - id: SolarFlare
+    - id: SpiderClownSpawn
+    - id: SpiderSpawn
+    - id: VentClog
+
+- type: entityTable
+  id: BasicAntagEventsTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - id: ClosetSkeleton
+    - id: DragonSpawn
+    - id: KingRatMigration
+    - id: NinjaSpawn
+    - id: RevenantSpawn
+    - id: SleeperAgents
+    - id: ZombieOutbreak
+
+
 - type: entity
   id: BaseStationEvent
   parent: BaseGameRule
     sounds:
       collection: Paracusia
 
-- type: entity
-  id: ImmovableRodSpawn
-  parent: BaseGameRule
-  components:
-  - type: StationEvent
-    startAnnouncement: station-event-immovable-rod-start-announcement
-    startAudio:
-      path: /Audio/Announcements/attention.ogg
-    weight: 3.5
-    duration: 1
-    earliestStart: 30
-    minimumPlayers: 20
-  - type: ImmovableRodRule
-    rodPrototypes:
-    - id: ImmovableRodKeepTilesStill
-      prob: 0.95
-      orGroup: rodProto
-    - id: ImmovableRodMop
-      prob: 0.0072
-      orGroup: rodProto
-    - id: ImmovableRodShark
-      prob: 0.0072
-      orGroup: rodProto
-    - id: ImmovableRodClown
-      prob: 0.0072
-      orGroup: rodProto
-    - id: ImmovableRodBanana
-      prob: 0.0072
-      orGroup: rodProto
-    - id: ImmovableRodHammer
-      prob: 0.0072
-      orGroup: rodProto
-    - id: ImmovableRodThrongler
-      prob: 0.0072
-      orGroup: rodProto
-    - id: ImmovableRodGibstick
-      prob: 0.0072
-      orGroup: rodProto
-
 - type: entity
   parent: BaseGameRule
   id: IonStorm
index 2f1cb4eba5ed90c766faadcc553eae945365cd96..d69fd9700b93bac73865aea0de5835cb332dc177 100644 (file)
@@ -1,21 +1,39 @@
-- type: entity
-  parent: BaseGameRule
-  id: GameRuleMeteorScheduler
-  components:
-  - type: GameRule
-    minPlayers: 25
-    cancelPresetOnTooFewPlayers: false
-  - type: MeteorScheduler
+# Event Tables
 
-- type: weightedRandomEntity
-  id: DefaultConfig
-  weights:
-    GameRuleSpaceDustMinor: 44
-    GameRuleSpaceDustMajor: 22
-    GameRuleMeteorSwarmSmall: 18
-    GameRuleMeteorSwarmMedium: 10
-    GameRuleMeteorSwarmLarge: 5
-    GameRuleUristSwarm: 0.05
+- type: entityTable
+  id: MeteorSwarmDustEventsTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - id: GameRuleSpaceDustMinor
+    - id: GameRuleSpaceDustMajor
+
+- type: entityTable
+  id: MeteorSwarmSmallChanceEventsTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - id: GameRuleMeteorSwarmSmall
+      prob: 0.15
+
+- type: entityTable
+  id: MeteorSwarmMildTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - !type:NestedSelector
+        tableId: MeteorSwarmDustEventsTable
+    - !type:NestedSelector
+        tableId: MeteorSwarmSmallChanceEventsTable
+
+- type: entityTable
+  id: BasicMeteorSwarmEventsTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - !type:NestedSelector
+        tableId: MeteorSwarmDustEventsTable
+    - id: GameRuleMeteorSwarmSmall
+    - id: GameRuleMeteorSwarmMedium
+    - id: GameRuleMeteorSwarmLarge
+    - id: GameRuleUristSwarm
+    - id: ImmovableRodSpawn
 
 - type: weightedRandomEntity
   id: MeteorSpawnAsteroidWallTable
     AsteroidRockPlasma: 2
     AsteroidRockDiamond: 2
     AsteroidRockUranium: 0.5
-    AsteroidRockBananium: 0.5      
+    AsteroidRockBananium: 0.5
+
+# Event Schedulers
+
+- type: entity
+  parent: BaseGameRule
+  id: MeteorSwarmScheduler
+  components:
+  - type: GameRule
+  - type: BasicStationEventScheduler
+    minimumTimeUntilFirstEvent: 300 # 5 min
+    minMaxEventTiming:
+      min: 750 # 12.5 min
+      max: 930 # 17.5 min
+    scheduledGameRules: !type:NestedSelector
+      tableId: BasicMeteorSwarmEventsTable
+
+- type: entity
+  parent: BaseGameRule
+  id: MeteorSwarmMildScheduler
+  components:
+  - type: GameRule
+  - type: BasicStationEventScheduler
+    minimumTimeUntilFirstEvent: 300 # 5 min 
+    minMaxEventTiming:
+      min: 750 # 12.5 min
+      max: 930 # 17.5 min
+    scheduledGameRules: !type:NestedSelector
+      tableId: MeteorSwarmMildTable
+
+- type: entity
+  parent: BaseGameRule
+  id: KesslerSyndromeScheduler
+  components:
+  - type: GameRule
+  - type: RampingStationEventScheduler
+    scheduledGameRules: !type:NestedSelector
+      tableId: BasicMeteorSwarmEventsTable
+
+# Game Rules
 
 - type: entity
   parent: BaseGameRule
   abstract: true
   components:
   - type: GameRule
+  - type: StationEvent
+    earliestStart: 12
+    minimumPlayers: 25
   - type: MeteorSwarm
 
 - type: entity
   parent: GameRuleMeteorSwarm
   id: GameRuleSpaceDustMinor
   components:
+  - type: StationEvent
+    weight: 44
+    earliestStart: 2
+    minimumPlayers: 0
   - type: MeteorSwarm
     announcement: null
     announcementSound: null
   parent: GameRuleMeteorSwarm
   id: GameRuleSpaceDustMajor
   components:
+  - type: StationEvent
+    weight: 22
+    minimumPlayers: 0
   - type: MeteorSwarm
     announcement: station-event-space-dust-start-announcement
     announcementSound: /Audio/Announcements/attention.ogg
   parent: GameRuleMeteorSwarm
   id: GameRuleMeteorSwarmSmall
   components:
+  - type: StationEvent
+    weight: 18
+    minimumPlayers: 15
   - type: MeteorSwarm
     meteors:
       MeteorSmall: 7
   parent: GameRuleMeteorSwarm
   id: GameRuleMeteorSwarmMedium
   components:
+  - type: StationEvent
+    weight: 10
   - type: MeteorSwarm
     meteors:
       MeteorSmall: 3
   parent: GameRuleMeteorSwarm
   id: GameRuleMeteorSwarmLarge
   components:
+  - type: StationEvent
+    weight: 5
   - type: MeteorSwarm
     meteors:
       MeteorSmall: 2
   parent: GameRuleMeteorSwarm
   id: GameRuleUristSwarm
   components:
+  - type: StationEvent
+    weight: 0.05
   - type: MeteorSwarm
     announcement: station-event-meteor-urist-start-announcement
     announcementSound: /Audio/Announcements/attention.ogg
     meteorsPerWave:
       min: 10
       max: 10
+
+- type: entity
+  id: ImmovableRodSpawn
+  parent: BaseGameRule
+  components:
+  - type: StationEvent
+    startAnnouncement: station-event-immovable-rod-start-announcement
+    startAudio:
+      path: /Audio/Announcements/attention.ogg
+    weight: 3.5
+    duration: 1
+    earliestStart: 30
+    minimumPlayers: 25
+  - type: ImmovableRodRule
+    rodPrototypes:
+    - id: ImmovableRodKeepTilesStill
+      prob: 0.95
+      orGroup: rodProto
+    - id: ImmovableRodMop
+      prob: 0.0072
+      orGroup: rodProto
+    - id: ImmovableRodShark
+      prob: 0.0072
+      orGroup: rodProto
+    - id: ImmovableRodClown
+      prob: 0.0072
+      orGroup: rodProto
+    - id: ImmovableRodBanana
+      prob: 0.0072
+      orGroup: rodProto
+    - id: ImmovableRodHammer
+      prob: 0.0072
+      orGroup: rodProto
+    - id: ImmovableRodThrongler
+      prob: 0.0072
+      orGroup: rodProto
+    - id: ImmovableRodGibstick
+      prob: 0.0072
+      orGroup: rodProto
index a10a6c8d2a6f1ed3495d74f96214e1ebb4a24689..8ef0db965827d1859075435b77f081043e7f0dcf 100644 (file)
         prototype: InitialInfected
 
 # event schedulers
+
+- type: entityTable
+  id: BasicGameRulesTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+      - !type:NestedSelector
+        tableId: BasicCalmEventsTable
+      - !type:NestedSelector
+        tableId: BasicAntagEventsTable
+      - !type:NestedSelector
+        tableId: CargoGiftsTable
+
+- type: entityTable
+  id: SpaceTrafficControlTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+      - !type:NestedSelector
+        tableId: UnknownShuttlesFriendlyTable
+      - !type:NestedSelector
+        tableId: UnknownShuttlesFreelanceTable
+      - !type:NestedSelector
+        tableId: UnknownShuttlesHostileTable
+
 - type: entity
   id: BasicStationEventScheduler
   parent: BaseGameRule
   components:
   - type: BasicStationEventScheduler
+    scheduledGameRules: !type:NestedSelector
+      tableId: BasicGameRulesTable
 
 - type: entity
   id: RampingStationEventScheduler
   parent: BaseGameRule
   components:
   - type: RampingStationEventScheduler
+    scheduledGameRules: !type:NestedSelector
+      tableId: BasicGameRulesTable
+
+- type: entity
+  id: SpaceTrafficControlEventScheduler # iff we make a selector for EntityTables that can respect StationEventComp restrictions, or somehow impliment them otherwise in said tables,
+  parent: BaseGameRule                  # we can remerge this with the other schedulers, but it will silently fail due to that limitation without a separate scheduler to balance atm.
+  components:
+  - type: BasicStationEventScheduler
+    minimumTimeUntilFirstEvent: 1200 # 20 mins
+    minMaxEventTiming:
+      min: 600 # 10 mins
+      max: 1800 # 30 mins
+    scheduledGameRules: !type:NestedSelector
+      tableId: SpaceTrafficControlTable
+
+- type: entity
+  id: SpaceTrafficControlFriendlyEventScheduler 
+  parent: BaseGameRule                  
+  components:
+  - type: BasicStationEventScheduler
+    minimumTimeUntilFirstEvent: 1200 # 20 mins
+    minMaxEventTiming:
+      min: 600 # 10 mins
+      max: 1800 # 30 mins
+    scheduledGameRules: !type:NestedSelector
+      tableId: UnknownShuttlesFriendlyTable
 
 # variation passes
 - type: entity
index 1ce365cd816b90d8452e877bbc5bae6e1a52d9bd..3f707fd57e1fb72e0cdb790182ca87ec3452d7ee 100644 (file)
@@ -1,3 +1,28 @@
+# Shuttle Game Rule Tables -- If you dont add your rules to these they wont be used by the games schedulers.
+
+- type: entityTable
+  id: UnknownShuttlesFriendlyTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - id: UnknownShuttleCargoLost
+    - id: UnknownShuttleTravelingCuisine
+    - id: UnknownShuttleDisasterEvacPod
+    - id: UnknownShuttleHonki
+
+- type: entityTable
+  id: UnknownShuttlesFreelanceTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - id: UnknownShuttleSyndieEvacPod
+
+- type: entityTable
+  id: UnknownShuttlesHostileTable
+  table: !type:AllSelector # we need to pass a list of rules, since rules have further restrictions to consider via StationEventComp
+    children:
+    - id: LoneOpsSpawn
+
+# Shuttle Game Rules
+
 - type: entity
   abstract: true
   parent: BaseGameRule
index 3a3f07760b9ab420a7dab8d0bf9b973015d80b2e..efce3c4e24ccb206b28c9b17a273afae36e98bfc 100644 (file)
@@ -6,12 +6,31 @@
   showInVote: false # secret
   description: survival-description
   rules:
+    - MeteorSwarmScheduler
     - RampingStationEventScheduler
-    - GameRuleMeteorScheduler
+    - SpaceTrafficControlEventScheduler
+    - SpaceTrafficControlFriendlyEventScheduler
+    - BasicRoundstartVariation
+
+- type: gamePreset
+  id: KesslerSyndrome
+  alias:
+    - kessler
+    - junk
+    - meteorhell
+  name: kessler-syndrome-title
+  showInVote: false # secret
+  description: kessler-syndrome-description
+  rules:
+    - KesslerSyndromeScheduler
+    - RampingStationEventScheduler
+    - SpaceTrafficControlEventScheduler
     - BasicRoundstartVariation
 
 - type: gamePreset
   id: AllAtOnce
+  alias:
+  - all
   name: all-at-once-title
   description: all-at-once-description
   showInVote: false
     - Traitor
     - Revolutionary
     - Zombie
+    - KesslerSyndromeScheduler
+    - RampingStationEventScheduler
+    - SpaceTrafficControlEventScheduler
+    - BasicRoundstartVariation
+
+- type: gamePreset
+  id: AllerAtOnce
+  alias:
+  - allall
+  - aller
+  - badidea
+  - punishment
+  name: aller-at-once-title
+  description: all-at-once-description
+  showInVote: false #Please god dont do this
+  rules:
+    - Nukeops
+    - Traitor
+    - Revolutionary
+    - Zombie
+    - BasicStationEventScheduler
+    - KesslerSyndromeScheduler
+    - MeteorSwarmMildScheduler
+    - MeteorSwarmScheduler
     - RampingStationEventScheduler
-    - GameRuleMeteorScheduler
+    - SpaceTrafficControlEventScheduler
+    - SpaceTrafficControlFriendlyEventScheduler
+    - BasicRoundstartVariation
 
 - type: gamePreset
   id: Extended
@@ -33,7 +78,8 @@
   description: extended-description
   rules:
   - BasicStationEventScheduler
-  - GameRuleMeteorScheduler
+  - MeteorSwarmScheduler
+  - SpaceTrafficControlEventScheduler
   - BasicRoundstartVariation
 
 - type: gamePreset
@@ -45,6 +91,7 @@
   showInVote: false #4boring4vote
   description: greenshift-description
   rules:
+  - SpaceTrafficControlFriendlyEventScheduler 
   - BasicRoundstartVariation
 
 - type: gamePreset
   description: secret-description
   rules:
     - BasicStationEventScheduler
-    - GameRuleMeteorScheduler
+    - MeteorSwarmScheduler
+    - SpaceTrafficControlEventScheduler
+    - BasicRoundstartVariation
 
 - type: gamePreset
   id: SecretGreenshift #For Admin Use: Runs Greenshift but shows "Secret" in lobby.
   name: secret-title
   showInVote: false #Admin Use
   description: secret-description
+  rules:
+  - SpaceTrafficControlFriendlyEventScheduler 
+  - BasicRoundstartVariation
 
 - type: gamePreset
   id: Sandbox
   id: Traitor
   alias:
     - traitor
+    - tator
   name: traitor-title
   description: traitor-description
   showInVote: false
     - Traitor
     - SubGamemodesRule
     - BasicStationEventScheduler
-    - GameRuleMeteorScheduler
+    - MeteorSwarmScheduler
+    - SpaceTrafficControlEventScheduler
     - BasicRoundstartVariation
 
 - type: gamePreset
     - Nukeops
     - SubGamemodesRule
     - BasicStationEventScheduler
-    - GameRuleMeteorScheduler
+    - MeteorSwarmScheduler
+    - SpaceTrafficControlEventScheduler
     - BasicRoundstartVariation
 
 - type: gamePreset
     - Revolutionary
     - SubGamemodesRule
     - BasicStationEventScheduler
-    - GameRuleMeteorScheduler
+    - MeteorSwarmScheduler
+    - SpaceTrafficControlEventScheduler
     - BasicRoundstartVariation
 
 - type: gamePreset
   rules:
   - Zombie
   - BasicStationEventScheduler
-  - GameRuleMeteorScheduler
+  - MeteorSwarmScheduler
+  - SpaceTrafficControlEventScheduler
+  - BasicRoundstartVariation
+
+- type: gamePreset
+  id: Zombieteors
+  alias:
+  - zombieteors
+  - zombombies
+  - meteombies
+  name: zombieteors-title
+  description: zombieteors-description
+  showInVote: false
+  rules:
+  - Zombie
+  - BasicStationEventScheduler
+  - KesslerSyndromeScheduler
+  - SpaceTrafficControlEventScheduler
   - BasicRoundstartVariation
index 7af610af6c7d6c39b6b57ad37b373ecc59c01546..0a272e24c7c07c4d33eb0a32c408293e134b9f04 100644 (file)
@@ -3,6 +3,8 @@
   weights:
     Nukeops: 0.20
     Traitor: 0.60
-    Zombie: 0.05
-    Survival: 0.10
+    Zombie: 0.04
+    Zombieteors: 0.01
+    Survival: 0.09
+    KesslerSyndrome: 0.01
     Revolutionary: 0.05